spack find: accepts anonymous specs as arguments fixes #2170 (#2188)

This commit is contained in:
Massimiliano Culpo 2016-11-03 08:45:15 +01:00 committed by Todd Gamblin
parent b706da1109
commit 5b5894afba
5 changed files with 33 additions and 58 deletions

View File

@ -46,19 +46,25 @@ class ConstraintAction(argparse.Action):
"""Constructs a list of specs based on a constraint given on the command line """Constructs a list of specs based on a constraint given on the command line
An instance of this class is supposed to be used as an argument action An instance of this class is supposed to be used as an argument action
in a parser. It will read a constraint and will attach a list of matching in a parser. It will read a constraint and will attach a function to the
specs to the namespace arguments that accepts optional keyword arguments.
To obtain the specs from a command the function must be called.
""" """
qualifiers = {}
def __call__(self, parser, namespace, values, option_string=None): def __call__(self, parser, namespace, values, option_string=None):
# Query specs from command line # Query specs from command line
d = self.qualifiers.get(namespace.subparser_name, {}) self.values = values
specs = [s for s in spack.store.db.query(**d)] namespace.contraint = values
values = ' '.join(values) namespace.specs = self._specs
def _specs(self, **kwargs):
specs = [s for s in spack.store.db.query(**kwargs)]
values = ' '.join(self.values)
if values: if values:
specs = [x for x in specs if x.satisfies(values, strict=True)] specs = [x for x in specs if x.satisfies(values, strict=True)]
namespace.specs = specs return specs
_arguments['constraint'] = Args( _arguments['constraint'] = Args(
'constraint', nargs='*', action=ConstraintAction, 'constraint', nargs='*', action=ConstraintAction,

View File

@ -22,16 +22,11 @@
# License along with this program; if not, write to the Free Software # License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
import argparse
import sys import sys
import llnl.util.tty as tty import llnl.util.tty as tty
import spack import spack.cmd.common.arguments as arguments
import spack.spec
import spack.store
from llnl.util.lang import *
from llnl.util.tty.colify import *
from llnl.util.tty.color import *
from spack.cmd import display_specs from spack.cmd import display_specs
description = "Find installed spack packages" description = "Find installed spack packages"
@ -43,6 +38,7 @@ def setup_parser(subparser):
action='store_const', action='store_const',
dest='mode', dest='mode',
const='short', const='short',
default='short',
help='Show only specs (default)') help='Show only specs (default)')
format_group.add_argument('-p', '--paths', format_group.add_argument('-p', '--paths',
action='store_const', action='store_const',
@ -68,12 +64,12 @@ def setup_parser(subparser):
action='store_true', action='store_true',
dest='show_flags', dest='show_flags',
help='Show spec compiler flags.') help='Show spec compiler flags.')
implicit_explicit = subparser.add_mutually_exclusive_group()
subparser.add_argument( implicit_explicit.add_argument(
'-e', '--explicit', '-e', '--explicit',
action='store_true', action='store_true',
help='Show only specs that were installed explicitly') help='Show only specs that were installed explicitly')
subparser.add_argument( implicit_explicit.add_argument(
'-E', '--implicit', '-E', '--implicit',
action='store_true', action='store_true',
help='Show only specs that were installed as dependencies') help='Show only specs that were installed as dependencies')
@ -100,17 +96,10 @@ def setup_parser(subparser):
action='store_true', action='store_true',
help='Show fully qualified package names.') help='Show fully qualified package names.')
subparser.add_argument('query_specs', arguments.add_common_arguments(subparser, ['constraint'])
nargs=argparse.REMAINDER,
help='optional specs to filter results')
def query_arguments(args): def query_arguments(args):
# Check arguments
if args.explicit and args.implicit:
tty.error('You can\'t pass -E and -e options simultaneously.')
raise SystemExit(1)
# Set up query arguments. # Set up query arguments.
installed, known = True, any installed, known = True, any
if args.only_missing: if args.only_missing:
@ -129,35 +118,17 @@ def query_arguments(args):
def find(parser, args): def find(parser, args):
# Filter out specs that don't exist.
query_specs = spack.cmd.parse_specs(args.query_specs)
query_specs, nonexisting = partition_list(
query_specs, lambda s: spack.repo.exists(s.name) or not s.name)
if nonexisting:
msg = "No such package%s: " % ('s' if len(nonexisting) > 1 else '')
msg += ", ".join(s.name for s in nonexisting)
tty.msg(msg)
if not query_specs:
return
q_args = query_arguments(args) q_args = query_arguments(args)
query_specs = args.specs(**q_args)
# Get all the specs the user asked for # Exit early if no package matches the constraint
if not query_specs: if not query_specs:
specs = set(spack.store.db.query(**q_args)) msg = "No package matches the query: {0}".format(args.contraint)
else: tty.msg(msg)
results = [set(spack.store.db.query(qs, **q_args)) return
for qs in query_specs] # Display the result
specs = set.union(*results)
if not args.mode:
args.mode = 'short'
if sys.stdout.isatty(): if sys.stdout.isatty():
tty.msg("%d installed packages." % len(specs)) tty.msg("%d installed packages." % len(query_specs))
display_specs(specs, display_specs(query_specs,
mode=args.mode, mode=args.mode,
long=args.long, long=args.long,
very_long=args.very_long, very_long=args.very_long,

View File

@ -244,17 +244,17 @@ def module(parser, args):
'known': True 'known': True
}, },
} }
arguments.ConstraintAction.qualifiers.update(constraint_qualifiers) query_args = constraint_qualifiers.get(args.subparser_name, {})
specs = args.specs(**query_args)
module_type = args.module_type module_type = args.module_type
constraint = args.constraint constraint = args.constraint
try: try:
callbacks[args.subparser_name](module_type, args.specs, args) callbacks[args.subparser_name](module_type, specs, args)
except MultipleMatches: except MultipleMatches:
message = ('the constraint \'{query}\' matches multiple packages, ' message = ('the constraint \'{query}\' matches multiple packages, '
'and this is not allowed in this context') 'and this is not allowed in this context')
tty.error(message.format(query=constraint)) tty.error(message.format(query=constraint))
for s in args.specs: for s in specs:
sys.stderr.write(s.format(color=True) + '\n') sys.stderr.write(s.format(color=True) + '\n')
raise SystemExit(1) raise SystemExit(1)
except NoMatch: except NoMatch:

View File

@ -52,5 +52,3 @@ def test_query_arguments(self):
args.implicit = True args.implicit = True
q_args = query_arguments(args) q_args = query_arguments(args)
self.assertEqual(q_args['explicit'], False) self.assertEqual(q_args['explicit'], False)
args.explicit = True
self.assertRaises(SystemExit, query_arguments, args)

View File

@ -34,7 +34,7 @@ class TestModule(spack.test.mock_database.MockDatabase):
def _get_module_files(self, args): def _get_module_files(self, args):
return [modules.module_types[args.module_type](spec).file_name return [modules.module_types[args.module_type](spec).file_name
for spec in args.specs] for spec in args.specs()]
def test_module_common_operations(self): def test_module_common_operations(self):
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()