From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id D7BC0139695 for ; Sun, 14 May 2017 18:12:30 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 39278E0E1E; Sun, 14 May 2017 18:12:30 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 07242E0E1E for ; Sun, 14 May 2017 18:12:30 +0000 (UTC) Received: from oystercatcher.gentoo.org (unknown [IPv6:2a01:4f8:202:4333:225:90ff:fed9:fc84]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id E608E341301 for ; Sun, 14 May 2017 18:12:28 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id B26AC7439 for ; Sun, 14 May 2017 18:12:27 +0000 (UTC) From: "Zac Medico" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Zac Medico" Message-ID: <1494785505.40505ceeadc769f4f01c66e52a19ce0bf2f59761.zmedico@gentoo> Subject: [gentoo-commits] proj/portage:master commit in: pym/_emerge/, man/, pym/portage/tests/resolver/ X-VCS-Repository: proj/portage X-VCS-Files: man/emerge.1 pym/_emerge/depgraph.py pym/_emerge/main.py pym/portage/tests/resolver/test_autounmask.py pym/portage/tests/resolver/test_autounmask_use_breakage.py pym/portage/tests/resolver/test_slot_conflict_unsatisfied_deep_deps.py X-VCS-Directories: man/ pym/_emerge/ pym/portage/tests/resolver/ X-VCS-Committer: zmedico X-VCS-Committer-Name: Zac Medico X-VCS-Revision: 40505ceeadc769f4f01c66e52a19ce0bf2f59761 X-VCS-Branch: master Date: Sun, 14 May 2017 18:12:27 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: aafd8a71-2a19-43fd-8118-7f2df0889da8 X-Archives-Hash: dbc8f82ff46ed41386bc623327d01c42 commit: 40505ceeadc769f4f01c66e52a19ce0bf2f59761 Author: Zac Medico gentoo org> AuthorDate: Wed May 10 03:44:56 2017 +0000 Commit: Zac Medico gentoo org> CommitDate: Sun May 14 18:11:45 2017 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=40505cee emerge: terminate backtracking early for autounmask changes (bug 615680) Since autounmask changes are a strong indicator that backtracking will ultimately fail to produce a solution, terminate early for autounmask changes, and add a --autounmask-backtrack= option to modify this behavior. The --autounmask-continue option implies --autounmask-backtrack=y behavior, for backward compatibility. When backtracking terminates early, the following warning message is displayed after the autounmask change(s): * In order to avoid wasting time, backtracking has terminated early * due to the above autounmask change(s). The --autounmask-backtrack=y * option can be used to force further backtracking, but there is no * guarantee that it will produce a solution. With this change, five of the existing cases fail unless --autounmask-backtrack=y is added to the options. For each of these cases, comments below the test case document how it behaves with and without --autounmask-backtrack=y enabled. X-Gentoo-bug: 615680 X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=615680 Acked-by: Brian Dolbec gentoo.org> man/emerge.1 | 10 ++- pym/_emerge/depgraph.py | 80 ++++++++++++++++++---- pym/_emerge/main.py | 6 ++ pym/portage/tests/resolver/test_autounmask.py | 57 ++++++++++++++- .../tests/resolver/test_autounmask_use_breakage.py | 40 +++++++++++ .../test_slot_conflict_unsatisfied_deep_deps.py | 61 +++++++++++++++++ 6 files changed, 237 insertions(+), 17 deletions(-) diff --git a/man/emerge.1 b/man/emerge.1 index f1a9d4f3f..94edc9095 100644 --- a/man/emerge.1 +++ b/man/emerge.1 @@ -363,12 +363,20 @@ the specified configuration file(s), or enable the \fBEMERGE_DEFAULT_OPTS\fR variable may be used to disable this option by default in \fBmake.conf\fR(5). .TP +.BR "\-\-autounmask\-backtrack < y | n >" +Allow backtracking after autounmask has detected that +configuration changes are necessary. This option is not +recommended, since it can cause a large amount of time to +be wasted by backtracking calculations, even though there +is no guarantee that it will produce a solution. This +option is disabled by default. +.TP .BR "\-\-autounmask\-continue [ y | n ]" Automatically apply autounmask changes to configuration files, and continue to execute the specified command. If the dependency calculation is not entirely successful, then emerge will simply abort without modifying any configuration -files. +files. This option implies \fB\-\-autounmask\-backtrack=y\fR. \fBWARNING:\fR This option is intended to be used only with great caution, since it is possible for it to make nonsensical configuration diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index e1119af3c..53910dd25 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -444,6 +444,7 @@ class _dynamic_depgraph_config(object): self._autounmask = depgraph._frozen_config.myopts.get('--autounmask') != 'n' self._displayed_autounmask = False self._success_without_autounmask = False + self._autounmask_backtrack_disabled = False self._required_use_unsatisfied = False self._traverse_ignored_deps = False self._complete_mode = False @@ -1129,7 +1130,8 @@ class depgraph(object): self._show_merge_list() - self._dynamic_config._slot_conflict_handler = slot_conflict_handler(self) + if self._dynamic_config._slot_conflict_handler is None: + self._dynamic_config._slot_conflict_handler = slot_conflict_handler(self) handler = self._dynamic_config._slot_conflict_handler conflict = handler.get_conflict() @@ -4243,17 +4245,7 @@ class depgraph(object): # set below is reserved for cases where there are *zero* other # problems. For reference, see backtrack_depgraph, where it skips the # get_best_run() call when success_without_autounmask is True. - - digraph_nodes = self._dynamic_config.digraph.nodes - - if any(x in digraph_nodes for x in - self._dynamic_config._needed_unstable_keywords) or \ - any(x in digraph_nodes for x in - self._dynamic_config._needed_p_mask_changes) or \ - any(x in digraph_nodes for x in - self._dynamic_config._needed_use_config_changes) or \ - any(x in digraph_nodes for x in - self._dynamic_config._needed_license_changes) : + if self._have_autounmask_changes(): #We failed if the user needs to change the configuration self._dynamic_config._success_without_autounmask = True if (self._frozen_config.myopts.get("--autounmask-continue") is True and @@ -8564,6 +8556,17 @@ class depgraph(object): "experimental or unstable packages.\n", noiselevel=-1) + if self._dynamic_config._autounmask_backtrack_disabled: + msg = [ + "In order to avoid wasting time, backtracking has terminated early", + "due to the above autounmask change(s). The --autounmask-backtrack=y", + "option can be used to force further backtracking, but there is no", + "guarantee that it will produce a solution.", + ] + writemsg("\n", noiselevel=-1) + for line in msg: + writemsg(" %s %s\n" % (colorize("WARN", "*"), line), + noiselevel=-1) def display_problems(self): """ @@ -9072,8 +9075,57 @@ class depgraph(object): not self._dynamic_config._skip_restart def need_config_change(self): - return self._dynamic_config._success_without_autounmask or \ - self._dynamic_config._required_use_unsatisfied + """ + Returns true if backtracking should terminate due to a needed + configuration change. + """ + if (self._dynamic_config._success_without_autounmask or + self._dynamic_config._required_use_unsatisfied): + return True + + if (self._dynamic_config._slot_conflict_handler is None and + not self._accept_blocker_conflicts() and + any(self._dynamic_config._package_tracker.slot_conflicts())): + self._dynamic_config._slot_conflict_handler = slot_conflict_handler(self) + if self._dynamic_config._slot_conflict_handler.changes: + # Terminate backtracking early if the slot conflict + # handler finds some changes to suggest. The case involving + # sci-libs/L and sci-libs/M in SlotCollisionTestCase will + # otherwise fail with --autounmask-backtrack=n, since + # backtracking will eventually lead to some autounmask + # changes. Changes suggested by the slot conflict handler + # are more likely to be useful. + return True + + if (self._dynamic_config._allow_backtracking and + self._frozen_config.myopts.get("--autounmask-backtrack") != 'y' and + self._have_autounmask_changes()): + + if (self._frozen_config.myopts.get("--autounmask-continue") is True and + self._frozen_config.myopts.get("--autounmask-backtrack") != 'n'): + # --autounmask-continue implies --autounmask-backtrack=y behavior, + # for backward compatibility. + return False + + # This disables backtracking when there are autounmask + # config changes. The display_problems method will notify + # the user that --autounmask-backtrack=y can be used to + # force backtracking in this case. + self._dynamic_config._autounmask_backtrack_disabled = True + return True + + return False + + def _have_autounmask_changes(self): + digraph_nodes = self._dynamic_config.digraph.nodes + return (any(x in digraph_nodes for x in + self._dynamic_config._needed_unstable_keywords) or + any(x in digraph_nodes for x in + self._dynamic_config._needed_p_mask_changes) or + any(x in digraph_nodes for x in + self._dynamic_config._needed_use_config_changes) or + any(x in digraph_nodes for x in + self._dynamic_config._needed_license_changes)) def need_config_reload(self): return self._dynamic_config._need_config_reload diff --git a/pym/_emerge/main.py b/pym/_emerge/main.py index 76e963ac9..808496722 100644 --- a/pym/_emerge/main.py +++ b/pym/_emerge/main.py @@ -326,6 +326,12 @@ def parse_opts(tmpcmdline, silent=False): "choices" : true_y_or_n }, + "--autounmask-backtrack": { + "help": ("continue backtracking when there are autounmask " + "configuration changes"), + "choices":("y", "n") + }, + "--autounmask-continue": { "help" : "write autounmask changes and continue", "choices" : true_y_or_n diff --git a/pym/portage/tests/resolver/test_autounmask.py b/pym/portage/tests/resolver/test_autounmask.py index 75fb36843..e2a7de028 100644 --- a/pym/portage/tests/resolver/test_autounmask.py +++ b/pym/portage/tests/resolver/test_autounmask.py @@ -81,20 +81,73 @@ class AutounmaskTestCase(TestCase): #Make sure we restart if needed. ResolverPlaygroundTestCase( ["dev-libs/A:1", "dev-libs/B"], - options={"--autounmask": True}, + options={"--autounmask": True, "--autounmask-backtrack": "y"}, all_permutations=True, success=False, mergelist=["dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1"], use_changes={ "dev-libs/B-1": {"foo": True} }), + + # With --autounmask-backtrack=y: + #[ebuild N ] dev-libs/C-1 + #[ebuild N ] dev-libs/B-1 USE="foo -bar" + #[ebuild N ] dev-libs/A-1 + # + #The following USE changes are necessary to proceed: + # (see "package.use" in the portage(5) man page for more details) + ## required by dev-libs/A-1::test_repo + ## required by dev-libs/A:1 (argument) + #>=dev-libs/B-1 foo + + # Without --autounmask-backtrack=y: + #[ebuild N ] dev-libs/B-1 USE="foo -bar" + #[ebuild N ] dev-libs/A-1 + # + #The following USE changes are necessary to proceed: + # (see "package.use" in the portage(5) man page for more details) + ## required by dev-libs/A-1::test_repo + ## required by dev-libs/A:1 (argument) + #>=dev-libs/B-1 foo + ResolverPlaygroundTestCase( ["dev-libs/A:1", "dev-libs/A:2", "dev-libs/B"], - options={"--autounmask": True}, + options={"--autounmask": True, "--autounmask-backtrack": "y"}, all_permutations=True, success=False, mergelist=["dev-libs/D-1", "dev-libs/C-1", "dev-libs/B-1", "dev-libs/A-1", "dev-libs/A-2"], ignore_mergelist_order=True, use_changes={ "dev-libs/B-1": {"foo": True, "bar": True} }), + # With --autounmask-backtrack=y: + #[ebuild N ] dev-libs/C-1 + #[ebuild N ] dev-libs/D-1 + #[ebuild N ] dev-libs/B-1 USE="bar foo" + #[ebuild N ] dev-libs/A-2 + #[ebuild N ] dev-libs/A-1 + # + #The following USE changes are necessary to proceed: + # (see "package.use" in the portage(5) man page for more details) + ## required by dev-libs/A-2::test_repo + ## required by dev-libs/A:2 (argument) + #>=dev-libs/B-1 bar foo + + # Without --autounmask-backtrack=y: + #[ebuild N ] dev-libs/B-1 USE="bar foo" + #[ebuild N ] dev-libs/A-1 + #[ebuild N ] dev-libs/A-2 + # + #The following USE changes are necessary to proceed: + # (see "package.use" in the portage(5) man page for more details) + ## required by dev-libs/A-1::test_repo + ## required by dev-libs/A:1 (argument) + #>=dev-libs/B-1 foo bar + + # NOTE: The --autounmask-backtrack=n behavior is acceptable, but + # it would be nicer if it added the dev-libs/C-1 and dev-libs/D-1 + # deps to the depgraph without backtracking. It could add two + # instances of dev-libs/B-1 to the graph with different USE flags, + # and then use _solve_non_slot_operator_slot_conflicts to eliminate + # the redundant instance. + #Test keywording. #The simple case. diff --git a/pym/portage/tests/resolver/test_autounmask_use_breakage.py b/pym/portage/tests/resolver/test_autounmask_use_breakage.py index 3654aa6a3..173941629 100644 --- a/pym/portage/tests/resolver/test_autounmask_use_breakage.py +++ b/pym/portage/tests/resolver/test_autounmask_use_breakage.py @@ -46,12 +46,52 @@ class AutounmaskUseBreakageTestCase(TestCase): # due to autounmask USE breakage. ResolverPlaygroundTestCase( ["app-misc/C", "app-misc/B", "app-misc/A"], + options={"--autounmask-backtrack": "y"}, all_permutations = True, success = False, ambiguous_slot_collision_solutions = True, slot_collision_solutions = [None, []] ), + # With --autounmask-backtrack=y: + #emerge: there are no ebuilds built with USE flags to satisfy "app-misc/D[foo]". + #!!! One of the following packages is required to complete your request: + #- app-misc/D-0::test_repo (Change USE: +foo) + #(dependency required by "app-misc/B-0::test_repo" [ebuild]) + #(dependency required by "app-misc/B" [argument]) + + # Without --autounmask-backtrack=y: + #[ebuild N ] app-misc/D-0 USE="foo" + #[ebuild N ] app-misc/D-1 USE="-bar" + #[ebuild N ] app-misc/C-0 + #[ebuild N ] app-misc/B-0 + #[ebuild N ] app-misc/A-0 + # + #!!! Multiple package instances within a single package slot have been pulled + #!!! into the dependency graph, resulting in a slot conflict: + # + #app-misc/D:0 + # + # (app-misc/D-0:0/0::test_repo, ebuild scheduled for merge) pulled in by + # app-misc/D[-foo] required by (app-misc/A-0:0/0::test_repo, ebuild scheduled for merge) + # ^^^^ + # app-misc/D[foo] required by (app-misc/B-0:0/0::test_repo, ebuild scheduled for merge) + # ^^^ + # + # (app-misc/D-1:0/0::test_repo, ebuild scheduled for merge) pulled in by + # >=app-misc/D-1 required by (app-misc/C-0:0/0::test_repo, ebuild scheduled for merge) + # ^^ ^ + # + #The following USE changes are necessary to proceed: + # (see "package.use" in the portage(5) man page for more details) + ## required by app-misc/B-0::test_repo + ## required by app-misc/B (argument) + #=app-misc/D-0 foo + + # NOTE: The --autounmask-backtrack=n output is preferable here, + # because it highlights the unsolvable dependency conflict. + # It would be better if it eliminated the autounmask suggestion, + # since that suggestion won't solve the conflict. ) playground = ResolverPlayground(ebuilds=ebuilds, debug=False) diff --git a/pym/portage/tests/resolver/test_slot_conflict_unsatisfied_deep_deps.py b/pym/portage/tests/resolver/test_slot_conflict_unsatisfied_deep_deps.py index 13f7e67e3..846ba0e59 100644 --- a/pym/portage/tests/resolver/test_slot_conflict_unsatisfied_deep_deps.py +++ b/pym/portage/tests/resolver/test_slot_conflict_unsatisfied_deep_deps.py @@ -79,6 +79,7 @@ class SlotConflictUnsatisfiedDeepDepsTestCase(TestCase): ["@world"], options={ "--autounmask": "y", + "--autounmask-backtrack": "y", "--complete-graph": True, "--selective": True, "--deep": 1 @@ -89,11 +90,63 @@ class SlotConflictUnsatisfiedDeepDepsTestCase(TestCase): unsatisfied_deps=["dev-libs/initially-unsatisfied"], success=False), + # With --autounmask-backtrack=y: + #[ebuild N ~] dev-libs/A-2 + #[ebuild N ] dev-libs/C-1 + #[ebuild N ] dev-libs/D-1 + #[ebuild N ] dev-libs/B-1 + # + #The following keyword changes are necessary to proceed: + # (see "package.accept_keywords" in the portage(5) man page for more details) + ## required by dev-libs/C-1::test_repo + ## required by @selected + ## required by @world (argument) + #=dev-libs/A-2 ~x86 + # + #!!! Problems have been detected with your world file + #!!! Please run emaint --check world + # + # + #!!! Ebuilds for the following packages are either all + #!!! masked or don't exist: + #dev-libs/broken + # + #emerge: there are no ebuilds to satisfy "dev-libs/initially-unsatisfied". + #(dependency required by "dev-libs/broken-1::test_repo" [installed]) + #(dependency required by "@selected" [set]) + #(dependency required by "@world" [argument]) + + # Without --autounmask-backtrack=y: + #!!! Multiple package instances within a single package slot have been pulled + #!!! into the dependency graph, resulting in a slot conflict: + # + #dev-libs/A:0 + # + # (dev-libs/A-1:0/0::test_repo, ebuild scheduled for merge) pulled in by + # (no parents that aren't satisfied by other packages in this slot) + # + # (dev-libs/A-2:0/0::test_repo, ebuild scheduled for merge) pulled in by + # >=dev-libs/A-2 required by (dev-libs/C-1:0/0::test_repo, ebuild scheduled for merge) + # ^^ ^ + # + #The following keyword changes are necessary to proceed: + # (see "package.accept_keywords" in the portage(5) man page for more details) + ## required by dev-libs/C-1::test_repo + ## required by @selected + ## required by @world (argument) + #=dev-libs/A-2 ~x86 + # + #emerge: there are no ebuilds to satisfy "dev-libs/initially-unsatisfied". + #(dependency required by "dev-libs/broken-1::test_repo" [installed]) + #(dependency required by "@selected" [set]) + #(dependency required by "@world" [argument]) + # Test --deep = True ResolverPlaygroundTestCase( ["@world"], options={ "--autounmask": "y", + "--autounmask-backtrack": "y", "--complete-graph": True, "--selective": True, "--deep": True @@ -103,6 +156,14 @@ class SlotConflictUnsatisfiedDeepDepsTestCase(TestCase): unstable_keywords=["dev-libs/A-2"], unsatisfied_deps=["dev-libs/initially-unsatisfied"], success=False), + + # The effects of --autounmask-backtrack are the same as the previous test case. + # Both test cases can randomly succeed with --autounmask-backtrack=n, when + # "backtracking due to unsatisfied dep" randomly occurs before the autounmask + # unstable keyword change. It would be possible to eliminate backtracking here + # by recognizing that there are no alternatives to satisfy the dev-libs/broken + # atom in the world file. Then the test cases will consistently succeed with + # --autounmask-backtrack=n. ) playground = ResolverPlayground(ebuilds=ebuilds, installed=installed,