On Tue,  9 May 2017 20:52:34 -0700
Zac Medico <zmed...@gentoo.org> wrote:

> 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=<y|n> 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
> ---
>  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 f1a9d4f..94edc90 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 e1119af..53910dd 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 76e963a..8084967 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
> 75fb368..e2a7de0 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
> 3654aa6..1739416 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 13f7e67..846ba0e 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,


Looks good, thank you :)

-- 
Brian Dolbec <dolsen>


Reply via email to