env: add spack env activate/deactivate and shell support
- `spack env activate foo`: sets SPACK_ENV to the current active env name - `spack env deactivate`: unsets SPACK_ENV, deactivates the environment - added support to setup_env.sh and setup_env.csh - other env commands work properly with SPACK_ENV, as with an environment arguments. - command-line --env arguments take precedence over the active environment, if given.
This commit is contained in:
parent
15c5c36eaf
commit
d14f7b82bb
@ -8,21 +8,30 @@
|
||||
from llnl.util import tty
|
||||
|
||||
|
||||
shell_init_instructions = [
|
||||
"To initialize spack's shell commands:",
|
||||
"",
|
||||
" # for bash and zsh",
|
||||
" . %s/setup-env.sh" % spack.paths.share_path,
|
||||
"",
|
||||
" # for csh and tcsh",
|
||||
" setenv SPACK_ROOT %s" % spack.paths.prefix,
|
||||
" source %s/setup-env.csh" % spack.paths.share_path, ""
|
||||
]
|
||||
|
||||
|
||||
def print_module_placeholder_help():
|
||||
"""
|
||||
For use by commands to tell user how to activate shell support.
|
||||
"""
|
||||
tty.msg("This command requires spack's shell integration.", "",
|
||||
"To initialize spack's shell commands, you must run one of",
|
||||
"the commands below. Choose the right command for your shell.",
|
||||
"", "For bash and zsh:",
|
||||
" . %s/setup-env.sh" % spack.paths.share_path, "",
|
||||
"For csh and tcsh:",
|
||||
" setenv SPACK_ROOT %s" % spack.paths.prefix,
|
||||
" source %s/setup-env.csh" % spack.paths.share_path, "",
|
||||
"This exposes a 'spack' shell function, which you can use like",
|
||||
" $ spack load package-foo", "",
|
||||
"Running the Spack executable directly (for example, invoking",
|
||||
"./bin/spack) will bypass the shell function and print this",
|
||||
"placeholder message, even if you have sourced one of the above",
|
||||
"shell integration scripts.")
|
||||
msg = [
|
||||
"This command requires spack's shell integration.", ""
|
||||
] + shell_init_instructions + [
|
||||
"This exposes a 'spack' shell function, which you can use like",
|
||||
" $ spack load package-foo", "",
|
||||
"Running the Spack executable directly (for example, invoking",
|
||||
"./bin/spack) will bypass the shell function and print this",
|
||||
"placeholder message, even if you have sourced one of the above",
|
||||
"shell integration scripts."
|
||||
]
|
||||
tty.msg(*msg)
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
#: List of subcommands of `spack env`
|
||||
subcommands = [
|
||||
'activate',
|
||||
'deactivate',
|
||||
'create',
|
||||
'destroy',
|
||||
['list', 'ls'],
|
||||
@ -46,6 +48,141 @@
|
||||
]
|
||||
|
||||
|
||||
def get_env(args, cmd_name):
|
||||
"""Get target environment from args, or from environment variables.
|
||||
|
||||
This is used by a number of commands for handling the environment
|
||||
argument.
|
||||
|
||||
Check whether an environment was passed via arguments, then whether
|
||||
it was passed via SPACK_ENV. If an environment is found, read it in.
|
||||
If not, print an error message referencing the calling command.
|
||||
|
||||
Arguments:
|
||||
args (Namespace): argparse namespace wtih command arguments
|
||||
cmd_name (str): name of calling command
|
||||
|
||||
"""
|
||||
env = args.env
|
||||
if not env:
|
||||
env = os.environ.get('SPACK_ENV')
|
||||
if not env:
|
||||
tty.die(
|
||||
'spack env %s requires an active environment or an argument'
|
||||
% cmd_name)
|
||||
|
||||
return ev.read(env)
|
||||
|
||||
|
||||
#
|
||||
# env activate
|
||||
#
|
||||
def env_activate_setup_parser(subparser):
|
||||
"""set the current environment"""
|
||||
shells = subparser.add_mutually_exclusive_group()
|
||||
shells.add_argument(
|
||||
'--sh', action='store_const', dest='shell', const='sh',
|
||||
help="print sh commands to activate the environment")
|
||||
shells.add_argument(
|
||||
'--csh', action='store_const', dest='shell', const='csh',
|
||||
help="print csh commands to activate the environment")
|
||||
subparser.add_argument(
|
||||
metavar='env', dest='activate_env',
|
||||
help='name of environment to activate')
|
||||
|
||||
|
||||
def env_activate(args):
|
||||
if not args.activate_env:
|
||||
tty.die('spack env activate requires an environment name')
|
||||
|
||||
env = args.activate_env
|
||||
if not args.shell:
|
||||
msg = [
|
||||
"This command works best with Spack's shell support",
|
||||
""
|
||||
] + spack.cmd.common.shell_init_instructions + [
|
||||
'Or, if you want to use `spack env activate` without initializing',
|
||||
'shell support, you can run one of these:',
|
||||
'',
|
||||
' eval `spack env activate --sh %s` # for bash/sh' % env,
|
||||
' eval `spack env activate --csh %s` # for csh/tcsh' % env,
|
||||
]
|
||||
tty.msg(*msg)
|
||||
return 1
|
||||
|
||||
if not ev.exists(env):
|
||||
tty.die("No such environment: '%s'" % env)
|
||||
|
||||
env_name_prompt = '[%s] ' % env
|
||||
|
||||
if args.shell == 'csh':
|
||||
# TODO: figure out how to make color work for csh
|
||||
sys.stdout.write('''\
|
||||
setenv SPACK_ENV %s;
|
||||
setenv SPACK_OLD_PROMPT "${prompt}";
|
||||
set prompt="%s ${prompt}";
|
||||
alias despacktivate "spack env deactivate";
|
||||
''' % (env, env_name_prompt))
|
||||
else:
|
||||
if 'color' in os.environ['TERM']:
|
||||
env_name_prompt = colorize('@G{%s} ' % env_name_prompt, color=True)
|
||||
|
||||
sys.stdout.write('''\
|
||||
export SPACK_ENV=%s;
|
||||
if [ -z "${SPACK_OLD_PS1}" ]; then export SPACK_OLD_PS1="${PS1}"; fi;
|
||||
export PS1="%s ${PS1}";
|
||||
alias despacktivate='spack env deactivate'
|
||||
''' % (env, env_name_prompt))
|
||||
|
||||
|
||||
#
|
||||
# env deactivate
|
||||
#
|
||||
def env_deactivate_setup_parser(subparser):
|
||||
"""deactivate any active environment in the shell"""
|
||||
shells = subparser.add_mutually_exclusive_group()
|
||||
shells.add_argument(
|
||||
'--sh', action='store_const', dest='shell', const='sh',
|
||||
help="print sh commands to deactivate the environment")
|
||||
shells.add_argument(
|
||||
'--csh', action='store_const', dest='shell', const='csh',
|
||||
help="print csh commands to deactivate the environment")
|
||||
|
||||
|
||||
def env_deactivate(args):
|
||||
if not args.shell:
|
||||
msg = [
|
||||
"This command works best with Spack's shell support",
|
||||
""
|
||||
] + spack.cmd.common.shell_init_instructions + [
|
||||
'Or, if you want to use `spack env activate` without initializing',
|
||||
'shell support, you can run one of these:',
|
||||
'',
|
||||
' eval `spack env deactivate --sh` # for bash/sh',
|
||||
' eval `spack env deactivate --csh` # for csh/tcsh',
|
||||
]
|
||||
tty.msg(*msg)
|
||||
return 1
|
||||
|
||||
if 'SPACK_ENV' not in os.environ:
|
||||
tty.die('No environment is currently active.')
|
||||
|
||||
if args.shell == 'csh':
|
||||
sys.stdout.write('''\
|
||||
unsetenv SPACK_ENV;
|
||||
set prompt="${SPACK_OLD_PROMPT}";
|
||||
unsetenv SPACK_OLD_PROMPT;
|
||||
unalias despacktivate;
|
||||
''')
|
||||
else:
|
||||
sys.stdout.write('''\
|
||||
unset SPACK_ENV; export SPACK_ENV;
|
||||
export PS1="$SPACK_OLD_PS1";
|
||||
unset SPACK_OLD_PS1; export SPACK_OLD_PS1;
|
||||
unalias despacktivate;
|
||||
''')
|
||||
|
||||
|
||||
#
|
||||
# env create
|
||||
#
|
||||
@ -59,12 +196,12 @@ def env_create_setup_parser(subparser):
|
||||
def env_create(args):
|
||||
if args.envfile:
|
||||
with open(args.envfile) as f:
|
||||
_environment_create(args.env, f)
|
||||
_env_create(args.env, f)
|
||||
else:
|
||||
_environment_create(args.env)
|
||||
_env_create(args.env)
|
||||
|
||||
|
||||
def _environment_create(name, env_yaml=None):
|
||||
def _env_create(name, env_yaml=None):
|
||||
"""Create a new environment, with an optional yaml description.
|
||||
|
||||
Arguments:
|
||||
@ -93,7 +230,7 @@ def env_destroy_setup_parser(subparser):
|
||||
|
||||
def env_destroy(args):
|
||||
for env in args.env:
|
||||
if not ev.exists(ev.root(env)):
|
||||
if not ev.exists(env):
|
||||
tty.die("No such environment: '%s'" % env)
|
||||
elif not os.access(ev.root(env), os.W_OK):
|
||||
tty.die("insufficient permissions to modify environment: '%s'"
|
||||
@ -152,10 +289,8 @@ def env_add_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_add(args):
|
||||
if not args.env:
|
||||
tty.die('spack env unadd requires an active env or argument')
|
||||
env = get_env(args, 'add')
|
||||
|
||||
env = ev.read(args.env)
|
||||
for spec in spack.cmd.parse_specs(args.specs):
|
||||
if not env.add(spec):
|
||||
tty.msg("Package {0} was already added to {1}"
|
||||
@ -204,17 +339,14 @@ def env_concretize_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_concretize(args):
|
||||
if not args.env:
|
||||
tty.die('spack env status requires an active env or argument')
|
||||
environment = ev.read(args.env)
|
||||
_environment_concretize(
|
||||
environment, use_repo=bool(args.exact_env), force=args.force)
|
||||
env = get_env(args, 'status')
|
||||
_env_concretize(env, use_repo=bool(args.exact_env), force=args.force)
|
||||
|
||||
|
||||
def _environment_concretize(environment, use_repo=False, force=False):
|
||||
def _env_concretize(env, use_repo=False, force=False):
|
||||
"""Function body separated out to aid in testing."""
|
||||
new_specs = environment.concretize(force=force)
|
||||
environment.write(dump_packages=new_specs)
|
||||
new_specs = env.concretize(force=force)
|
||||
env.write(dump_packages=new_specs)
|
||||
|
||||
|
||||
# REMOVE
|
||||
@ -228,10 +360,7 @@ def env_install_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_install(args):
|
||||
if not args.env:
|
||||
tty.die('spack env status requires an active env or argument')
|
||||
|
||||
env = ev.read(args.env)
|
||||
env = get_env(args, 'status')
|
||||
env.install(args)
|
||||
|
||||
|
||||
@ -246,11 +375,8 @@ def env_uninstall_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_uninstall(args):
|
||||
if not args.env:
|
||||
tty.die('spack env uninstall requires an active env or argument')
|
||||
|
||||
environment = ev.read(args.env)
|
||||
environment.uninstall(args)
|
||||
env = get_env(args, 'uninstall')
|
||||
env.uninstall(args)
|
||||
|
||||
|
||||
#
|
||||
@ -262,9 +388,9 @@ def env_relocate_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_relocate(args):
|
||||
environment = ev.read(args.env)
|
||||
environment.reset_os_and_compiler(compiler=args.compiler)
|
||||
environment.write()
|
||||
env = get_env(args, 'relocate')
|
||||
env.reset_os_and_compiler(compiler=args.compiler)
|
||||
env.write()
|
||||
|
||||
|
||||
#
|
||||
@ -280,12 +406,10 @@ def env_status_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_status(args):
|
||||
if not args.env:
|
||||
tty.die('spack env status requires an active env or argument')
|
||||
env = get_env(args, 'status')
|
||||
|
||||
# TODO? option to show packages w/ multiple instances?
|
||||
environment = ev.read(args.env)
|
||||
environment.status(
|
||||
# TODO: option to show packages w/ multiple instances?
|
||||
env.status(
|
||||
sys.stdout, recurse_dependencies=args.recurse_dependencies,
|
||||
hashes=args.long or args.very_long,
|
||||
hashlen=None if args.very_long else 7,
|
||||
@ -302,11 +426,8 @@ def env_stage_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_stage(args):
|
||||
if not args.env:
|
||||
tty.die('spack env loads requires an active env or argument')
|
||||
|
||||
environment = ev.read(args.env)
|
||||
for spec in environment.specs_by_hash.values():
|
||||
env = get_env(args, 'stage')
|
||||
for spec in env.specs_by_hash.values():
|
||||
for dep in spec.traverse():
|
||||
dep.package.do_stage()
|
||||
|
||||
@ -325,8 +446,7 @@ def env_loads_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_loads(args):
|
||||
if not args.env:
|
||||
tty.die('spack env loads requires an active env or argument')
|
||||
env = get_env(args, 'loads')
|
||||
|
||||
# Set the module types that have been selected
|
||||
module_type = args.module_type
|
||||
@ -334,13 +454,12 @@ def env_loads(args):
|
||||
# If no selection has been made select all of them
|
||||
module_type = 'tcl'
|
||||
|
||||
environment = ev.read(args.env)
|
||||
recurse_dependencies = args.recurse_dependencies
|
||||
args.recurse_dependencies = False
|
||||
|
||||
loads_file = fs.join_path(environment.path, 'loads')
|
||||
loads_file = fs.join_path(env.path, 'loads')
|
||||
with open(loads_file, 'w') as f:
|
||||
specs = environment._get_environment_specs(
|
||||
specs = env._get_environment_specs(
|
||||
recurse_dependencies=recurse_dependencies)
|
||||
|
||||
spack.cmd.modules.loads(module_type, specs, args, f)
|
||||
@ -360,7 +479,7 @@ def env_upgrade_setup_parser(subparser):
|
||||
|
||||
|
||||
def env_upgrade(args):
|
||||
env = ev.read(args.env)
|
||||
env = get_env(args, 'upgrade')
|
||||
|
||||
if os.path.exists(env.repos_path):
|
||||
repo_stage = tempfile.mkdtemp()
|
||||
|
@ -26,6 +26,10 @@
|
||||
from spack.version import VersionList
|
||||
|
||||
|
||||
#: environment variable used to indicate the active environment
|
||||
spack_env_var = 'SPACK_ENV'
|
||||
|
||||
|
||||
#: currently activated environment
|
||||
active = None
|
||||
|
||||
|
@ -587,6 +587,10 @@ def main(argv=None):
|
||||
env = args.env or args.exact_env
|
||||
if env:
|
||||
spack.environment.activate(env, args.exact_env is not None)
|
||||
else:
|
||||
env = os.environ.get(spack.environment.spack_env_var)
|
||||
if env:
|
||||
spack.environment.activate(env, False)
|
||||
|
||||
# make spack.config aware of any command line configuration scopes
|
||||
if args.config_scopes:
|
||||
|
@ -14,4 +14,4 @@ def test_cd():
|
||||
|
||||
out = cd()
|
||||
|
||||
assert "To initialize spack's shell commands, you must run one of" in out
|
||||
assert "To initialize spack's shell commands:" in out
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
import spack.modules
|
||||
import spack.environment as ev
|
||||
from spack.cmd.env import _environment_concretize, _environment_create
|
||||
from spack.cmd.env import _env_concretize, _env_create
|
||||
from spack.version import Version
|
||||
from spack.spec import Spec
|
||||
from spack.main import SpackCommand
|
||||
@ -170,7 +170,7 @@ def test_to_lockfile_dict():
|
||||
def test_env_repo():
|
||||
e = ev.Environment('testx')
|
||||
e.add('mpileaks')
|
||||
_environment_concretize(e)
|
||||
_env_concretize(e)
|
||||
|
||||
package = e.repo.get(spack.spec.Spec('mpileaks'))
|
||||
assert package.namespace == 'spack.pkg.builtin.mock'
|
||||
@ -246,7 +246,7 @@ def test_env_with_config():
|
||||
"""
|
||||
spack.package_prefs.PackagePrefs.clear_caches()
|
||||
|
||||
_environment_create('test', test_config)
|
||||
_env_create('test', test_config)
|
||||
|
||||
e = ev.read('test')
|
||||
ev.prepare_config_scope(e)
|
||||
@ -266,7 +266,7 @@ def test_env_with_included_config_file():
|
||||
"""
|
||||
spack.package_prefs.PackagePrefs.clear_caches()
|
||||
|
||||
_environment_create('test', test_config)
|
||||
_env_create('test', test_config)
|
||||
|
||||
e = ev.read('test')
|
||||
|
||||
@ -296,7 +296,7 @@ def test_env_with_included_config_scope():
|
||||
""" % config_scope_path
|
||||
|
||||
spack.package_prefs.PackagePrefs.clear_caches()
|
||||
_environment_create('test', test_config)
|
||||
_env_create('test', test_config)
|
||||
|
||||
e = ev.read('test')
|
||||
|
||||
@ -328,7 +328,7 @@ def test_env_config_precedence():
|
||||
"""
|
||||
spack.package_prefs.PackagePrefs.clear_caches()
|
||||
|
||||
_environment_create('test', test_config)
|
||||
_env_create('test', test_config)
|
||||
|
||||
e = ev.read('test')
|
||||
|
||||
|
@ -63,6 +63,47 @@ case cd:
|
||||
cd `\spack location $_sp_arg $_sp_args`
|
||||
endif
|
||||
breaksw
|
||||
case env:
|
||||
shift _sp_args # get rid of 'env'
|
||||
|
||||
set _sp_arg=""
|
||||
[ $#_sp_args -gt 0 ] && set _sp_arg = ($_sp_args[1])
|
||||
|
||||
if ( "$_sp_arg" == "-h" ) then
|
||||
\spack env -h
|
||||
else
|
||||
switch ($_sp_arg)
|
||||
case activate:
|
||||
set _sp_env_arg=""
|
||||
[ $#_sp_args -gt 1 ] && set _sp_env_arg = ($_sp_args[2])
|
||||
|
||||
if ( "$_sp_env_arg" == "" || "$_sp_env_arg" =~ "-*" ) then
|
||||
# no args or does not start with -: just execute
|
||||
\spack $_sp_flags env $_sp_args
|
||||
else
|
||||
shift _sp_args # consume 'activate' or 'deactivate'
|
||||
# actual call to activate: source the output
|
||||
eval `\spack $_sp_flags env activate --csh $_sp_args`
|
||||
endif
|
||||
breaksw
|
||||
case deactivate:
|
||||
set _sp_env_arg=""
|
||||
[ $#_sp_args -gt 1 ] && set _sp_env_arg = ($_sp_args[2])
|
||||
|
||||
if ( "$_sp_env_arg" != "" ) then
|
||||
# with args: execute the command
|
||||
\spack $_sp_flags env $_sp_args
|
||||
else
|
||||
# no args: source the output
|
||||
eval `\spack $_sp_flags env deactivate --csh`
|
||||
endif
|
||||
breaksw
|
||||
default:
|
||||
echo default
|
||||
\spack $_sp_flags env $_sp_args
|
||||
breaksw
|
||||
endsw
|
||||
endif
|
||||
case use:
|
||||
case unuse:
|
||||
case load:
|
||||
@ -113,3 +154,4 @@ endsw
|
||||
_sp_end:
|
||||
unset _sp_args _sp_full_spec _sp_modtype _sp_module_args
|
||||
unset _sp_sh_cmd _sp_spec _sp_subcommand _sp_flags
|
||||
unset _sp_arg _sp_env_arg
|
||||
|
@ -28,5 +28,6 @@ if ($?SPACK_ROOT) then
|
||||
_spack_pathadd DK_NODE "$_sp_dotkit_root/$_sp_sys_type"
|
||||
_spack_pathadd MODULEPATH "$_sp_tcl_root/$_sp_sys_type"
|
||||
else
|
||||
echo "ERROR: Sourcing spack setup-env.csh requires setting SPACK_ROOT to the root of your spack installation"
|
||||
echo "ERROR: Sourcing spack setup-env.csh requires setting SPACK_ROOT to "
|
||||
echo " the root of your spack installation."
|
||||
endif
|
||||
|
@ -89,6 +89,42 @@ function spack {
|
||||
fi
|
||||
return
|
||||
;;
|
||||
"env")
|
||||
_sp_arg=""
|
||||
if [ -n "$1" ]; then
|
||||
_sp_arg="$1"
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$_sp_arg" = "-h" ]; then
|
||||
command spack env -h
|
||||
else
|
||||
case $_sp_arg in
|
||||
activate)
|
||||
if [ -z "$1" -o "${1#-}" != "$1" ]; then
|
||||
# no args or does not start with -: just execute
|
||||
command spack "${args[@]}"
|
||||
else
|
||||
# actual call to activate: source the output
|
||||
eval $(command spack $_sp_flags env activate --sh "$@")
|
||||
fi
|
||||
;;
|
||||
deactivate)
|
||||
if [ -n "$1" ]; then
|
||||
# with args: execute the command
|
||||
command spack "${args[@]}"
|
||||
else
|
||||
# no args: source the output.
|
||||
eval $(command spack $_sp_flags env deactivate --sh)
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
command spack "${args[@]}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
return
|
||||
;;
|
||||
"use"|"unuse"|"load"|"unload")
|
||||
# Shift any other args for use off before parsing spec.
|
||||
_sp_subcommand_args=""
|
||||
|
Loading…
Reference in New Issue
Block a user