summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2018-11-07 18:43:35 -0800
committerPeter Scheibel <scheibel1@llnl.gov>2018-11-11 18:32:24 -0600
commit8d92fd66401a46af641c799394480140300f2e3d (patch)
tree90d3a481f6b28f3b3e328ac55b89e4a6414d3278 /lib
parent25f8abb9639d62bd9078cdad62ad0c1c10488858 (diff)
downloadspack-8d92fd66401a46af641c799394480140300f2e3d.tar.gz
spack-8d92fd66401a46af641c799394480140300f2e3d.tar.bz2
spack-8d92fd66401a46af641c799394480140300f2e3d.tar.xz
spack-8d92fd66401a46af641c799394480140300f2e3d.zip
env: make `spack config edit` and `spack config get` environment-aware
- with no arguments, these commands will now edit or dump the environment's `spack.yaml` file. - users may not know where named environments live - this makes it convenient for users to get to the spack.yaml configuration file for their named environment.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/cmd/config.py83
-rw-r--r--lib/spack/spack/environment.py6
-rw-r--r--lib/spack/spack/test/cmd/config.py93
-rw-r--r--lib/spack/spack/test/config.py14
-rw-r--r--lib/spack/spack/test/conftest.py14
5 files changed, 183 insertions, 27 deletions
diff --git a/lib/spack/spack/cmd/config.py b/lib/spack/spack/cmd/config.py
index 754b1e8336..4fd21768c8 100644
--- a/lib/spack/spack/cmd/config.py
+++ b/lib/spack/spack/cmd/config.py
@@ -3,7 +3,13 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+from __future__ import print_function
+import os
+
+import llnl.util.tty as tty
+
import spack.config
+import spack.environment as ev
from spack.util.editor import editor
@@ -27,6 +33,7 @@ def setup_parser(subparser):
get_parser.add_argument('section',
help="configuration section to print. "
"options: %(choices)s",
+ nargs='?',
metavar='SECTION',
choices=spack.config.section_schemas)
@@ -43,29 +50,81 @@ def setup_parser(subparser):
help="configuration section to edit. "
"options: %(choices)s",
metavar='SECTION',
+ nargs='?',
choices=spack.config.section_schemas)
+ edit_parser.add_argument(
+ '--print-file', action='store_true',
+ help="print the file name that would be edited")
+
+
+def _get_scope_and_section(args):
+ """Extract config scope and section from arguments."""
+ scope = args.scope
+ section = args.section
+
+ # w/no args and an active environment, point to env manifest
+ if not args.section:
+ env = ev.get_env(args, 'config edit', required=False)
+ if env:
+ scope = env.env_file_config_scope_name()
+
+ # set scope defaults
+ elif not args.scope:
+ if section == 'compilers':
+ scope = spack.config.default_modify_scope()
+ else:
+ scope = 'user'
+
+ return scope, section
def config_get(args):
- spack.config.config.print_section(args.section)
+ """Dump merged YAML configuration for a specific section.
+
+ With no arguments and an active environment, print the contents of
+ the environment's manifest file (spack.yaml).
+
+ """
+ scope, section = _get_scope_and_section(args)
+
+ if scope and scope.startswith('env:'):
+ config_file = spack.config.config.get_config_filename(scope, section)
+ if os.path.exists(config_file):
+ with open(config_file) as f:
+ print(f.read())
+ else:
+ tty.die('environment has no %s file' % ev.manifest_name)
+
+ elif section is not None:
+ spack.config.config.print_section(section)
+
+ else:
+ tty.die('`spack config get` requires a section argument '
+ 'or an active environment.')
def config_blame(args):
+ """Print out line-by-line blame of merged YAML."""
spack.config.config.print_section(args.section, blame=True)
def config_edit(args):
- if not args.scope:
- if args.section == 'compilers':
- args.scope = spack.config.default_modify_scope()
- else:
- args.scope = 'user'
- if not args.section:
- args.section = None
-
- config = spack.config.config
- config_file = config.get_config_filename(args.scope, args.section)
- editor(config_file)
+ """Edit the configuration file for a specific scope and config section.
+
+ With no arguments and an active environment, edit the spack.yaml for
+ the active environment.
+
+ """
+ scope, section = _get_scope_and_section(args)
+ if not scope and not section:
+ tty.die('`spack config edit` requires a section argument '
+ 'or an active environment.')
+
+ config_file = spack.config.config.get_config_filename(scope, section)
+ if args.print_file:
+ print(config_file)
+ else:
+ editor(config_file)
def config(parser, args):
diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py
index 208eb485ae..1ac5a99159 100644
--- a/lib/spack/spack/environment.py
+++ b/lib/spack/spack/environment.py
@@ -483,9 +483,13 @@ class Environment(object):
return scopes
+ def env_file_config_scope_name(self):
+ """Name of the config scope of this environment's manifest file."""
+ return 'env:%s' % self.name
+
def env_file_config_scope(self):
"""Get the configuration scope for the environment's manifest file."""
- config_name = 'env:%s' % self.name
+ config_name = self.env_file_config_scope_name()
return spack.config.SingleFileScope(config_name,
self.manifest_path,
spack.schema.env.schema,
diff --git a/lib/spack/spack/test/cmd/config.py b/lib/spack/spack/test/cmd/config.py
new file mode 100644
index 0000000000..493236709b
--- /dev/null
+++ b/lib/spack/spack/test/cmd/config.py
@@ -0,0 +1,93 @@
+# Copyright 2013-2018 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+import os
+
+from llnl.util.filesystem import mkdirp
+
+import spack.config
+import spack.environment as ev
+from spack.main import SpackCommand
+
+config = SpackCommand('config')
+
+
+def test_get_config_scope(mock_config):
+ assert config('get', 'compilers').strip() == 'compilers: {}'
+
+
+def test_get_config_scope_merged(mock_config):
+ low_path = mock_config.scopes['low'].path
+ high_path = mock_config.scopes['high'].path
+
+ mkdirp(low_path)
+ mkdirp(high_path)
+
+ with open(os.path.join(low_path, 'repos.yaml'), 'w') as f:
+ f.write('''\
+repos:
+- repo3
+''')
+
+ with open(os.path.join(high_path, 'repos.yaml'), 'w') as f:
+ f.write('''\
+repos:
+- repo1
+- repo2
+''')
+
+ assert config('get', 'repos').strip() == '''repos:
+- repo1
+- repo2
+- repo3'''
+
+
+def test_config_edit():
+ """Ensure `spack config edit` edits the right paths."""
+ dms = spack.config.default_modify_scope()
+ dms_path = spack.config.config.scopes[dms].path
+ user_path = spack.config.config.scopes['user'].path
+
+ comp_path = os.path.join(dms_path, 'compilers.yaml')
+ repos_path = os.path.join(user_path, 'repos.yaml')
+
+ assert config('edit', '--print-file', 'compilers').strip() == comp_path
+ assert config('edit', '--print-file', 'repos').strip() == repos_path
+
+
+def test_config_get_gets_spack_yaml(mutable_mock_env_path):
+ env = ev.create('test')
+
+ config('get', fail_on_error=False)
+ assert config.returncode == 1
+
+ with env:
+ config('get', fail_on_error=False)
+ assert config.returncode == 1
+
+ env.write()
+
+ assert 'mpileaks' not in config('get')
+
+ env.add('mpileaks')
+ env.write()
+
+ assert 'mpileaks' in config('get')
+
+
+def test_config_edit_edits_spack_yaml(mutable_mock_env_path):
+ env = ev.create('test')
+ with env:
+ assert config('edit', '--print-file').strip() == env.manifest_path
+
+
+def test_config_edit_fails_correctly_with_no_env(mutable_mock_env_path):
+ output = config('edit', '--print-file', fail_on_error=False)
+ assert "requires a section argument or an active environment" in output
+
+
+def test_config_get_fails_correctly_with_no_env(mutable_mock_env_path):
+ output = config('get', fail_on_error=False)
+ assert "requires a section argument or an active environment" in output
diff --git a/lib/spack/spack/test/config.py b/lib/spack/spack/test/config.py
index 1a162bd598..1235d57f30 100644
--- a/lib/spack/spack/test/config.py
+++ b/lib/spack/spack/test/config.py
@@ -50,20 +50,6 @@ config_override_list = {
@pytest.fixture()
-def mock_config(tmpdir):
- """Mocks the configuration scope."""
- real_configuration = spack.config.config
-
- spack.config.config = spack.config.Configuration(
- *[spack.config.ConfigScope(name, str(tmpdir.join(name)))
- for name in ['low', 'high']])
-
- yield spack.config.config
-
- spack.config.config = real_configuration
-
-
-@pytest.fixture()
def write_config_file(tmpdir):
"""Returns a function that writes a config file."""
def _write(config, data, scope):
diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py
index 4405335cf4..ad0644da3e 100644
--- a/lib/spack/spack/test/conftest.py
+++ b/lib/spack/spack/test/conftest.py
@@ -309,6 +309,20 @@ def mutable_config(tmpdir_factory, configuration_dir, config):
spack.package_prefs.PackagePrefs.clear_caches()
+@pytest.fixture()
+def mock_config(tmpdir):
+ """Mocks two configuration scopes: 'low' and 'high'."""
+ real_configuration = spack.config.config
+
+ spack.config.config = spack.config.Configuration(
+ *[spack.config.ConfigScope(name, str(tmpdir.join(name)))
+ for name in ['low', 'high']])
+
+ yield spack.config.config
+
+ spack.config.config = real_configuration
+
+
def _populate(mock_db):
r"""Populate a mock database with packages.