From d3f704a425a50b5cfa997a25866929b30f1b7d0f Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Thu, 17 Nov 2011 15:10:13 -0800 Subject: Skip the "resume after portage update" routine. Instead, finish the whole job using a copy of the currently running instance. This allows us to avoid the complexities of emerge --resume, such as the differences in option handling between different portage versions, as reported in bug #390819. --- pym/_emerge/Scheduler.py | 143 +++++++++------------------------ pym/_emerge/depgraph.py | 2 - pym/_emerge/resolver/output.py | 21 ----- pym/_emerge/resolver/output_helpers.py | 1 - 4 files changed, 38 insertions(+), 129 deletions(-) (limited to 'pym/_emerge') diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py index 3b53a3723..393eeb605 100644 --- a/pym/_emerge/Scheduler.py +++ b/pym/_emerge/Scheduler.py @@ -29,7 +29,8 @@ from portage._sets.base import InternalPackageSet from portage.util import ensure_dirs, writemsg, writemsg_level from portage.package.ebuild.digestcheck import digestcheck from portage.package.ebuild.digestgen import digestgen -from portage.package.ebuild.doebuild import _check_temp_dir +from portage.package.ebuild.doebuild import (_check_temp_dir, + _prepare_self_update) from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs import _emerge @@ -75,12 +76,9 @@ class Scheduler(PollScheduler): frozenset(["--pretend", "--fetchonly", "--fetch-all-uri"]) - _opts_no_restart = frozenset(["--buildpkgonly", + _opts_no_self_reinstall = frozenset(["--buildpkgonly", "--fetchonly", "--fetch-all-uri", "--pretend"]) - _bad_resume_opts = set(["--ask", "--changelog", - "--resume", "--skipfirst"]) - class _iface_class(SlotObject): __slots__ = ("fetch", "output", "register", "schedule", @@ -289,6 +287,38 @@ class Scheduler(PollScheduler): self._running_portage = self._pkg(cpv, "installed", self._running_root, installed=True) + def _handle_self_update(self): + """ + If portage is updating itself, create temporary + copies of PORTAGE_BIN_PATH and PORTAGE_PYM_PATH in order + to avoid relying on the new versions which may be + incompatible. Register an atexit hook to clean up the + temporary directories. Pre-load elog modules here since + we won't be able to later if they get unmerged (happens + when namespace changes). + """ + + if self._opts_no_self_reinstall.intersection(self.myopts): + return + + for x in self._mergelist: + if not isinstance(x, Package): + continue + if x.operation != "merge": + continue + if x.root != self._running_root.root: + continue + if not portage.dep.match_from_list( + portage.const.PORTAGE_PACKAGE_ATOM, [x]): + continue + if self._running_portage is None or \ + self._running_portage.cpv != x.cpv or \ + '9999' in x.cpv or \ + 'git' in x.inherited or \ + 'git-2' in x.inherited: + _prepare_self_update(self.settings) + break + def _terminate_tasks(self): self._status_display.quiet = True while self._running_tasks: @@ -785,100 +815,6 @@ class Scheduler(PollScheduler): return prefetcher - def _is_restart_scheduled(self): - """ - Check if the merge list contains a replacement - for the current running instance, that will result - in restart after merge. - @rtype: bool - @returns: True if a restart is scheduled, False otherwise. - """ - if self._opts_no_restart.intersection(self.myopts): - return False - - mergelist = self._mergelist - - for i, pkg in enumerate(mergelist): - if self._is_restart_necessary(pkg) and \ - i != len(mergelist) - 1: - return True - - return False - - def _is_restart_necessary(self, pkg): - """ - @return: True if merging the given package - requires restart, False otherwise. - """ - - # Figure out if we need a restart. - if pkg.root == self._running_root.root and \ - portage.match_from_list( - portage.const.PORTAGE_PACKAGE_ATOM, [pkg]): - if self._running_portage is None: - return True - elif pkg.cpv != self._running_portage.cpv or \ - '9999' in pkg.cpv or \ - 'git' in pkg.inherited or \ - 'git-2' in pkg.inherited: - return True - return False - - def _restart_if_necessary(self, pkg): - """ - Use execv() to restart emerge. This happens - if portage upgrades itself and there are - remaining packages in the list. - """ - - if self._opts_no_restart.intersection(self.myopts): - return - - if not self._is_restart_necessary(pkg): - return - - if pkg == self._mergelist[-1]: - return - - self._main_loop_cleanup() - - logger = self._logger - pkg_count = self._pkg_count - mtimedb = self._mtimedb - bad_resume_opts = self._bad_resume_opts - - logger.log(" ::: completed emerge (%s of %s) %s to %s" % \ - (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root)) - - logger.log(" *** RESTARTING " + \ - "emerge via exec() after change of " + \ - "portage version.") - - mtimedb["resume"]["mergelist"].remove(list(pkg)) - mtimedb.commit() - portage.run_exitfuncs() - # Don't trust sys.argv[0] here because eselect-python may modify it. - emerge_binary = os.path.join(portage.const.PORTAGE_BIN_PATH, 'emerge') - mynewargv = [emerge_binary, "--resume"] - resume_opts = self.myopts.copy() - # For automatic resume, we need to prevent - # any of bad_resume_opts from leaking in - # via EMERGE_DEFAULT_OPTS. - resume_opts["--ignore-default-opts"] = True - for myopt, myarg in resume_opts.items(): - if myopt not in bad_resume_opts: - if myarg is True: - mynewargv.append(myopt) - elif isinstance(myarg, list): - # arguments like --exclude that use 'append' action - for x in myarg: - mynewargv.append("%s=%s" % (myopt, x)) - else: - mynewargv.append("%s=%s" % (myopt, myarg)) - # priority only needs to be adjusted on the first run - os.environ["PORTAGE_NICENESS"] = "0" - os.execv(mynewargv[0], mynewargv) - def _run_pkg_pretend(self): """ Since pkg_pretend output may be important, this method sends all @@ -1034,6 +970,8 @@ class Scheduler(PollScheduler): except self._unknown_internal_error: return 1 + self._handle_self_update() + for root in self.trees: root_config = self.trees[root]["root_config"] @@ -1379,8 +1317,6 @@ class Scheduler(PollScheduler): if pkg.installed: return - self._restart_if_necessary(pkg) - # Call mtimedb.commit() after each merge so that # --resume still works after being interrupted # by reboot, sigkill or similar. @@ -1585,10 +1521,7 @@ class Scheduler(PollScheduler): def _main_loop(self): - # Only allow 1 job max if a restart is scheduled - # due to portage update. - if self._is_restart_scheduled() or \ - self._opts_no_background.intersection(self.myopts): + if self._opts_no_background.intersection(self.myopts): self._set_max_jobs(1) while self._schedule(): diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index fda335fcc..65fe1fda2 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -100,8 +100,6 @@ class _frozen_depgraph_config(object): self.edebug = 1 self.spinner = spinner self._running_root = trees[trees._running_eroot]["root_config"] - self._opts_no_restart = frozenset(["--buildpkgonly", - "--fetchonly", "--fetch-all-uri", "--pretend"]) self.pkgsettings = {} self.trees = {} self._trees_orig = trees diff --git a/pym/_emerge/resolver/output.py b/pym/_emerge/resolver/output.py index eed30190d..6f1c76c43 100644 --- a/pym/_emerge/resolver/output.py +++ b/pym/_emerge/resolver/output.py @@ -865,27 +865,6 @@ class Display(object): continue self.print_msg.append((myprint, self.verboseadd, self.repoadd)) - if not self.conf.tree_display \ - and not self.conf.no_restart \ - and pkg.root == self.conf.running_root.root \ - and match_from_list(PORTAGE_PACKAGE_ATOM, [pkg]) \ - and not self.conf.quiet: - - if not self.vardb.cpv_exists(pkg.cpv) or \ - '9999' in pkg.cpv or \ - 'git' in pkg.inherited or \ - 'git-2' in pkg.inherited: - if mylist_index < len(mylist) - 1: - self.print_msg.append( - colorize( - "WARN", "*** Portage will stop merging " - "at this point and reload itself," - ) - ) - self.print_msg.append( - colorize("WARN", " then resume the merge.") - ) - show_repos = repoadd_set and repoadd_set != set(["0"]) # now finally print out the messages diff --git a/pym/_emerge/resolver/output_helpers.py b/pym/_emerge/resolver/output_helpers.py index b3cdbc4c4..dd26534f8 100644 --- a/pym/_emerge/resolver/output_helpers.py +++ b/pym/_emerge/resolver/output_helpers.py @@ -198,7 +198,6 @@ class _DisplayConfig(object): self.print_use_string = self.verbosity != 1 or "--verbose" in frozen_config.myopts self.changelog = "--changelog" in frozen_config.myopts self.edebug = frozen_config.edebug - self.no_restart = frozen_config._opts_no_restart.intersection(frozen_config.myopts) self.unordered_display = "--unordered-display" in frozen_config.myopts mywidth = 130 -- cgit v1.2.3-1-g7c22