module : added rm subcommand, encapsulated logic for constraints in argarse.Action subclass

This commit is contained in:
alalazo 2016-07-01 14:27:55 +02:00
parent fe4ef286f2
commit f0f7b23c8a

View File

@ -28,6 +28,7 @@
import shutil import shutil
import sys import sys
import collections import collections
import argparse
import llnl.util.tty as tty import llnl.util.tty as tty
import spack.cmd import spack.cmd
@ -40,33 +41,76 @@
description = "Manipulate module files" 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): def _add_common_arguments(subparser):
type_help = 'Type of module files' 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' 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): 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 # spack module refresh
refresh_parser = sp.add_parser('refresh', help='Regenerate all module files.') 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') refresh_parser.add_argument('--delete-tree', help='Delete the module file tree before refresh', action='store_true')
_add_common_arguments(refresh_parser) _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 # spack module find
find_parser = sp.add_parser('find', help='Find module files for packages.') find_parser = sp.add_parser('find', help='Find module files for packages.')
_add_common_arguments(find_parser) _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( loadlist_parser = sp.add_parser(
'load-list', 'load-list',
help='Prompt the list of modules associated with packages that satisfy a contraint' help='Prompt the list of modules associated with packages that satisfy a contraint'
) )
loadlist_parser.add_argument( loadlist_parser.add_argument(
'-r', '--dependencies', action='store_true', '-d', '--dependencies', action='store_true',
dest='recurse_dependencies', dest='recurse_dependencies',
help='Recursively traverse dependencies for modules to load.') help='Recursively traverse spec dependencies')
loadlist_parser.add_argument( loadlist_parser.add_argument(
'-s', '--shell', action='store_true', dest='shell', '-s', '--shell', action='store_true', dest='shell',
@ -87,7 +131,6 @@ class NoMatch(Exception):
def load_list(mtype, specs, args): def load_list(mtype, specs, args):
# Get a comprehensive list of specs # Get a comprehensive list of specs
if args.recurse_dependencies: if args.recurse_dependencies:
specs_from_user_constraint = specs[:] specs_from_user_constraint = specs[:]
@ -121,7 +164,7 @@ def load_list(mtype, specs, args):
for spec, mod in modules: for spec, mod in modules:
d['comment'] = '' if not args.shell else '# {0}\n'.format(spec.format()) d['comment'] = '' if not args.shell else '# {0}\n'.format(spec.format())
d['name'] = mod d['name'] = mod
print( prompt_template.format(**d)) print(prompt_template.format(**d))
def find(mtype, specs, args): 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)) tty.die("No %s module is installed for %s" % (mtype, spec))
print(mod.use_name) 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 Regenerate all module files for installed packages known to
spack (some packages may no longer exist). spack (some packages may no longer exist).
@ -153,13 +218,14 @@ def refresh(name, specs, args):
tty.msg('No package matches your query') tty.msg('No package matches your query')
return return
tty.msg('You are about to regenerate the {name} module files for the following specs:\n'.format(name=name)) 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: for s in specs:
print(s.format(color=True)) print(s.format(color=True))
print('') print('')
ask_for_confirmation('Do you want to proceed ? ') ask_for_confirmation('Do you want to proceed ? ')
cls = module_types[name] cls = module_types[mtype]
# Detect name clashes # Detect name clashes
writers = [cls(spec) for spec in specs] writers = [cls(spec) for spec in specs]
@ -179,48 +245,31 @@ def refresh(name, specs, args):
raise SystemExit(1) raise SystemExit(1)
# Proceed regenerating module files # 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: if os.path.isdir(cls.path) and args.delete_tree:
shutil.rmtree(cls.path, ignore_errors=False) shutil.rmtree(cls.path, ignore_errors=False)
mkdirp(cls.path) mkdirp(cls.path)
for x in writers: for x in writers:
x.write(overwrite=True) x.write(overwrite=True)
# Qualifiers to be used when querying the db for specs # Dictionary of callbacks based on the value of subparser_name
constraint_qualifiers = {
'refresh': {
'installed': True,
'known': True
},
'find': {
},
'load-list':{
}
}
# Dictionary of callbacks based on the value of module_command
callbacks = { callbacks = {
'refresh': refresh, 'refresh': refresh,
'find': find, 'find': find,
'load-list': load_list 'load-list': load_list,
'rm': rm
} }
def module(parser, args): def module(parser, args):
module_type = args.module_type module_type = args.module_type
# Query specs from command line constraint = args.constraint
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
try: try:
callbacks[args.module_command](module_type, specs, args) callbacks[args.subparser_name](module_type, args.specs, args)
except MultipleMatches: except MultipleMatches:
message = 'the constraint \'{query}\' matches multiple packages, and this is not allowed in this context' message = 'the constraint \'{query}\' matches multiple packages, and this is not allowed in this context'
tty.error(message.format(query=constraint)) tty.error(message.format(query=constraint))
for s in specs: for s in args.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: