From f0f7b23c8a6804da6d215e15712c99a6d72e782a Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 1 Jul 2016 14:27:55 +0200 Subject: module : added rm subcommand, encapsulated logic for constraints in argarse.Action subclass --- lib/spack/spack/cmd/module.py | 127 +++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 39 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/module.py b/lib/spack/spack/cmd/module.py index 5628ab17a5..6f9ede21ac 100644 --- a/lib/spack/spack/cmd/module.py +++ b/lib/spack/spack/cmd/module.py @@ -28,6 +28,7 @@ import os import shutil import sys import collections +import argparse import llnl.util.tty as tty import spack.cmd @@ -40,33 +41,76 @@ from spack.cmd.uninstall import ask_for_confirmation description = "Manipulate module files" +# Qualifiers to be used when querying the db for specs +constraint_qualifiers = { + 'refresh': { + 'installed': True, + 'known': True + }, + 'find': { + }, + 'load-list':{ + }, + 'rm': { + } +} + + +class ConstraintAction(argparse.Action): + qualifiers = {} + + def __call__(self, parser, namespace, values, option_string=None): + # Query specs from command line + d = self.qualifiers.get(namespace.subparser_name, {}) + specs = [s for s in spack.installed_db.query(**d)] + values = ' '.join(values) + if values: + specs = [x for x in specs if x.satisfies(values, strict=True)] + namespace.specs = specs + +# TODO : this needs better wrapping to be extracted +ConstraintAction.qualifiers.update(constraint_qualifiers) + + def _add_common_arguments(subparser): type_help = 'Type of module files' - subparser.add_argument('--module-type', help=type_help, default='tcl', choices=module_types) + subparser.add_argument('-m', '--module-type', help=type_help, default='tcl', choices=module_types) constraint_help = 'Optional constraint to select a subset of installed packages' - subparser.add_argument('constraint', nargs='*', help=constraint_help) + subparser.add_argument('constraint', nargs='*', help=constraint_help, action=ConstraintAction) def setup_parser(subparser): - sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='module_command') + sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='subparser_name') # spack module refresh refresh_parser = sp.add_parser('refresh', help='Regenerate all module files.') refresh_parser.add_argument('--delete-tree', help='Delete the module file tree before refresh', action='store_true') _add_common_arguments(refresh_parser) + refresh_parser.add_argument( + '-y', '--yes-to-all', action='store_true', dest='yes_to_all', + help='Assume "yes" is the answer to every confirmation asked to the user.' + ) # spack module find find_parser = sp.add_parser('find', help='Find module files for packages.') _add_common_arguments(find_parser) - # spack module env + # spack module rm + rm_parser = sp.add_parser('rm', help='Find module files for packages.') + _add_common_arguments(rm_parser) + rm_parser.add_argument( + '-y', '--yes-to-all', action='store_true', dest='yes_to_all', + help='Assume "yes" is the answer to every confirmation asked to the user.' + ) + + # spack module load-list loadlist_parser = sp.add_parser( 'load-list', help='Prompt the list of modules associated with packages that satisfy a contraint' ) loadlist_parser.add_argument( - '-r', '--dependencies', action='store_true', + '-d', '--dependencies', action='store_true', dest='recurse_dependencies', - help='Recursively traverse dependencies for modules to load.') + help='Recursively traverse spec dependencies') loadlist_parser.add_argument( '-s', '--shell', action='store_true', dest='shell', @@ -87,7 +131,6 @@ class NoMatch(Exception): def load_list(mtype, specs, args): - # Get a comprehensive list of specs if args.recurse_dependencies: specs_from_user_constraint = specs[:] @@ -121,7 +164,7 @@ def load_list(mtype, specs, args): for spec, mod in modules: d['comment'] = '' if not args.shell else '# {0}\n'.format(spec.format()) d['name'] = mod - print( prompt_template.format(**d)) + print(prompt_template.format(**d)) def find(mtype, specs, args): @@ -143,7 +186,29 @@ def find(mtype, specs, args): tty.die("No %s module is installed for %s" % (mtype, spec)) print(mod.use_name) -def refresh(name, specs, args): + +def rm(mtype, specs, args): + module_cls = module_types[mtype] + modules = [module_cls(spec) for spec in specs if os.path.exists(module_cls(spec).file_name)] + + if not modules: + tty.msg('No module file matches your query') + return + + # Ask for confirmation + if not args.yes_to_all: + tty.msg('You are about to remove the following module files:\n') + for s in modules: + print(s.file_name) + print('') + ask_for_confirmation('Do you want to proceed ? ') + + # Remove the module files + for s in modules: + s.remove() + + +def refresh(mtype, specs, args): """ Regenerate all module files for installed packages known to spack (some packages may no longer exist). @@ -153,13 +218,14 @@ def refresh(name, specs, args): tty.msg('No package matches your query') return - tty.msg('You are about to regenerate the {name} module files for the following specs:\n'.format(name=name)) - for s in specs: - print(s.format(color=True)) - print('') - ask_for_confirmation('Do you want to proceed ? ') + if not args.yes_to_all: + tty.msg('You are about to regenerate the {name} module files for the following specs:\n'.format(name=mtype)) + for s in specs: + print(s.format(color=True)) + print('') + ask_for_confirmation('Do you want to proceed ? ') - cls = module_types[name] + cls = module_types[mtype] # Detect name clashes writers = [cls(spec) for spec in specs] @@ -179,48 +245,31 @@ def refresh(name, specs, args): raise SystemExit(1) # Proceed regenerating module files - tty.msg('Regenerating {name} module files'.format(name=name)) + tty.msg('Regenerating {name} module files'.format(name=mtype)) if os.path.isdir(cls.path) and args.delete_tree: shutil.rmtree(cls.path, ignore_errors=False) mkdirp(cls.path) for x in writers: x.write(overwrite=True) -# Qualifiers to be used when querying the db for specs -constraint_qualifiers = { - 'refresh': { - 'installed': True, - 'known': True - }, - 'find': { - }, - 'load-list':{ - } -} - -# Dictionary of callbacks based on the value of module_command +# Dictionary of callbacks based on the value of subparser_name callbacks = { 'refresh': refresh, 'find': find, - 'load-list': load_list + 'load-list': load_list, + 'rm': rm } def module(parser, args): module_type = args.module_type - # Query specs from command line - qualifiers = constraint_qualifiers[args.module_command] - specs = [s for s in spack.installed_db.query(**qualifiers)] - constraint = ' '.join(args.constraint) - if constraint: - specs = [x for x in specs if x.satisfies(constraint, strict=True)] - # Call the appropriate function + constraint = args.constraint try: - callbacks[args.module_command](module_type, specs, args) + callbacks[args.subparser_name](module_type, args.specs, args) except MultipleMatches: message = 'the constraint \'{query}\' matches multiple packages, and this is not allowed in this context' tty.error(message.format(query=constraint)) - for s in specs: + for s in args.specs: sys.stderr.write(s.format(color=True) + '\n') raise SystemExit(1) except NoMatch: -- cgit v1.2.3-60-g2f50