From e3951c2a2157d05c6e191270a0e3f846dc077234 Mon Sep 17 00:00:00 2001 From: healther Date: Fri, 2 Feb 2018 23:45:21 +0100 Subject: [PATCH] Fix ignore-conflicts for extensions in views (#7167) Fixes #7159 When activating extensions in external views, the --ignore-conflicts option was being ignored. In this particular issue the conflict was for the duplicate __init__ file for multiple python packages in the same namespace, but in general any conflict for extensions would cause an error whether or not --ignore-conflicts was set. This also renames the 'force' option of do_activate to 'with_dependencies' and updates views to call do_activate with this set to False (since it traverses the dependency dag anyway). This isn't strictly required, it just avoids redundant calls. --- lib/spack/spack/cmd/activate.py | 3 ++- lib/spack/spack/filesystem_view.py | 5 ++++- lib/spack/spack/package.py | 29 ++++++++++++++++++++++------- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/spack/spack/cmd/activate.py b/lib/spack/spack/cmd/activate.py index a5909df9fb..12a743161d 100644 --- a/lib/spack/spack/cmd/activate.py +++ b/lib/spack/spack/cmd/activate.py @@ -61,4 +61,5 @@ def activate(parser, args): if spec.package.is_activated(extensions_layout=layout): tty.die("Package %s is already activated." % specs[0].short_spec) - spec.package.do_activate(extensions_layout=layout) + spec.package.do_activate(extensions_layout=layout, + with_dependencies=not args.force) diff --git a/lib/spack/spack/filesystem_view.py b/lib/spack/spack/filesystem_view.py index 9be55e381b..1c6e5f0523 100644 --- a/lib/spack/spack/filesystem_view.py +++ b/lib/spack/spack/filesystem_view.py @@ -94,7 +94,7 @@ def add_specs(self, *specs, **kwargs): def add_extension(self, spec): """ - Add (link) an extension in this view. + Add (link) an extension in this view. Does not add dependencies. """ raise NotImplementedError @@ -228,6 +228,9 @@ def add_extension(self, spec): try: if not spec.package.is_activated(self.extensions_layout): spec.package.do_activate( + ignore_conflicts=self.ignore_conflicts, + with_dependencies=False, # already taken care of + # in add_specs() verbose=self.verbose, extensions_layout=self.extensions_layout) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index f0f092015f..f7cb3b0253 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -1825,12 +1825,17 @@ def _sanity_check_extension(self): raise ActivationError("%s does not extend %s!" % (self.name, self.extendee.name)) - def do_activate(self, force=False, verbose=True, extensions_layout=None): + def do_activate(self, with_dependencies=True, ignore_conflicts=False, + verbose=True, extensions_layout=None): """Called on an extension to invoke the extendee's activate method. Commands should call this routine, and should not call activate() directly. """ + if verbose: + tty.msg("Activating extension %s for %s" % + (self.spec.cshort_spec, self.extendee_spec.cshort_spec)) + self._sanity_check_extension() if extensions_layout is None: @@ -1840,16 +1845,19 @@ def do_activate(self, force=False, verbose=True, extensions_layout=None): self.extendee_spec, self.spec) # Activate any package dependencies that are also extensions. - if not force: + if with_dependencies: for spec in self.dependency_activations(): if not spec.package.is_activated( extensions_layout=extensions_layout): spec.package.do_activate( - force=force, verbose=verbose, + with_dependencies=with_dependencies, + ignore_conflicts=ignore_conflicts, + verbose=verbose, extensions_layout=extensions_layout) self.extendee_spec.package.activate( - self, extensions_layout=extensions_layout, **self.extendee_args) + self, extensions_layout=extensions_layout, + ignore_conflicts=ignore_conflicts, **self.extendee_args) extensions_layout.add_extension(self.extendee_spec, self.spec) @@ -1863,7 +1871,7 @@ def dependency_activations(self): return (spec for spec in self.spec.traverse(root=False, deptype='run') if spec.package.extends(self.extendee_spec)) - def activate(self, extension, **kwargs): + def activate(self, extension, ignore_conflicts=False, **kwargs): """Make extension package usable by linking all its files to a target provided by the directory layout (depending if the user wants to activate globally or in a specified file system view). @@ -1883,11 +1891,18 @@ def ignore(filename): kwargs.get('ignore', lambda f: False)(filename)) tree = LinkTree(extension.prefix) + conflict = tree.find_conflict(target, ignore=ignore) - if conflict: + if not conflict: + pass + elif ignore_conflicts: + tty.warn("While activating %s, found conflict %s" % + (self.spec.cshort_spec, conflict)) + else: raise ExtensionConflictError(conflict) - tree.merge(target, ignore=ignore, link=extensions_layout.link) + tree.merge(target, ignore=ignore, link=extensions_layout.link, + ignore_conflicts=ignore_conflicts) def do_deactivate(self, **kwargs): """Called on the extension to invoke extendee's deactivate() method.