module : added rm subcommand, encapsulated logic for constraints in argarse.Action subclass
This commit is contained in:
		@@ -28,6 +28,7 @@
 | 
			
		||||
import shutil
 | 
			
		||||
import sys
 | 
			
		||||
import collections
 | 
			
		||||
import argparse
 | 
			
		||||
 | 
			
		||||
import llnl.util.tty as tty
 | 
			
		||||
import spack.cmd
 | 
			
		||||
@@ -40,33 +41,76 @@
 | 
			
		||||
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:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user