From bae4f91bfe4e93cb8f2364c6580a54dfda0e3832 Mon Sep 17 00:00:00 2001 From: G-Ragghianti <33492707+G-Ragghianti@users.noreply.github.com> Date: Fri, 3 Apr 2020 16:33:20 -0400 Subject: Add option "--first" for "spack load" (#15622) * Implemented --first option for "spack load" * added test for "spack load --first" Co-authored-by: gragghia --- lib/spack/docs/workflows.rst | 6 ++++-- lib/spack/spack/cmd/__init__.py | 10 +++++++--- lib/spack/spack/cmd/load.py | 10 +++++++++- lib/spack/spack/test/cmd/load.py | 15 ++++++++++++++- 4 files changed, 34 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/spack/docs/workflows.rst b/lib/spack/docs/workflows.rst index 89d17e98b2..9ce664b6ca 100644 --- a/lib/spack/docs/workflows.rst +++ b/lib/spack/docs/workflows.rst @@ -284,8 +284,10 @@ have some drawbacks: The ``spack load`` and ``spack module tcl loads`` commands, on the other hand, are not very smart: if the user-supplied spec matches more than one installed package, then ``spack module tcl loads`` will - fail. This may change in the future. For now, the workaround is to - be more specific on any ``spack load`` commands that fail. + fail. This default behavior may change in the future. For now, + 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. """""""""""""""""""""" diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py index 2a75a87b54..83e12004a1 100644 --- a/lib/spack/spack/cmd/__init__.py +++ b/lib/spack/spack/cmd/__init__.py @@ -177,7 +177,7 @@ def elide_list(line_list, max_num=10): 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. Arguments: @@ -190,10 +190,11 @@ def disambiguate_spec(spec, env, local=False, installed=True): database query. See ``spack.database.Database._query`` for details. """ 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. Arguments: @@ -213,6 +214,9 @@ def disambiguate_spec_from_hashes(spec, hashes, local=False, installed=True): if not matching_specs: tty.die("Spec '%s' matches no installed packages." % spec) + elif first: + return matching_specs[0] + elif len(matching_specs) > 1: format_string = '{name}{@version}{%compiler}{arch=architecture}' args = ["%s matches multiple packages." % spec, diff --git a/lib/spack/spack/cmd/load.py b/lib/spack/spack/cmd/load.py index 9a00ad1c58..3ef485941f 100644 --- a/lib/spack/spack/cmd/load.py +++ b/lib/spack/spack/cmd/load.py @@ -33,6 +33,14 @@ def setup_parser(subparser): '--csh', action='store_const', dest='shell', const='csh', 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( '--only', default='package,dependencies', @@ -47,7 +55,7 @@ the dependencies""" def load(parser, args): 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)] if not args.shell: diff --git a/lib/spack/spack/test/cmd/load.py b/lib/spack/spack/test/cmd/load.py index a10b99d45b..e6664a9d39 100644 --- a/lib/spack/spack/test/cmd/load.py +++ b/lib/spack/spack/test/cmd/load.py @@ -3,7 +3,8 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os -from spack.main import SpackCommand +import pytest +from spack.main import SpackCommand, SpackCommandError import spack.spec 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 +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, mock_packages): """Test that spack load prints an error message without a shell.""" -- cgit v1.2.3-60-g2f50