From 581f70ff6f3bc13d53c98da60fa0fe50fe784f2c Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Mon, 21 Aug 2017 18:20:07 +0200 Subject: [PATCH] Added custom messages for conflicts directive. fixes #4965 (#5083) Users can now add an optional custom message to the conflicts directive. Layout on screen has been changed to improve readability and the long spec is shown in tree format. Two conflicts in `espresso` have been modified to showcase the feature. --- lib/spack/spack/directives.py | 6 ++-- lib/spack/spack/spec.py | 28 +++++++++++++++---- .../builtin/packages/espresso/package.py | 13 +++++++-- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py index 2e8b32e5af..2a99e171a0 100644 --- a/lib/spack/spack/directives.py +++ b/lib/spack/spack/directives.py @@ -263,7 +263,7 @@ def _depends_on(pkg, spec, when=None, type=None): @directive('conflicts') -def conflicts(conflict_spec, when=None): +def conflicts(conflict_spec, when=None, msg=None): """Allows a package to define a conflict. Currently, a "conflict" is a concretized configuration that is known @@ -280,14 +280,16 @@ def conflicts(conflict_spec, when=None): Args: conflict_spec (Spec): constraint defining the known conflict when (Spec): optional constraint that triggers the conflict + msg (str): optional user defined message """ def _execute(pkg): # If when is not specified the conflict always holds condition = pkg.name if when is None else when when_spec = parse_anonymous_spec(condition, pkg.name) + # Save in a list the conflicts and the associated custom messages when_spec_list = pkg.conflicts.setdefault(conflict_spec, []) - when_spec_list.append(when_spec) + when_spec_list.append((when_spec, msg)) return _execute diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 43d57f2b98..a58e1ceb2f 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1798,9 +1798,9 @@ def concretize(self): for x in self.traverse(): for conflict_spec, when_list in x.package.conflicts.items(): if x.satisfies(conflict_spec): - for when_spec in when_list: + for when_spec, msg in when_list: if x.satisfies(when_spec): - matches.append((x, conflict_spec, when_spec)) + matches.append((x, conflict_spec, when_spec, msg)) if matches: raise ConflictsInSpecError(self, matches) @@ -3447,8 +3447,24 @@ def __init__(self, spec, matches): message = 'Conflicts in concretized spec "{0}"\n'.format( spec.short_spec ) - long_message = 'List of matching conflicts:\n\n' - match_fmt = '{0}. "{1}" conflicts with "{2}" in spec "{3}"\n' - for idx, (s, c, w) in enumerate(matches): - long_message += match_fmt.format(idx + 1, c, w, s) + + visited = set() + + long_message = '' + + match_fmt_default = '{0}. "{1}" conflicts with "{2}"\n' + match_fmt_custom = '{0}. "{1}" conflicts with "{2}" [{3}]\n' + + for idx, (s, c, w, msg) in enumerate(matches): + + if s not in visited: + visited.add(s) + long_message += 'List of matching conflicts for spec:\n\n' + long_message += s.tree(indent=4) + '\n' + + if msg is None: + long_message += match_fmt_default.format(idx + 1, c, w) + else: + long_message += match_fmt_custom.format(idx + 1, c, w, msg) + super(ConflictsInSpecError, self).__init__(message, long_message) diff --git a/var/spack/repos/builtin/packages/espresso/package.py b/var/spack/repos/builtin/packages/espresso/package.py index b77e14ec76..26cbf8fd88 100644 --- a/var/spack/repos/builtin/packages/espresso/package.py +++ b/var/spack/repos/builtin/packages/espresso/package.py @@ -75,8 +75,17 @@ class Espresso(Package): patch('dspev_drv_elpa.patch', when='@6.1 ^elpa@2016.05.003') # We can't ask for scalapack or elpa if we don't want MPI - conflicts('+scalapack', when='~mpi') - conflicts('+elpa', when='~mpi') + conflicts( + '+scalapack', + when='~mpi', + msg='scalapack is a parallel library and needs MPI support' + ) + + conflicts( + '+elpa', + when='~mpi', + msg='elpa is a parallel library and needs MPI support' + ) # Elpa is formally supported by @:5.4.0, but QE configure searches # for it in the wrong folders (or tries to download it within