class uninstall_op(ebd, format.uninstall): """phase operations and steps for uninstall execution""" def __init__(self, domain, pkg, observer): format.uninstall.__init__(self, domain, pkg, observer) ebd.__init__(self, pkg, observer=observer, initial_env=domain.settings, env_data_source=pkg.environment, clean=False, tmp_offset="unmerge") prerm = pretty_docs( observer.decorate_build_method("prerm")(post_curry( ebd._generic_phase, "prerm", False, False, False)), "run the prerm phase") postrm = pretty_docs( observer.decorate_build_method("postrm")(post_curry( ebd._generic_phase, "postrm", False, False, False, failure_allowed=True)), "run the postrm phase") def add_triggers(self, domain_op, engine): self.old_pkg.add_format_triggers(domain_op, self, engine) def finish(self): self.cleanup() return format.uninstall.finish(self)
class install_op(ebd, format.install): """phase operations and steps for install execution""" def __init__(self, domain, pkg, observer): format.install.__init__(self, domain, pkg, observer) ebd.__init__( self, pkg, observer=observer, initial_env=domain.settings, env_data_source=pkg.environment, clean=False) preinst = pretty_docs( observer.decorate_build_method("preinst")( post_curry(ebd._generic_phase, "preinst", False, False)), "run the postinst phase") postinst = pretty_docs( observer.decorate_build_method("postinst")( post_curry(ebd._generic_phase, "postinst", False, False)), "run the postinst phase") def add_triggers(self, domain_op, engine): self.new_pkg.add_format_triggers(domain_op, self, engine)
def unpack(self): """execute the unpack phase""" if self.setup_is_for_src: self.setup_distfiles() if self.userpriv: try: os.chown(self.env["WORKDIR"], portage_uid, -1) except OSError as oe: raise_from( format.GenericBuildError( "failed forcing %i uid for WORKDIR: %s" % (portage_uid, str(oe)))) return self._generic_phase("unpack", True, True, False) compile = pretty_docs( observer.decorate_build_method("compile")(post_curry( ebd._generic_phase, "compile", True, True, False)), "run the compile phase (maps to src_compile)") @observer.decorate_build_method("install") def install(self): """run the install phase (maps to src_install)""" if self.fakeroot: return self._generic_phase("install", True, False, True) else: return self._generic_phase("install", False, True, False) @observer.decorate_build_method("test") def test(self): """run the test phase (if enabled), maps to src_test""" if not self.run_test: return True
class buildable(ebd, setup_mixin, format.build): """Generic build operation.""" # XXX this is unclean- should be handing in strictly what is build # env, rather then dumping domain settings as env. def __init__(self, domain, pkg, verified_files, eclass_cache, observer=None, force_test=False, **kwargs): """ :param pkg: :obj:`pkgcore.ebuild.ebuild_src.package` instance we'll be building :param eclass_cache: the :class:`pkgcore.ebuild.eclass_cache` we'll be using :param verified_files: mapping of fetchables mapped to their disk location """ self._built_class = ebuild_built.fresh_built_package format.build.__init__(self, domain, pkg, verified_files, observer) domain_settings = self.domain.settings ebd.__init__(self, pkg, initial_env=domain_settings, **kwargs) self.env["FILESDIR"] = pjoin(os.path.dirname(pkg.ebuild.path), "files") self.eclass_cache = eclass_cache self.run_test = force_test or self.feat_or_bool("test", domain_settings) self.allow_failed_test = self.feat_or_bool("test-fail-continue", domain_settings) if "test" in self.restrict: self.run_test = False elif not force_test and "test" not in pkg.use: if self.run_test: logger.warning(f"disabling test for {pkg} due to test use flag being disabled") self.run_test = False # XXX minor hack path = self.env["PATH"].split(os.pathsep) for s, default in (("DISTCC", ".distcc"), ("CCACHE", "ccache")): b = (self.feat_or_bool(s, domain_settings) and s not in self.restrict) setattr(self, s.lower(), b) if b: # looks weird I realize, but # pjoin("/foor/bar", "/barr/foo") == "/barr/foo" # and pjoin("/foo/bar", ".asdf") == "/foo/bar/.asdf" self.env.setdefault(s + "_DIR", pjoin(self.domain.tmpdir, default)) # gentoo bug 355283 libdir = self.env.get("ABI") if libdir is not None: libdir = self.env.get(f"LIBDIR_{libdir}") if libdir is not None: libdir = self.env.get(libdir) if libdir is None: libdir = "lib" path.insert(0, f"/usr/{libdir}/{s.lower()}/bin") else: for y in ("_PATH", "_DIR"): if s + y in self.env: del self.env[s+y] self.env["PATH"] = os.pathsep.join(path) # ordering must match appearance order in SRC_URI per PMS self.env["A"] = ' '.join(iter_stable_unique(pkg.distfiles)) if self.eapi.options.has_AA: pkg = self.pkg while hasattr(pkg, '_raw_pkg'): pkg = getattr(pkg, '_raw_pkg') self.env["AA"] = ' '.join(set(iflatten_instance(pkg.distfiles))) if self.eapi.options.has_KV: self.env["KV"] = domain.KV if self.eapi.options.has_merge_type: self.env["MERGE_TYPE"] = "source" if self.eapi.options.has_portdir: self.env["PORTDIR"] = pkg.repo.location self.env["ECLASSDIR"] = eclass_cache.eclassdir if self.setup_is_for_src: self._init_distfiles_env() def _init_distfiles_env(self): # TODO: PORTAGE_ACTUAL_DISTDIR usage by vcs eclasses needs to be killed off distdir_write = self.domain.fetcher.get_storage_path() if distdir_write is None: raise format.GenericBuildError( "no usable distdir was found " f"for PORTAGE_ACTUAL_DISTDIR from fetcher {self.domain.fetcher}") self.env["PORTAGE_ACTUAL_DISTDIR"] = distdir_write self.env["DISTDIR"] = normpath( pjoin(self.builddir, "distdir")) for x in ("PORTAGE_ACTUAL_DISTDIR", "DISTDIR"): self.env[x] = os.path.realpath(self.env[x]).rstrip(os.sep) + os.sep def _setup_distfiles(self): if not self.verified_files and self.allow_fetching: ops = self.domain.pkg_operations(self.pkg, observer=self.observer) if not ops.fetch(): raise format.GenericBuildError("failed fetching required distfiles") self.verified_files = ops._fetch_op.verified_files if self.verified_files: try: if os.path.exists(self.env["DISTDIR"]): if (os.path.isdir(self.env["DISTDIR"]) and not os.path.islink(self.env["DISTDIR"])): shutil.rmtree(self.env["DISTDIR"]) else: os.unlink(self.env["DISTDIR"]) except EnvironmentError as e: raise format.FailedDirectory( self.env["DISTDIR"], f"failed removing existing file/dir/link: {e}") from e if not ensure_dirs(self.env["DISTDIR"], mode=0o770, gid=portage_gid): raise format.FailedDirectory( self.env["DISTDIR"], "failed creating distdir symlink directory") try: for src, dest in [ (k, pjoin(self.env["DISTDIR"], v.filename)) for (k, v) in self.verified_files.items()]: os.symlink(src, dest) except EnvironmentError as e: raise format.GenericBuildError( f"Failed symlinking in distfiles for src {src} -> {dest}: {e}") from e @observer.decorate_build_method("setup") def setup(self): """Execute the setup phase, mapping out to pkg_setup in the ebuild. Necessarily dirs are created as required, and build env is initialized at this point. """ if self.distcc: for p in ("", "/lock", "/state"): if not ensure_dirs(pjoin(self.env["DISTCC_DIR"], p), mode=0o2775, gid=portage_gid): raise format.FailedDirectory( pjoin(self.env["DISTCC_DIR"], p), "failed creating needed distcc directory") if self.ccache: # yuck. st = None try: st = os.stat(self.env["CCACHE_DIR"]) except OSError as e: st = None if not ensure_dirs(self.env["CCACHE_DIR"], mode=0o2775, gid=portage_gid): raise format.FailedDirectory( self.env["CCACHE_DIR"], "failed creation of ccache dir") from e # XXX this is more then mildly stupid. st = os.stat(self.env["CCACHE_DIR"]) try: if st.st_gid != portage_gid or (st.st_mode & 0o2775) != 0o2775: try: cwd = os.getcwd() except OSError: cwd = "/" with chdir(cwd): # crap. os.chmod(self.env["CCACHE_DIR"], 0o2775) os.chown(self.env["CCACHE_DIR"], -1, portage_gid) if 0 != spawn( ["chgrp", "-R", str(portage_gid), self.env["CCACHE_DIR"]]): raise format.FailedDirectory( self.env["CCACHE_DIR"], "failed changing ownership for CCACHE_DIR") if 0 != spawn_bash( "find '%s' -type d -print0 | %s --null chmod 02775" % (self.env["CCACHE_DIR"], xargs)): raise format.FailedDirectory( self.env["CCACHE_DIR"], "failed correcting perms for CCACHE_DIR") if 0 != spawn_bash( "find '%s' -type f -print0 | %s --null chmod 0775" % (self.env["CCACHE_DIR"], xargs)): raise format.FailedDirectory( self.env["CCACHE_DIR"], "failed correcting perms for CCACHE_DIR") except OSError as e: raise format.FailedDirectory( self.env["CCACHE_DIR"], "failed ensuring perms/group owner for CCACHE_DIR") from e return setup_mixin.setup(self) def configure(self): """Execute the configure phase. Does nothing if the pkg's EAPI is less than 2 (that spec lacks a separated configure phase). """ if "configure" in self.eapi.phases: return self._generic_phase("configure", True, True) return True def prepare(self): """Execute a source preparation phase. does nothing if the pkg's EAPI is less than 2 """ ret = True if "prepare" in self.eapi.phases: ret = self._generic_phase("prepare", True, True) if (self.eapi.options.user_patches and not os.path.exists(pjoin(self.env['T'], '.user_patches_applied'))): self.observer.error( 'eapply_user (or default) must be called in src_prepare()') raise format.GenericBuildError('missing eapply_user call') return ret def nofetch(self): """Execute the nofetch phase. We need the same prerequisites as setup, so reuse that. """ ensure_dirs(self.env["T"], mode=0o770, gid=portage_gid, minimal=True) return setup_mixin.setup(self, "nofetch") def unpack(self): """Execute the unpack phase.""" if self.setup_is_for_src: self._setup_distfiles() if self.userpriv: try: os.chown(self.env["WORKDIR"], portage_uid, -1) except OSError as e: raise format.GenericBuildError( "failed forcing %i uid for WORKDIR: %s" % (portage_uid, e)) from e return self._generic_phase("unpack", True, True) compile = pretty_docs( observer.decorate_build_method("compile")( post_curry(ebd._generic_phase, "compile", True, True)), "Run the compile phase (maps to src_compile).") @observer.decorate_build_method("install") def install(self): """Run the install phase (maps to src_install).""" # TODO: replace print() usage with observer print(f">>> Install {self.env['PF']} into {self.ED!r} category {self.env['CATEGORY']}") ret = self._generic_phase("install", False, True) print(f">>> Completed installing {self.env['PF']} into {self.ED!r}") return ret @observer.decorate_build_method("test") def test(self): """Run the test phase (if enabled), maps to src_test.""" if not self.run_test: return True return self._generic_phase( "test", True, True, failure_allowed=self.allow_failed_test) def finalize(self): """Finalize the operation. This yields a built package, but the packages metadata/contents are bound to the workdir. In other words, install the package somewhere prior to executing clean if you intend on installing it. :return: :obj:`pkgcore.ebuild.ebuild_built.package` instance """ factory = ebuild_built.fake_package_factory(self._built_class) return factory.new_package( self.pkg, self.env["D"], pjoin(self.env["T"], "environment"))
def unpack(self): """execute the unpack phase""" if self.setup_is_for_src: self.setup_distfiles() if self.userpriv: try: os.chown(self.env["WORKDIR"], portage_uid, -1) except OSError as oe: raise_from(format.GenericBuildError( "failed forcing %i uid for WORKDIR: %s" % (portage_uid, str(oe)))) return self._generic_phase("unpack", True, True, False) compile = pretty_docs( observer.decorate_build_method("compile")( post_curry( ebd._generic_phase, "compile", True, True, False)), "run the compile phase (maps to src_compile)") @observer.decorate_build_method("install") def install(self): """run the install phase (maps to src_install)""" if self.fakeroot: return self._generic_phase("install", True, False, True) else: return self._generic_phase("install", False, True, False) @observer.decorate_build_method("test") def test(self): """run the test phase (if enabled), maps to src_test""" if not self.run_test: