From b71d430af6025cb46ac574e91e516bc5c4caf048 Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 28 Jun 2016 17:59:34 +0200 Subject: module : can regenerate single module files, homogenized cli options spack module : - refresh accepts a constraint - find and refresh share common cli options - ask for confirmation before refreshing - deleting the module file tree is now optional --- lib/spack/spack/cmd/module.py | 140 +++++++++++++++++++++++++++--------------- lib/spack/spack/modules.py | 8 +-- share/spack/csh/spack.csh | 8 +-- share/spack/setup-env.sh | 8 +-- 4 files changed, 103 insertions(+), 61 deletions(-) diff --git a/lib/spack/spack/cmd/module.py b/lib/spack/spack/cmd/module.py index 5292d42225..c71e615d1c 100644 --- a/lib/spack/spack/cmd/module.py +++ b/lib/spack/spack/cmd/module.py @@ -32,73 +32,115 @@ from llnl.util.filesystem import mkdirp from spack.modules import module_types from spack.util.string import * -description = "Manipulate modules and dotkits." +from spack.cmd.uninstall import ask_for_confirmation + +description = "Manipulate module files" + + +def _add_common_arguments(subparser): + type_help = 'Type of module files' + subparser.add_argument('--module-type', help=type_help, required=True, choices=module_types) + constraint_help = 'Optional constraint to select a subset of installed packages' + subparser.add_argument('constraint', nargs='*', help=constraint_help) def setup_parser(subparser): sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='module_command') + # 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) - sp.add_parser('refresh', help='Regenerate all module files.') - + # spack module find find_parser = sp.add_parser('find', help='Find module files for packages.') - find_parser.add_argument('module_type', - help="Type of module to find file for. [" + - '|'.join(module_types) + "]") - find_parser.add_argument('spec', - nargs='+', - help='spec to find a module file for.') - - -def module_find(mtype, spec_array): - """Look at all installed packages and see if the spec provided - matches any. If it does, check whether there is a module file - of type there, and print out the name that the user - should type to use that package's module. - """ - if mtype not in module_types: - tty.die("Invalid module type: '%s'. Options are %s" % - (mtype, comma_or(module_types))) + _add_common_arguments(find_parser) - specs = spack.cmd.parse_specs(spec_array) - if len(specs) > 1: - tty.die("You can only pass one spec.") - spec = specs[0] - specs = spack.installed_db.query(spec) +class MultipleMatches(Exception): + pass + + +class NoMatch(Exception): + pass + + +def module_find(mtype, specs, args): + """ + Look at all installed packages and see if the spec provided + matches any. If it does, check whether there is a module file + of type there, and print out the name that the user + should type to use that package's module. + """ if len(specs) == 0: - tty.die("No installed packages match spec %s" % spec) + raise NoMatch() if len(specs) > 1: - tty.error("Multiple matches for spec %s. Choose one:" % spec) - for s in specs: - sys.stderr.write(s.tree(color=True)) - sys.exit(1) + raise MultipleMatches() - mt = module_types[mtype] - mod = mt(specs[0]) + mod = module_types[mtype](specs.pop()) if not os.path.isfile(mod.file_name): tty.die("No %s module is installed for %s" % (mtype, spec)) print(mod.use_name) -def module_refresh(): - """Regenerate all module files for installed packages known to - spack (some packages may no longer exist).""" - specs = [s for s in spack.installed_db.query(installed=True, known=True)] - - for name, cls in module_types.items(): - tty.msg("Regenerating %s module files." % name) - if os.path.isdir(cls.path): - shutil.rmtree(cls.path, ignore_errors=False) - mkdirp(cls.path) - for spec in specs: - cls(spec).write() +def module_refresh(name, specs, args): + """ + Regenerate all module files for installed packages known to + spack (some packages may no longer exist). + """ + # Prompt a message to the user about what is going to change + if not specs: + tty.msg('No package matches your query') + return + + tty.msg('You are about to regenerate the {name} module files for the following specs:'.format(name=name)) + for s in specs: + print(s.format(color=True)) + ask_for_confirmation('Do you want to proceed ? ') + + cls = module_types[name] + tty.msg('Regenerating {name} module files'.format(name=name)) + if os.path.isdir(cls.path) and args.delete_tree: + shutil.rmtree(cls.path, ignore_errors=False) + mkdirp(cls.path) + for spec in specs: + cls(spec).write() + +# Qualifiers to be used when querying the db for specs +constraint_qualifiers = { + 'refresh': { + 'installed': True, + 'known': True + }, + 'find': { + } +} + +# Dictionary of callbacks based on the value of module_command +callbacks = { + 'refresh': module_refresh, + 'find': module_find +} def module(parser, args): - if args.module_command == 'refresh': - module_refresh() - - elif args.module_command == 'find': - module_find(args.module_type, args.spec) + 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 + try: + callbacks[args.module_command](module_type, 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: + sys.stderr.write(s.format(color=True) + '\n') + raise SystemExit(1) + except NoMatch: + message = 'the constraint \'{query}\' match no package, and this is not allowed in this context' + tty.die(message.format(query=constraint)) diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index ce46047fa3..068179c0ce 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -454,7 +454,7 @@ class EnvModule(object): class Dotkit(EnvModule): name = 'dotkit' - + path = join_path(spack.share_path, 'dotkit') environment_modifications_formats = { PrependPath: 'dk_alter {name} {value}\n', SetEnv: 'dk_setenv {name} {value}\n' @@ -466,7 +466,7 @@ class Dotkit(EnvModule): @property def file_name(self): - return join_path(spack.share_path, "dotkit", self.spec.architecture, + return join_path(self.path, self.spec.architecture, '%s.dk' % self.use_name) @property @@ -494,7 +494,7 @@ class Dotkit(EnvModule): class TclModule(EnvModule): name = 'tcl' - + path = join_path(spack.share_path, "modules") environment_modifications_formats = { PrependPath: 'prepend-path --delim "{delim}" {name} \"{value}\"\n', AppendPath: 'append-path --delim "{delim}" {name} \"{value}\"\n', @@ -514,7 +514,7 @@ class TclModule(EnvModule): @property def file_name(self): - return join_path(spack.share_path, "modules", self.spec.architecture, self.use_name) + return join_path(self.path, self.spec.architecture, self.use_name) @property def header(self): diff --git a/share/spack/csh/spack.csh b/share/spack/csh/spack.csh index d64ce8935b..5acd190449 100644 --- a/share/spack/csh/spack.csh +++ b/share/spack/csh/spack.csh @@ -74,25 +74,25 @@ case unload: # tool's commands to add/remove the result from the environment. switch ($_sp_subcommand) case "use": - set _sp_full_spec = ( "`\spack $_sp_flags module find dotkit $_sp_spec`" ) + set _sp_full_spec = ( "`\spack $_sp_flags module find --module-type dotkit $_sp_spec`" ) if ( $? == 0 ) then use $_sp_module_args $_sp_full_spec endif breaksw case "unuse": - set _sp_full_spec = ( "`\spack $_sp_flags module find dotkit $_sp_spec`" ) + set _sp_full_spec = ( "`\spack $_sp_flags module find --module-type dotkit $_sp_spec`" ) if ( $? == 0 ) then unuse $_sp_module_args $_sp_full_spec endif breaksw case "load": - set _sp_full_spec = ( "`\spack $_sp_flags module find tcl $_sp_spec`" ) + set _sp_full_spec = ( "`\spack $_sp_flags module find --module-type tcl $_sp_spec`" ) if ( $? == 0 ) then module load $_sp_module_args $_sp_full_spec endif breaksw case "unload": - set _sp_full_spec = ( "`\spack $_sp_flags module find tcl $_sp_spec`" ) + set _sp_full_spec = ( "`\spack $_sp_flags module find --module-type tcl $_sp_spec`" ) if ( $? == 0 ) then module unload $_sp_module_args $_sp_full_spec endif diff --git a/share/spack/setup-env.sh b/share/spack/setup-env.sh index 8aa259cf15..3975672e7b 100755 --- a/share/spack/setup-env.sh +++ b/share/spack/setup-env.sh @@ -105,19 +105,19 @@ function spack { # If spack module command comes back with an error, do nothing. case $_sp_subcommand in "use") - if _sp_full_spec=$(command spack $_sp_flags module find dotkit $_sp_spec); then + if _sp_full_spec=$(command spack $_sp_flags module find --module-type dotkit $_sp_spec); then use $_sp_module_args $_sp_full_spec fi ;; "unuse") - if _sp_full_spec=$(command spack $_sp_flags module find dotkit $_sp_spec); then + if _sp_full_spec=$(command spack $_sp_flags module find --module-type dotkit $_sp_spec); then unuse $_sp_module_args $_sp_full_spec fi ;; "load") - if _sp_full_spec=$(command spack $_sp_flags module find tcl $_sp_spec); then + if _sp_full_spec=$(command spack $_sp_flags module find --module-type tcl $_sp_spec); then module load $_sp_module_args $_sp_full_spec fi ;; "unload") - if _sp_full_spec=$(command spack $_sp_flags module find tcl $_sp_spec); then + if _sp_full_spec=$(command spack $_sp_flags module find --module-type tcl $_sp_spec); then module unload $_sp_module_args $_sp_full_spec fi ;; esac -- cgit v1.2.3-70-g09d2