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
This commit is contained in:
parent
0fd58fb585
commit
b71d430af6
4 changed files with 101 additions and 59 deletions
|
@ -32,73 +32,115 @@
|
|||
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.')
|
||||
_add_common_arguments(find_parser)
|
||||
|
||||
|
||||
def module_find(mtype, spec_array):
|
||||
"""Look at all installed packages and see if the spec provided
|
||||
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 <mtype> 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)))
|
||||
|
||||
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)
|
||||
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)]
|
||||
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
|
||||
|
||||
for name, cls in module_types.items():
|
||||
tty.msg("Regenerating %s module files." % name)
|
||||
if os.path.isdir(cls.path):
|
||||
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))
|
||||
|
|
|
@ -454,7 +454,7 @@ def remove(self):
|
|||
|
||||
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 @@ def prerequisite(self, spec):
|
|||
|
||||
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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue