Add option "--first" for "spack load" (#15622)

* Implemented --first option for "spack load"

* added test for "spack load --first"

Co-authored-by: gragghia <gragghia@localhost.localdomain>
This commit is contained in:
G-Ragghianti 2020-04-03 16:33:20 -04:00 committed by GitHub
parent 0b99cc2261
commit bae4f91bfe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 8 deletions

View file

@ -284,8 +284,10 @@ have some drawbacks:
The ``spack load`` and ``spack module tcl loads`` commands, on the The ``spack load`` and ``spack module tcl loads`` commands, on the
other hand, are not very smart: if the user-supplied spec matches other hand, are not very smart: if the user-supplied spec matches
more than one installed package, then ``spack module tcl loads`` will more than one installed package, then ``spack module tcl loads`` will
fail. This may change in the future. For now, the workaround is to fail. This default behavior may change in the future. For now,
be more specific on any ``spack load`` commands that fail. the workaround is to either be more specific on any failing ``spack load``
commands or to use ``spack load --first`` to allow spack to load the
first matching spec.
"""""""""""""""""""""" """"""""""""""""""""""

View file

@ -177,7 +177,7 @@ def elide_list(line_list, max_num=10):
return line_list return line_list
def disambiguate_spec(spec, env, local=False, installed=True): def disambiguate_spec(spec, env, local=False, installed=True, first=False):
"""Given a spec, figure out which installed package it refers to. """Given a spec, figure out which installed package it refers to.
Arguments: Arguments:
@ -190,10 +190,11 @@ def disambiguate_spec(spec, env, local=False, installed=True):
database query. See ``spack.database.Database._query`` for details. database query. See ``spack.database.Database._query`` for details.
""" """
hashes = env.all_hashes() if env else None hashes = env.all_hashes() if env else None
return disambiguate_spec_from_hashes(spec, hashes, local, installed) return disambiguate_spec_from_hashes(spec, hashes, local, installed, first)
def disambiguate_spec_from_hashes(spec, hashes, local=False, installed=True): def disambiguate_spec_from_hashes(spec, hashes, local=False,
installed=True, first=False):
"""Given a spec and a list of hashes, get concrete spec the spec refers to. """Given a spec and a list of hashes, get concrete spec the spec refers to.
Arguments: Arguments:
@ -213,6 +214,9 @@ def disambiguate_spec_from_hashes(spec, hashes, local=False, installed=True):
if not matching_specs: if not matching_specs:
tty.die("Spec '%s' matches no installed packages." % spec) tty.die("Spec '%s' matches no installed packages." % spec)
elif first:
return matching_specs[0]
elif len(matching_specs) > 1: elif len(matching_specs) > 1:
format_string = '{name}{@version}{%compiler}{arch=architecture}' format_string = '{name}{@version}{%compiler}{arch=architecture}'
args = ["%s matches multiple packages." % spec, args = ["%s matches multiple packages." % spec,

View file

@ -33,6 +33,14 @@ def setup_parser(subparser):
'--csh', action='store_const', dest='shell', const='csh', '--csh', action='store_const', dest='shell', const='csh',
help="print csh commands to load the package") help="print csh commands to load the package")
subparser.add_argument(
'--first',
action='store_true',
default=False,
dest='load_first',
help="load the first match if multiple packages match the spec"
)
subparser.add_argument( subparser.add_argument(
'--only', '--only',
default='package,dependencies', default='package,dependencies',
@ -47,7 +55,7 @@ def setup_parser(subparser):
def load(parser, args): def load(parser, args):
env = ev.get_env(args, 'load') env = ev.get_env(args, 'load')
specs = [spack.cmd.disambiguate_spec(spec, env) specs = [spack.cmd.disambiguate_spec(spec, env, first=args.load_first)
for spec in spack.cmd.parse_specs(args.specs)] for spec in spack.cmd.parse_specs(args.specs)]
if not args.shell: if not args.shell:

View file

@ -3,7 +3,8 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os import os
from spack.main import SpackCommand import pytest
from spack.main import SpackCommand, SpackCommandError
import spack.spec import spack.spec
import spack.user_environment as uenv import spack.user_environment as uenv
@ -83,6 +84,18 @@ def test_load_includes_run_env(install_mockery, mock_fetch, mock_archive,
assert 'setenv FOOBAR mpileaks' in csh_out assert 'setenv FOOBAR mpileaks' in csh_out
def test_load_first(install_mockery, mock_fetch, mock_archive, mock_packages):
"""Test with and without the --first option"""
install('libelf@0.8.12')
install('libelf@0.8.13')
# Now there are two versions of libelf
with pytest.raises(SpackCommandError):
# This should cause an error due to multiple versions
load('--sh', 'libelf')
# Using --first should avoid the error condition
load('--sh', '--first', 'libelf')
def test_load_fails_no_shell(install_mockery, mock_fetch, mock_archive, def test_load_fails_no_shell(install_mockery, mock_fetch, mock_archive,
mock_packages): mock_packages):
"""Test that spack load prints an error message without a shell.""" """Test that spack load prints an error message without a shell."""

View file

@ -984,7 +984,7 @@ _spack_list() {
_spack_load() { _spack_load() {
if $list_options if $list_options
then then
SPACK_COMPREPLY="-h --help -r --dependencies --sh --csh --only" SPACK_COMPREPLY="-h --help -r --dependencies --sh --csh --first --only"
else else
_installed_packages _installed_packages
fi fi