summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGreg Becker <becker33@llnl.gov>2019-04-17 18:21:40 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2019-04-17 18:21:40 -0700
commitf242f5f8a99f6fa5bd2739a4f1fdd9b41c44e92e (patch)
treed3a2e4b2b94c8507028058055c4fa04f01841ac4 /lib
parent49334f006d54636a5ed9c81093c913c323b65995 (diff)
downloadspack-f242f5f8a99f6fa5bd2739a4f1fdd9b41c44e92e.tar.gz
spack-f242f5f8a99f6fa5bd2739a4f1fdd9b41c44e92e.tar.bz2
spack-f242f5f8a99f6fa5bd2739a4f1fdd9b41c44e92e.tar.xz
spack-f242f5f8a99f6fa5bd2739a4f1fdd9b41c44e92e.zip
Features: Improve Spec format strings (#10556)
* Update spec format to simpler syntax, maintain backwards compatibility * Switch to new spec.format method throughout internals * update package files for new format strings * documentation and minor code cleanup. removed nonsensical variant sigils
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/docs/config_yaml.rst4
-rw-r--r--lib/spack/docs/configuration.rst4
-rw-r--r--lib/spack/docs/module_file_support.rst4
-rw-r--r--lib/spack/docs/tutorial_modules.rst33
-rw-r--r--lib/spack/docs/workflows.rst6
-rw-r--r--lib/spack/spack/architecture.py28
-rw-r--r--lib/spack/spack/build_environment.py2
-rw-r--r--lib/spack/spack/cmd/__init__.py17
-rw-r--r--lib/spack/spack/cmd/arch.py2
-rw-r--r--lib/spack/spack/cmd/dependencies.py3
-rw-r--r--lib/spack/spack/cmd/dependents.py3
-rw-r--r--lib/spack/spack/cmd/mirror.py4
-rw-r--r--lib/spack/spack/cmd/modules/__init__.py4
-rw-r--r--lib/spack/spack/cmd/spec.py5
-rw-r--r--lib/spack/spack/cmd/uninstall.py3
-rw-r--r--lib/spack/spack/cmd/view.py3
-rw-r--r--lib/spack/spack/compilers/__init__.py4
-rw-r--r--lib/spack/spack/concretize.py8
-rw-r--r--lib/spack/spack/database.py3
-rw-r--r--lib/spack/spack/directory_layout.py10
-rw-r--r--lib/spack/spack/filesystem_view.py3
-rw-r--r--lib/spack/spack/mirror.py7
-rw-r--r--lib/spack/spack/modules/common.py21
-rw-r--r--lib/spack/spack/modules/lmod.py2
-rw-r--r--lib/spack/spack/package.py4
-rw-r--r--lib/spack/spack/spec.py324
-rw-r--r--lib/spack/spack/test/architecture.py37
-rw-r--r--lib/spack/spack/test/cmd/view.py12
-rw-r--r--lib/spack/spack/test/data/modules/lmod/alter_environment.yaml2
-rw-r--r--lib/spack/spack/test/data/modules/tcl/alter_environment.yaml2
-rw-r--r--lib/spack/spack/test/data/modules/tcl/conflicts.yaml4
-rw-r--r--lib/spack/spack/test/data/modules/tcl/invalid_naming_scheme.yaml4
-rw-r--r--lib/spack/spack/test/data/modules/tcl/invalid_token_in_env_var_name.yaml4
-rw-r--r--lib/spack/spack/test/data/modules/tcl/wrong_conflicts.yaml4
-rw-r--r--lib/spack/spack/test/directory_layout.py10
-rw-r--r--lib/spack/spack/test/graph.py12
-rw-r--r--lib/spack/spack/test/modules/tcl.py2
-rw-r--r--lib/spack/spack/test/spec_semantics.py124
-rw-r--r--lib/spack/spack/test/spec_syntax.py10
39 files changed, 561 insertions, 177 deletions
diff --git a/lib/spack/docs/config_yaml.rst b/lib/spack/docs/config_yaml.rst
index 03e9060d45..ad2ff736af 100644
--- a/lib/spack/docs/config_yaml.rst
+++ b/lib/spack/docs/config_yaml.rst
@@ -39,7 +39,7 @@ default path uses the full 32 characters.
Secondly, it is
also possible to modify the entire installation scheme. By default
Spack uses
-``${ARCHITECTURE}/${COMPILERNAME}-${COMPILERVER}/${PACKAGE}-${VERSION}-${HASH}``
+``{architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}``
where the tokens that are available for use in this directive are the
same as those understood by the ``Spec.format`` method. Using this parameter it
is possible to use a different package layout or reduce the depth of
@@ -48,7 +48,7 @@ the installation paths. For example
.. code-block:: yaml
config:
- install_path_scheme: '${PACKAGE}/${VERSION}/${HASH:7}'
+ install_path_scheme: '{name}/{version}/{hash:7}'
would install packages into sub-directories using only the package
name, version and a hash length of 7 characters.
diff --git a/lib/spack/docs/configuration.rst b/lib/spack/docs/configuration.rst
index 6b1621d391..4ce08d067e 100644
--- a/lib/spack/docs/configuration.rst
+++ b/lib/spack/docs/configuration.rst
@@ -459,7 +459,7 @@ account all scopes. For example, to see the fully merged
install_tree: $spack/opt/spack
template_dirs:
- $spack/templates
- directory_layout: ${ARCHITECTURE}/${COMPILERNAME}-${COMPILERVER}/${PACKAGE}-${VERSION}-${HASH}
+ directory_layout: {architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}
module_roots:
tcl: $spack/share/spack/modules
lmod: $spack/share/spack/lmod
@@ -510,7 +510,7 @@ down the problem:
./my-scope/config.yaml:2 install_tree: /path/to/some/tree
/home/myuser/spack/etc/spack/defaults/config.yaml:23 template_dirs:
/home/myuser/spack/etc/spack/defaults/config.yaml:24 - $spack/templates
- /home/myuser/spack/etc/spack/defaults/config.yaml:28 directory_layout: ${ARCHITECTURE}/${COMPILERNAME}-${COMPILERVER}/${PACKAGE}-${VERSION}-${HASH}
+ /home/myuser/spack/etc/spack/defaults/config.yaml:28 directory_layout: {architecture}/{compiler.name}-{compiler.version}/{name}-{version}-{hash}
/home/myuser/spack/etc/spack/defaults/config.yaml:32 module_roots:
/home/myuser/spack/etc/spack/defaults/config.yaml:33 tcl: $spack/share/spack/modules
/home/myuser/spack/etc/spack/defaults/config.yaml:34 lmod: $spack/share/spack/lmod
diff --git a/lib/spack/docs/module_file_support.rst b/lib/spack/docs/module_file_support.rst
index 31fe902790..2335fc73bb 100644
--- a/lib/spack/docs/module_file_support.rst
+++ b/lib/spack/docs/module_file_support.rst
@@ -535,10 +535,10 @@ most likely via the ``+blas`` variant specification.
modules:
tcl:
- naming_scheme: '${PACKAGE}/${VERSION}-${COMPILERNAME}-${COMPILERVER}'
+ naming_scheme: '{name}/{version}-{compiler.name}-{compiler.version}'
all:
conflict:
- - '${PACKAGE}'
+ - '{name}'
- 'intel/14.0.1'
will create module files that will conflict with ``intel/14.0.1`` and with the
diff --git a/lib/spack/docs/tutorial_modules.rst b/lib/spack/docs/tutorial_modules.rst
index 3ae1a04069..8487a03759 100644
--- a/lib/spack/docs/tutorial_modules.rst
+++ b/lib/spack/docs/tutorial_modules.rst
@@ -646,14 +646,14 @@ modules that refer to different flavors of the same library/application:
modules:
tcl:
hash_length: 0
- naming_scheme: '${PACKAGE}/${VERSION}-${COMPILERNAME}-${COMPILERVER}'
+ naming_scheme: '{name}/{version}-{compiler.name}-{compiler.version}'
whitelist:
- gcc
blacklist:
- '%gcc@5.4.0'
all:
conflict:
- - '${PACKAGE}'
+ - '{name}'
suffixes:
'^openblas': openblas
'^netlib-lapack': netlib
@@ -713,14 +713,14 @@ is installed. You can achieve this with Spack by adding an
modules:
tcl:
hash_length: 0
- naming_scheme: '${PACKAGE}/${VERSION}-${COMPILERNAME}-${COMPILERVER}'
+ naming_scheme: '{name}/{version}-{compiler.name}-{compiler.version}'
whitelist:
- gcc
blacklist:
- '%gcc@5.4.0'
all:
conflict:
- - '${PACKAGE}'
+ - '{name}'
suffixes:
'^openblas': openblas
'^netlib-lapack': netlib
@@ -728,7 +728,7 @@ is installed. You can achieve this with Spack by adding an
environment_blacklist: ['CPATH', 'LIBRARY_PATH']
environment:
set:
- '${PACKAGE}_ROOT': '${PREFIX}'
+ '{name}_ROOT': '{prefix}'
netlib-scalapack:
suffixes:
'^openmpi': openmpi
@@ -737,8 +737,9 @@ is installed. You can achieve this with Spack by adding an
Under the hood Spack uses the :meth:`~spack.spec.Spec.format` API to substitute
tokens in either environment variable names or values. There are two caveats though:
-- The set of allowed tokens in variable names is restricted to ``PACKAGE``,
- ``VERSION``, ``COMPILER``, ``COMPILERNAME``, ``COMPILERVER``, ``ARCHITECTURE``
+- The set of allowed tokens in variable names is restricted to
+ ``name``, ``version``, ``compiler``, ``compiler.name``,
+ ``compiler.version``, ``architecture``
- Any token expanded in a variable name is made uppercase, but other than that
case sensitivity is preserved
@@ -784,14 +785,14 @@ etc. in the ``gcc`` module file and apply other custom modifications to the
modules:
tcl:
hash_length: 0
- naming_scheme: '${PACKAGE}/${VERSION}-${COMPILERNAME}-${COMPILERVER}'
+ naming_scheme: '{name}/{version}-{compiler.name}-{compiler.version}'
whitelist:
- gcc
blacklist:
- '%gcc@5.4.0'
all:
conflict:
- - '${PACKAGE}'
+ - '{name}'
suffixes:
'^openblas': openblas
'^netlib-lapack': netlib
@@ -799,7 +800,7 @@ etc. in the ``gcc`` module file and apply other custom modifications to the
environment_blacklist: ['CPATH', 'LIBRARY_PATH']
environment:
set:
- '${PACKAGE}_ROOT': '${PREFIX}'
+ '{name}_ROOT': '{prefix}'
gcc:
environment:
set:
@@ -896,14 +897,14 @@ directive and assigning it the value ``direct``:
tcl:
verbose: True
hash_length: 0
- naming_scheme: '${PACKAGE}/${VERSION}-${COMPILERNAME}-${COMPILERVER}'
+ naming_scheme: '{name}/{version}-{compiler.name}-{compiler.version}'
whitelist:
- gcc
blacklist:
- '%gcc@5.4.0'
all:
conflict:
- - '${PACKAGE}'
+ - '{name}'
suffixes:
'^openblas': openblas
'^netlib-lapack': netlib
@@ -911,7 +912,7 @@ directive and assigning it the value ``direct``:
environment_blacklist: ['CPATH', 'LIBRARY_PATH']
environment:
set:
- '${PACKAGE}_ROOT': '${PREFIX}'
+ '{name}_ROOT': '{prefix}'
gcc:
environment:
set:
@@ -1089,7 +1090,7 @@ After these modifications your configuration file should look like:
environment_blacklist: ['CPATH', 'LIBRARY_PATH']
environment:
set:
- '${PACKAGE}_ROOT': '${PREFIX}'
+ '{name}_ROOT': '{prefix}'
gcc:
environment:
set:
@@ -1298,7 +1299,7 @@ Coming back to our example, let's add ``lapack`` to the hierarchy and remove any
environment_blacklist: ['CPATH', 'LIBRARY_PATH']
environment:
set:
- '${PACKAGE}_ROOT': '${PREFIX}'
+ '{name}_ROOT': '{prefix}'
gcc:
environment:
set:
@@ -1534,7 +1535,7 @@ it's ``netlib-scalapack``:
environment_blacklist: ['CPATH', 'LIBRARY_PATH']
environment:
set:
- '${PACKAGE}_ROOT': '${PREFIX}'
+ '{name}_ROOT': '{prefix}'
gcc:
environment:
set:
diff --git a/lib/spack/docs/workflows.rst b/lib/spack/docs/workflows.rst
index 371fce35a2..454cb15ecc 100644
--- a/lib/spack/docs/workflows.rst
+++ b/lib/spack/docs/workflows.rst
@@ -541,9 +541,9 @@ spec format strings, as shown in the example below.
.. code-block:: yaml
projections:
- zlib: ${PACKAGE}-${VERSION}
- ^mpi: ${PACKAGE}-${VERSION}/${DEP:mpi:PACKAGE}-${DEP:mpi:VERSION}-${COMPILERNAME}-${COMPILERVER}
- all: ${PACKAGE}-${VERSION}/${COMPILERNAME}-${COMPILERVER}
+ zlib: {name}-{version}
+ ^mpi: {name}-{version}/{^mpi.name}-{^mpi.version}-{compiler.name}-{compiler.version}
+ all: {name}-{version}/{compiler.name}-{compiler.version}
The entries in the projections configuration file must all be either
specs or the keyword ``all``. For each spec, the projection used will
diff --git a/lib/spack/spack/architecture.py b/lib/spack/spack/architecture.py
index b37ae18266..eefe5287ae 100644
--- a/lib/spack/spack/architecture.py
+++ b/lib/spack/spack/architecture.py
@@ -336,7 +336,7 @@ class Arch(object):
self.platform = plat
if plat and os:
os = self.platform.operating_system(os)
- self.platform_os = os
+ self.os = os
if plat and target:
target = self.platform.target(target)
self.target = target
@@ -349,16 +349,16 @@ class Arch(object):
def concrete(self):
return all((self.platform is not None,
isinstance(self.platform, Platform),
- self.platform_os is not None,
- isinstance(self.platform_os, OperatingSystem),
+ self.os is not None,
+ isinstance(self.os, OperatingSystem),
self.target is not None, isinstance(self.target, Target)))
def __str__(self):
- if self.platform or self.platform_os or self.target:
+ if self.platform or self.os or self.target:
if self.platform.name == 'darwin':
- os_name = self.platform_os.name if self.platform_os else "None"
+ os_name = self.os.name if self.os else "None"
else:
- os_name = str(self.platform_os)
+ os_name = str(self.os)
return (str(self.platform) + "-" +
os_name + "-" + str(self.target))
@@ -371,7 +371,7 @@ class Arch(object):
# TODO: make this unnecessary: don't include an empty arch on *every* spec.
def __nonzero__(self):
return (self.platform is not None or
- self.platform_os is not None or
+ self.os is not None or
self.target is not None)
__bool__ = __nonzero__
@@ -380,21 +380,21 @@ class Arch(object):
platform = self.platform.name
else:
platform = self.platform
- if isinstance(self.platform_os, OperatingSystem):
- platform_os = self.platform_os.name
+ if isinstance(self.os, OperatingSystem):
+ os = self.os.name
else:
- platform_os = self.platform_os
+ os = self.os
if isinstance(self.target, Target):
target = self.target.name
else:
target = self.target
- return (platform, platform_os, target)
+ return (platform, os, target)
def to_dict(self):
str_or_none = lambda v: str(v) if v else None
d = syaml_dict([
('platform', str_or_none(self.platform)),
- ('platform_os', str_or_none(self.platform_os)),
+ ('platform_os', str_or_none(self.os)),
('target', str_or_none(self.target))])
return syaml_dict([('arch', d)])
@@ -430,13 +430,13 @@ def arch_for_spec(arch_spec):
assert(arch_spec.concrete)
arch_plat = get_platform(arch_spec.platform)
- if not (arch_plat.operating_system(arch_spec.platform_os) and
+ if not (arch_plat.operating_system(arch_spec.os) and
arch_plat.target(arch_spec.target)):
raise ValueError(
"Can't recreate arch for spec %s on current arch %s; "
"spec architecture is too different" % (arch_spec, sys_type()))
- return Arch(arch_plat, arch_spec.platform_os, arch_spec.target)
+ return Arch(arch_plat, arch_spec.os, arch_spec.target)
@memoized
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 614188a281..3d826937ba 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -381,7 +381,7 @@ def set_build_environment_variables(pkg, env, dirty):
if spack.config.get('config:debug'):
env.set(SPACK_DEBUG, 'TRUE')
env.set(SPACK_SHORT_SPEC, pkg.spec.short_spec)
- env.set(SPACK_DEBUG_LOG_ID, pkg.spec.format('${PACKAGE}-${HASH:7}'))
+ env.set(SPACK_DEBUG_LOG_ID, pkg.spec.format('{name}-{hash:7}'))
env.set(SPACK_DEBUG_LOG_DIR, spack.main.spack_working_dir)
# Find ccache binary and hand it to build environment
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py
index 9d003eb656..d1efb99e62 100644
--- a/lib/spack/spack/cmd/__init__.py
+++ b/lib/spack/spack/cmd/__init__.py
@@ -184,10 +184,11 @@ def disambiguate_spec(spec, env):
tty.die("Spec '%s' matches no installed packages." % spec)
elif len(matching_specs) > 1:
+ format_string = '{name}{@version}{%compiler}{arch=architecture}'
args = ["%s matches multiple packages." % spec,
"Matching packages:"]
args += [colorize(" @K{%s} " % s.dag_hash(7)) +
- s.cformat('$_$@$%@$=') for s in matching_specs]
+ s.cformat(format_string) for s in matching_specs]
args += ["Use a more specific spec."]
tty.die(*args)
@@ -263,15 +264,15 @@ def display_specs(specs, args=None, **kwargs):
hashes = True
hlen = None
- nfmt = '{fullpackage}' if namespace else '{package}'
+ nfmt = '{namespace}{name}' if namespace else '{name}'
ffmt = ''
if full_compiler or flags:
- ffmt += '$%'
+ ffmt += '{%compiler.name}'
if full_compiler:
- ffmt += '@'
- ffmt += '+'
- vfmt = '$+' if variants else ''
- format_string = '$%s$@%s%s' % (nfmt, ffmt, vfmt)
+ ffmt += '{@compiler.version}'
+ ffmt += ' {compiler_flags}'
+ vfmt = '{variants}' if variants else ''
+ format_string = nfmt + '{@version}' + ffmt + vfmt
# Make a dict with specs keyed by architecture and compiler.
index = index_by(specs, ('architecture', 'compiler'))
@@ -329,7 +330,7 @@ def display_specs(specs, args=None, **kwargs):
if hashes:
string += gray_hash(s, hlen) + ' '
string += s.cformat(
- '$%s$@%s' % (nfmt, vfmt), transform=transform)
+ nfmt + '{@version}' + vfmt, transform=transform)
return string
if not flags and not full_compiler:
diff --git a/lib/spack/spack/cmd/arch.py b/lib/spack/spack/cmd/arch.py
index 96de71e48f..f3208ec5c0 100644
--- a/lib/spack/spack/cmd/arch.py
+++ b/lib/spack/spack/cmd/arch.py
@@ -32,7 +32,7 @@ def arch(parser, args):
if args.platform:
print(arch.platform)
elif args.operating_system:
- print(arch.platform_os)
+ print(arch.os)
elif args.target:
print(arch.target)
else:
diff --git a/lib/spack/spack/cmd/dependencies.py b/lib/spack/spack/cmd/dependencies.py
index 2dde325ab2..31817783b2 100644
--- a/lib/spack/spack/cmd/dependencies.py
+++ b/lib/spack/spack/cmd/dependencies.py
@@ -42,7 +42,8 @@ def dependencies(parser, args):
env = ev.get_env(args, 'dependencies')
spec = spack.cmd.disambiguate_spec(specs[0], env)
- tty.msg("Dependencies of %s" % spec.format('$_$@$%@$/', color=True))
+ format_string = '{name}{@version}{%compiler}{/hash:7}'
+ tty.msg("Dependencies of %s" % spec.format(format_string, color=True))
deps = spack.store.db.installed_relatives(
spec, 'children', args.transitive)
if deps:
diff --git a/lib/spack/spack/cmd/dependents.py b/lib/spack/spack/cmd/dependents.py
index 51bf1fa656..368dae8f55 100644
--- a/lib/spack/spack/cmd/dependents.py
+++ b/lib/spack/spack/cmd/dependents.py
@@ -85,7 +85,8 @@ def dependents(parser, args):
env = ev.get_env(args, 'dependents')
spec = spack.cmd.disambiguate_spec(specs[0], env)
- tty.msg("Dependents of %s" % spec.cformat('$_$@$%@$/'))
+ format_string = '{name}{@version}{%compiler}{/hash:7}'
+ tty.msg("Dependents of %s" % spec.cformat(format_string))
deps = spack.store.db.installed_relatives(
spec, 'parents', args.transitive)
if deps:
diff --git a/lib/spack/spack/cmd/mirror.py b/lib/spack/spack/cmd/mirror.py
index 1b5167e816..698b78adb5 100644
--- a/lib/spack/spack/cmd/mirror.py
+++ b/lib/spack/spack/cmd/mirror.py
@@ -162,7 +162,7 @@ def mirror_create(args):
# If nothing is passed, use all packages.
if not specs:
specs = [Spec(n) for n in spack.repo.all_package_names()]
- specs.sort(key=lambda s: s.format("$_$@").lower())
+ specs.sort(key=lambda s: s.format("{name}{@version}").lower())
# If the user asked for dependencies, traverse spec DAG get them.
if args.dependencies:
@@ -204,7 +204,7 @@ def mirror_create(args):
" %-4d failed to fetch." % e)
if error:
tty.error("Failed downloads:")
- colify(s.cformat("$_$@") for s in error)
+ colify(s.cformat("{name}{@version}") for s in error)
def mirror(parser, args):
diff --git a/lib/spack/spack/cmd/modules/__init__.py b/lib/spack/spack/cmd/modules/__init__.py
index e3f2e8099b..7fadd73ee0 100644
--- a/lib/spack/spack/cmd/modules/__init__.py
+++ b/lib/spack/spack/cmd/modules/__init__.py
@@ -344,7 +344,9 @@ def modules_cmd(parser, args, module_type, callbacks=callbacks):
except MultipleSpecsMatch:
msg = "the constraint '{query}' matches multiple packages:\n"
for s in specs:
- msg += '\t' + s.cformat(format_string='$/ $_$@$+$%@+$+$=') + '\n'
+ spec_fmt = '{hash:7} {name}{@version}{%compiler}'
+ spec_fmt += '{compiler_flags}{variants}{arch=architecture}'
+ msg += '\t' + s.cformat(spec_fmt) + '\n'
tty.error(msg.format(query=args.constraint))
tty.die('In this context exactly **one** match is needed: please specify your constraints better.') # NOQA: ignore=E501
diff --git a/lib/spack/spack/cmd/spec.py b/lib/spack/spack/cmd/spec.py
index f60e5f1283..64a4a7edc9 100644
--- a/lib/spack/spack/cmd/spec.py
+++ b/lib/spack/spack/cmd/spec.py
@@ -42,11 +42,12 @@ def setup_parser(subparser):
def spec(parser, args):
- name_fmt = '$.' if args.namespaces else '$_'
+ name_fmt = '{namespace}.{name}' if args.namespaces else '{name}'
+ fmt = '{@version}{%compiler}{compiler_flags}{variants}{arch=architecture}'
install_status_fn = spack.spec.Spec.install_status
kwargs = {
'cover': args.cover,
- 'format': name_fmt + '$@$%@+$+$=',
+ 'format': name_fmt + fmt,
'hashlen': None if args.very_long else 7,
'show_types': args.types,
'status_fn': install_status_fn if args.install_status else None
diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py
index cd89f5aba8..532e0c0de4 100644
--- a/lib/spack/spack/cmd/uninstall.py
+++ b/lib/spack/spack/cmd/uninstall.py
@@ -260,7 +260,8 @@ def get_uninstall_list(args, specs, env):
if i > 0:
print()
- tty.info("Will not uninstall %s" % spec.cformat("$_$@$%@$/"),
+ spec_format = '{name}{@version}{%compiler}{/hash:7}'
+ tty.info("Will not uninstall %s" % spec.cformat(spec_format),
format='*r')
dependents = active_dpts.get(spec)
diff --git a/lib/spack/spack/cmd/view.py b/lib/spack/spack/cmd/view.py
index 6ef455770f..5480c28c6d 100644
--- a/lib/spack/spack/cmd/view.py
+++ b/lib/spack/spack/cmd/view.py
@@ -70,10 +70,11 @@ def disambiguate_in_view(specs, view):
matching_in_view = [ms for ms in matching_specs if ms in view_specs]
if len(matching_in_view) > 1:
+ spec_format = '{name}{@version}{%compiler}{arch=architecture}'
args = ["Spec matches multiple packages.",
"Matching packages:"]
args += [colorize(" @K{%s} " % s.dag_hash(7)) +
- s.cformat('$_$@$%@$=') for s in matching_in_view]
+ s.cformat(spec_format) for s in matching_in_view]
args += ["Use a more specific spec."]
tty.die(*args)
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index b2be6d84fd..b7b26e2890 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -307,7 +307,7 @@ def get_compilers(config, cspec=None, arch_spec=None):
# If an arch spec is given, confirm that this compiler
# is for the given operating system
os = items.get('operating_system', None)
- if arch_spec and os != arch_spec.platform_os:
+ if arch_spec and os != arch_spec.os:
continue
# If an arch spec is given, confirm that this compiler
@@ -333,7 +333,7 @@ def compiler_for_spec(compiler_spec, arch_spec):
compilers = compilers_for_spec(compiler_spec, arch_spec=arch_spec)
if len(compilers) < 1:
- raise NoCompilerForSpecError(compiler_spec, arch_spec.platform_os)
+ raise NoCompilerForSpecError(compiler_spec, arch_spec.os)
if len(compilers) > 1:
raise CompilerDuplicateError(compiler_spec, arch_spec)
return compilers[0]
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
index 01f32b8c95..a4d01af996 100644
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -285,7 +285,7 @@ class Concretizer(object):
"""
# Pass on concretizing the compiler if the target or operating system
# is not yet determined
- if not (spec.architecture.platform_os and spec.architecture.target):
+ if not (spec.architecture.os and spec.architecture.target):
# We haven't changed, but other changes need to happen before we
# continue. `return True` here to force concretization to keep
# running.
@@ -371,7 +371,7 @@ class Concretizer(object):
"""
# Pass on concretizing the compiler flags if the target or operating
# system is not set.
- if not (spec.architecture.platform_os and spec.architecture.target):
+ if not (spec.architecture.os and spec.architecture.target):
# We haven't changed, but other changes need to happen before we
# continue. `return True` here to force concretization to keep
# running.
@@ -471,7 +471,7 @@ class NoCompilersForArchError(spack.error.SpackError):
" for operating system %s and target %s."
"\nIf previous installations have succeeded, the"
" operating system may have been updated." %
- (arch.platform_os, arch.target))
+ (arch.os, arch.target))
available_os_target_strs = list()
for os, t in available_os_targets:
@@ -494,7 +494,7 @@ class UnavailableCompilerVersionError(spack.error.SpackError):
err_msg = "No compilers with spec {0} found".format(compiler_spec)
if arch:
err_msg += " for operating system {0} and target {1}.".format(
- arch.platform_os, arch.target
+ arch.os, arch.target
)
super(UnavailableCompilerVersionError, self).__init__(
diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py
index ded79cbd15..9781a7ed75 100644
--- a/lib/spack/spack/database.py
+++ b/lib/spack/spack/database.py
@@ -384,7 +384,8 @@ class Database(object):
if not child:
msg = ("Missing dependency not in database: "
"%s needs %s-%s" % (
- spec.cformat('$_$/'), dname, dhash[:7]))
+ spec.cformat('{name}{/hash:7}'),
+ dname, dhash[:7]))
if self._fail_when_missing_deps:
raise MissingDependenciesError(msg)
tty.warn(msg)
diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py
index 56b5cdeec6..b90daaecad 100644
--- a/lib/spack/spack/directory_layout.py
+++ b/lib/spack/spack/directory_layout.py
@@ -175,15 +175,15 @@ class YamlDirectoryLayout(DirectoryLayout):
super(YamlDirectoryLayout, self).__init__(root)
self.hash_len = kwargs.get('hash_len')
self.path_scheme = kwargs.get('path_scheme') or (
- "${ARCHITECTURE}/"
- "${COMPILERNAME}-${COMPILERVER}/"
- "${PACKAGE}-${VERSION}-${HASH}")
+ "{architecture}/"
+ "{compiler.name}-{compiler.version}/"
+ "{name}-{version}-{hash}")
if self.hash_len is not None:
- if re.search(r'\${HASH:\d+}', self.path_scheme):
+ if re.search(r'{hash:\d+}', self.path_scheme):
raise InvalidDirectoryLayoutParametersError(
"Conflicting options for installation layout hash length")
self.path_scheme = self.path_scheme.replace(
- "${HASH}", "${HASH:%d}" % self.hash_len)
+ "{hash}", "{hash:%d}" % self.hash_len)
# If any of these paths change, downstream databases may not be able to
# locate files in older upstream databases
diff --git a/lib/spack/spack/filesystem_view.py b/lib/spack/spack/filesystem_view.py
index abb6eb4c24..4a6e45172b 100644
--- a/lib/spack/spack/filesystem_view.py
+++ b/lib/spack/spack/filesystem_view.py
@@ -557,7 +557,8 @@ class YamlFilesystemView(FilesystemView):
specs = index[(architecture, compiler)]
specs.sort()
- format_string = '$_$@$%@+$+'
+ format_string = '{name}{@version}'
+ format_string += '{%compiler}{compiler_flags}{variants}'
abbreviated = [s.cformat(format_string) for s in specs]
# Print one spec per line along with prefix path
diff --git a/lib/spack/spack/mirror.py b/lib/spack/spack/mirror.py
index 06868853cf..f8e795ed56 100644
--- a/lib/spack/spack/mirror.py
+++ b/lib/spack/spack/mirror.py
@@ -210,7 +210,9 @@ def create(path, specs, **kwargs):
def add_single_spec(spec, mirror_root, categories, **kwargs):
- tty.msg("Adding package {pkg} to mirror".format(pkg=spec.format("$_$@")))
+ tty.msg("Adding package {pkg} to mirror".format(
+ pkg=spec.format("{name}{@version}")
+ ))
try:
spec.package.do_fetch()
spec.package.do_clean()
@@ -220,7 +222,8 @@ def add_single_spec(spec, mirror_root, categories, **kwargs):
sys.excepthook(*sys.exc_info())
else:
tty.warn(
- "Error while fetching %s" % spec.cformat('$_$@'), e.message)
+ "Error while fetching %s" % spec.cformat('{name}{@version}'),
+ e.message)
categories['error'].append(spec)
diff --git a/lib/spack/spack/modules/common.py b/lib/spack/spack/modules/common.py
index 748013ade4..a372f3dd01 100644
--- a/lib/spack/spack/modules/common.py
+++ b/lib/spack/spack/modules/common.py
@@ -59,12 +59,12 @@ prefix_inspections = spack.config.get('modules:prefix_inspections', {})
#: Valid tokens for naming scheme and env variable names
_valid_tokens = (
- 'PACKAGE',
- 'VERSION',
- 'COMPILER',
- 'COMPILERNAME',
- 'COMPILERVER',
- 'ARCHITECTURE'
+ 'name',
+ 'version',
+ 'compiler',
+ 'compiler.name',
+ 'compiler.version',
+ 'architecture'
)
@@ -80,8 +80,9 @@ def _check_tokens_are_valid(format_string, message):
tokens are found
"""
- named_tokens = re.findall(r'\${(\w*)}', format_string)
- invalid_tokens = [x for x in named_tokens if x not in _valid_tokens]
+ named_tokens = re.findall(r'{(\w*)}', format_string)
+ invalid_tokens = [x for x in named_tokens
+ if x.lower() not in _valid_tokens]
if invalid_tokens:
msg = message
msg += ' [{0}]. '.format(', '.join(invalid_tokens))
@@ -294,7 +295,7 @@ class BaseConfiguration(object):
"""Naming scheme suitable for non-hierarchical layouts"""
scheme = self.module.configuration.get(
'naming_scheme',
- '${PACKAGE}-${VERSION}-${COMPILERNAME}-${COMPILERVER}'
+ '{name}-{version}-{compiler.name}-{compiler.version}'
)
# Ensure the named tokens we are expanding are allowed, see
@@ -523,7 +524,7 @@ class BaseContext(tengine.Context):
value = re.sub(r'"', "'", value)
return value
# Otherwise the short description is just the package + version
- return self.spec.format("$_ $@")
+ return self.spec.format("{name} {@version}")
@tengine.context_property
def long_description(self):
diff --git a/lib/spack/spack/modules/lmod.py b/lib/spack/spack/modules/lmod.py
index 90d5440ba3..a381e08ca9 100644
--- a/lib/spack/spack/modules/lmod.py
+++ b/lib/spack/spack/modules/lmod.py
@@ -232,7 +232,7 @@ class LmodFileLayout(BaseFileLayout):
to console to use it.
"""
# Package name and version
- base = os.path.join("${PACKAGE}", "${VERSION}")
+ base = os.path.join("{name}", "{version}")
name_parts = [self.spec.format(base)]
# The remaining elements are filename suffixes
name_parts.extend(self.conf.suffixes)
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index b54a8abb74..4b81afe84e 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -946,7 +946,7 @@ class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)):
checksum = spack.config.get('config:checksum')
if checksum and self.version not in self.versions:
tty.warn("There is no checksum on file to fetch %s safely." %
- self.spec.cformat('$_$@'))
+ self.spec.cformat('{name}{@version}'))
# Ask the user whether to skip the checksum if we're
# interactive, but just fail if non-interactive.
@@ -960,7 +960,7 @@ class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)):
if not ignore_checksum:
raise FetchError("Will not fetch %s" %
- self.spec.format('$_$@'), ck_msg)
+ self.spec.format('{name}{@version}'), ck_msg)
self.stage.create()
self.stage.fetch(mirror_only)
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 67e0990a19..6afdc92f24 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -96,6 +96,7 @@ from llnl.util.lang import check_kwargs, memoized
from llnl.util.tty.color import cwrite, colorize, cescape, get_color_when
import llnl.util.tty as tty
+import spack.paths
import spack.architecture
import spack.compiler
import spack.compilers as compilers
@@ -187,6 +188,10 @@ _any_version = VersionList([':'])
#: Max integer helps avoid passing too large a value to cyaml.
maxint = 2 ** (ctypes.sizeof(ctypes.c_int) * 8 - 1) - 1
+default_format = '{name}{@version}'
+default_format += '{%compiler.name}{@compiler.version}{compiler_flags}'
+default_format += '{variants}{arch=architecture}'
+
def colorize_spec(spec):
"""Returns a spec colorized according to the colors specified in
@@ -221,7 +226,7 @@ class ArchSpec(object):
def __init__(self, *args):
to_attr_string = lambda s: str(s) if s and s != "None" else None
- self.platform, self.platform_os, self.target = (None, None, None)
+ self.platform, self.os, self.target = (None, None, None)
if len(args) == 1:
spec_like = args[0]
@@ -231,13 +236,13 @@ class ArchSpec(object):
spec_fields = spec_like.split("-")
if len(spec_fields) == 3:
- self.platform, self.platform_os, self.target = tuple(
+ self.platform, self.os, self.target = tuple(
to_attr_string(f) for f in spec_fields)
else:
raise ValueError("%s is an invalid arch spec" % spec_like)
elif len(args) == 3:
self.platform = to_attr_string(args[0])
- self.platform_os = to_attr_string(args[1])
+ self.os = to_attr_string(args[1])
self.target = to_attr_string(args[2])
elif len(args) != 0:
raise TypeError("Can't make arch spec from %s" % args)
@@ -248,11 +253,11 @@ class ArchSpec(object):
return ArchSpec(spec_like)
def _cmp_key(self):
- return (self.platform, self.platform_os, self.target)
+ return (self.platform, self.os, self.target)
def _dup(self, other):
self.platform = other.platform
- self.platform_os = other.platform_os
+ self.os = other.os
self.target = other.target
@property
@@ -269,11 +274,11 @@ class ArchSpec(object):
self._platform = value
@property
- def platform_os(self):
- return self._platform_os
+ def os(self):
+ return self._os
- @platform_os.setter
- def platform_os(self, value):
+ @os.setter
+ def os(self, value):
""" The OS of the architecture spec will update the platform field
if the OS is set to one of the reserved OS types so that the
default OS type can be resolved. Since the reserved OS
@@ -295,7 +300,7 @@ class ArchSpec(object):
spec_platform = spack.architecture.get_platform(self.platform)
value = str(spec_platform.operating_system(value))
- self._platform_os = value
+ self._os = value
@property
def target(self):
@@ -369,13 +374,13 @@ class ArchSpec(object):
"""Returns a dictionary that can be used for field comparison."""
return dict([
('platform', self.platform),
- ('platform_os', self.platform_os),
+ ('os', self.os),
('target', self.target)])
def to_dict(self):
d = syaml_dict([
('platform', self.platform),
- ('platform_os', self.platform_os),
+ ('platform_os', self.os),
('target', self.target)])
return syaml_dict([('arch', d)])
@@ -397,10 +402,13 @@ class ArchSpec(object):
return ArchSpec('spack09', 'unknown', d['arch'])
d = d['arch']
- return ArchSpec(d['platform'], d['platform_os'], d['target'])
+ if 'platform_os' in d:
+ return ArchSpec(d['platform'], d['platform_os'], d['target'])
+ else:
+ return ArchSpec(d['platform'], d['os'], d['target'])
def __str__(self):
- return "%s-%s-%s" % (self.platform, self.platform_os, self.target)
+ return "%s-%s-%s" % (self.platform, self.os, self.target)
def __repr__(self):
return str(self)
@@ -835,10 +843,10 @@ class ForwardQueryToPackage(object):
# properties defined and no default handler, or that all callbacks
# raised AttributeError. In this case, we raise AttributeError with an
# appropriate message.
- fmt = '\'{name}\' package has no relevant attribute \'{query}\'\n' # NOQA: ignore=E501
+ fmt = '\'{name}\' package has no relevant attribute \'{query}\'\n'
fmt += '\tspec : \'{spec}\'\n'
fmt += '\tqueried as : \'{spec.last_query.name}\'\n'
- fmt += '\textra parameters : \'{spec.last_query.extra_parameters}\'\n' # NOQA: ignore=E501
+ fmt += '\textra parameters : \'{spec.last_query.extra_parameters}\'\n'
message = fmt.format(
name=pkg.name,
query=self.attribute_name,
@@ -1004,11 +1012,11 @@ class Spec(object):
if name == 'arch' or name == 'architecture':
parts = tuple(value.split('-'))
plat, os, tgt = parts if len(parts) == 3 else (None, None, value)
- self._set_architecture(platform=plat, platform_os=os, target=tgt)
+ self._set_architecture(platform=plat, os=os, target=tgt)
elif name == 'platform':
self._set_architecture(platform=value)
elif name == 'os' or name == 'operating_system':
- self._set_architecture(platform_os=value)
+ self._set_architecture(os=value)
elif name == 'target':
self._set_architecture(target=value)
elif name in valid_flags:
@@ -1026,7 +1034,7 @@ class Spec(object):
def _set_architecture(self, **kwargs):
"""Called by the parser to set the architecture."""
- arch_attrs = ['platform', 'platform_os', 'target']
+ arch_attrs = ['platform', 'os', 'target']
if self.architecture and self.architecture.concrete:
raise DuplicateArchitectureError(
"Spec for '%s' cannot have two architectures." % self.name)
@@ -1258,12 +1266,16 @@ class Spec(object):
def short_spec(self):
"""Returns a version of the spec with the dependencies hashed
instead of completely enumerated."""
- return self.format('$_$@$%@$+$=$/')
+ spec_format = '{name}{@version}{%compiler}'
+ spec_format += '{variants}{arch=architecture}{/hash:7}'
+ return self.format(spec_format)
@property
def cshort_spec(self):
"""Returns an auto-colorized version of ``self.short_spec``."""
- return self.cformat('$_$@$%@$+$=$/')
+ spec_format = '{name}{@version}{%compiler}'
+ spec_format += '{variants}{arch=architecture}{/hash:7}'
+ return self.cformat(spec_format)
@property
def prefix(self):
@@ -2434,8 +2446,8 @@ class Spec(object):
if sarch.platform is not None and oarch.platform is not None:
if sarch.platform != oarch.platform:
raise UnsatisfiableArchitectureSpecError(sarch, oarch)
- if sarch.platform_os is not None and oarch.platform_os is not None:
- if sarch.platform_os != oarch.platform_os:
+ if sarch.os is not None and oarch.os is not None:
+ if sarch.os != oarch.os:
raise UnsatisfiableArchitectureSpecError(sarch, oarch)
if sarch.target is not None and oarch.target is not None:
if sarch.target != oarch.target:
@@ -2460,8 +2472,8 @@ class Spec(object):
else:
if sarch.platform is None or oarch.platform is None:
self.architecture.platform = sarch.platform or oarch.platform
- if sarch.platform_os is None or oarch.platform_os is None:
- sarch.platform_os = sarch.platform_os or oarch.platform_os
+ if sarch.os is None or oarch.os is None:
+ sarch.os = sarch.os or oarch.os
if sarch.target is None or oarch.target is None:
sarch.target = sarch.target or oarch.target
changed |= (str(self.architecture) != old)
@@ -3010,10 +3022,245 @@ class Spec(object):
def colorized(self):
return colorize_spec(self)
- def format(self, format_string='$_$@$%@+$+$=', **kwargs):
- """Prints out particular pieces of a spec, depending on what is
+ def format(self, format_string=default_format, **kwargs):
+ r"""Prints out particular pieces of a spec, depending on what is
in the format string.
+ Using the ``{attribute}`` syntax, any field of the spec can be
+ selected. Those attributes can be recursive. For example,
+ ``s.format({compiler.version})`` will print the version of the
+ compiler.
+
+ Commonly used attributes of the Spec for format strings include::
+
+ name
+ version
+ compiler
+ compiler.name
+ compiler.version
+ compiler_flags
+ variants
+ architecture
+ architecture.platform
+ architecture.os
+ architecture.target
+ prefix
+
+ Some additional special-case properties can be added::
+
+ hash[:len] The DAG hash with optional length argument
+ spack_root The spack root directory
+ spack_install The spack install directory
+
+ The ``^`` sigil can be used to access dependencies by name.
+ ``s.format({^mpi.name})`` will print the name of the MPI
+ implementation in the spec.
+
+ The ``@``, ``%``, ``arch=``, and ``/`` sigils
+ can be used to include the sigil with the printed
+ string. These sigils may only be used with the appropriate
+ attributes, listed below::
+
+ @ ``{@version}``, ``{@compiler.version}``
+ % ``{%compiler}``, ``{%compiler.name}``
+ arch= ``{arch=architecture}``
+ / ``{/hash}``, ``{/hash:7}``, etc
+
+ The ``@`` sigil may also be used for any other property named
+ ``version``. Sigils printed with the attribute string are only
+ printed if the attribute string is non-empty, and are colored
+ according to the color of the attribute.
+
+ Sigils are not used for printing variants. Variants listed by
+ name naturally print with their sigil. For example,
+ ``spec.format('{variants.debug}')`` would print either
+ ``+debug`` or ``~debug`` depending on the name of the
+ variant. Non-boolean variants print as ``name=value``. To
+ print variant names or values independently, use
+ ``spec.format('{variants.<name>.name}')`` or
+ ``spec.format('{variants.<name>.value}')``.
+
+ Spec format strings use ``\`` as the escape character. Use
+ ``\{`` and ``\}`` for literal braces, and ``\\`` for the
+ literal ``\`` character. Also use ``\$`` for the literal ``$``
+ to differentiate from previous, deprecated format string
+ syntax.
+
+ The previous format strings are deprecated. They can still be
+ accessed by the ``old_format`` method. The ``format`` method
+ will call ``old_format`` if the character ``$`` appears
+ unescaped in the format string.
+
+
+ Args:
+ format_string (str): string containing the format to be expanded
+
+ Keyword Args:
+ color (bool): True if returned string is colored
+ transform (dict): maps full-string formats to a callable \
+ that accepts a string and returns another one
+
+ """
+ # If we have an unescaped $ sigil, use the deprecated format strings
+ if re.search(r'[^\\]*\$', format_string):
+ return self.old_format(format_string, **kwargs)
+
+ color = kwargs.get('color', False)
+ transform = kwargs.get('transform', {})
+
+ out = StringIO()
+
+ def write(s, c=None):
+ f = cescape(s)
+ if c is not None:
+ f = color_formats[c] + f + '@.'
+ cwrite(f, stream=out, color=color)
+
+ def write_attribute(spec, attribute, color):
+ if attribute.startswith('^'):
+ attribute = attribute[1:]
+ dep, attribute = attribute.split('.', 1)
+ current = self[dep]
+
+ if attribute == '':
+ raise SpecFormatStringError(
+ 'Format string attributes must be non-empty')
+ attribute = attribute.lower()
+
+ current = spec
+ sig = ''
+ if attribute[0] in '@%/':
+ # color sigils that are inside braces
+ sig = attribute[0]
+ attribute = attribute[1:]
+ elif attribute.startswith('arch='):
+ sig = ' arch=' # include space as separator
+ attribute = attribute[5:]
+
+ parts = attribute.split('.')
+ assert parts
+
+ # check that the sigil is valid for the attribute.
+ if sig == '@' and parts[-1] not in ('versions', 'version'):
+ raise SpecFormatSigilError(sig, 'versions', attribute)
+ elif sig == '%' and attribute not in ('compiler', 'compiler.name'):
+ raise SpecFormatSigilError(sig, 'compilers', attribute)
+ elif sig == '/' and not re.match(r'hash(:\d+)?$', attribute):
+ raise SpecFormatSigilError(sig, 'DAG hashes', attribute)
+ elif sig == ' arch=' and attribute not in ('architecture', 'arch'):
+ raise SpecFormatSigilError(sig, 'the architecture', attribute)
+
+ # find the morph function for our attribute
+ morph = transform.get(attribute, lambda s, x: x)
+
+ # Special cases for non-spec attributes and hashes.
+ # These must be the only non-dep component of the format attribute
+ if attribute == 'spack_root':
+ write(morph(spec, spack.paths.spack_root))
+ return
+ elif attribute == 'spack_install':
+ write(morph(spec, spack.store.layout.root))
+ return
+ elif re.match(r'hash(:\d)?', attribute):
+ col = '#'
+ if ':' in attribute:
+ _, length = attribute.split(':')
+ write(sig + morph(spec, spec.dag_hash(int(length))), col)
+ else:
+ write(sig + morph(spec, spec.dag_hash()), col)
+ return
+
+ # Iterate over components using getattr to get next element
+ for idx, part in enumerate(parts):
+ if not part:
+ raise SpecFormatStringError(
+ 'Format string attributes must be non-empty'
+ )
+ if part.startswith('_'):
+ raise SpecFormatStringError(
+ 'Attempted to format private attribute'
+ )
+ else:
+ if isinstance(current, VariantMap):
+ # subscript instead of getattr for variant names
+ current = current[part]
+ else:
+ # aliases
+ if part == 'arch':
+ part = 'architecture'
+ elif part == 'version':
+ # Version requires concrete spec, versions does not
+ # when concrete, they print the same thing
+ part = 'versions'
+ try:
+ current = getattr(current, part)
+ except AttributeError:
+ parent = '.'.join(parts[:idx])
+ m = 'Attempted to format attribute %s.' % attribute
+ m += 'Spec.%s has no attribute %s' % (parent, part)
+ raise SpecFormatStringError(m)
+ if isinstance(current, VersionList):
+ if current == _any_version:
+ # We don't print empty version lists
+ return
+
+ if callable(current):
+ raise SpecFormatStringError(
+ 'Attempted to format callable object'
+ )
+ if not current:
+ # We're not printing anything
+ return
+
+ # Set color codes for various attributes
+ col = None
+ if 'variants' in parts:
+ col = '+'
+ elif 'architecture' in parts:
+ col = '='
+ elif 'compiler' in parts or 'compiler_flags' in parts:
+ col = '%'
+ elif 'version' in parts:
+ col = '@'
+
+ # Finally, write the ouptut
+ write(sig + morph(spec, str(current)), col)
+
+ attribute = ''
+ in_attribute = False
+ escape = False
+
+ for c in format_string:
+ if escape:
+ out.write(c)
+ escape = False
+ elif c == '\\':
+ escape = True
+ elif in_attribute:
+ if c == '}':
+ write_attribute(self, attribute, color)
+ attribute = ''
+ in_attribute = False
+ else:
+ attribute += c
+ else:
+ if c == '}':
+ raise SpecFormatStringError(
+ 'Encountered closing } before opening {'
+ )
+ elif c == '{':
+ in_attribute = True
+ else:
+ out.write(c)
+ if in_attribute:
+ raise SpecFormatStringError(
+ 'Format string terminated while reading attribute.'
+ 'Missing terminating }.'
+ )
+ return out.getvalue()
+
+ def old_format(self, format_string='$_$@$%@+$+$=', **kwargs):
+ """
The format strings you can provide are::
$_ Package name
@@ -3085,6 +3332,7 @@ class Spec(object):
TODO: allow, e.g., ``$6#`` to customize short hash length
TODO: allow, e.g., ``$//`` for full hash.
"""
+
color = kwargs.get('color', False)
# Dictionary of transformations for named tokens
@@ -3218,7 +3466,7 @@ class Spec(object):
platform = str(self.architecture.platform)
write(fmt % transform(self, platform), '=')
elif named_str == "OS":
- operating_sys = str(self.architecture.platform_os)
+ operating_sys = str(self.architecture.os)
write(fmt % transform(self, operating_sys), '=')
elif named_str == "TARGET":
target = str(self.architecture.target)
@@ -3302,7 +3550,7 @@ class Spec(object):
status_fn = kwargs.pop('status_fn', False)
cover = kwargs.pop('cover', 'nodes')
indent = kwargs.pop('indent', 0)
- fmt = kwargs.pop('format', '$_$@$%@+$+$=')
+ fmt = kwargs.pop('format', default_format)
prefix = kwargs.pop('prefix', None)
show_types = kwargs.pop('show_types', False)
deptypes = kwargs.pop('deptypes', 'all')
@@ -3516,7 +3764,7 @@ class SpecParser(spack.parse.Parser):
for spec in specs:
for s in spec.traverse():
if s.architecture and not s.architecture.platform and \
- (s.architecture.platform_os or s.architecture.target):
+ (s.architecture.os or s.architecture.target):
s._set_architecture(platform=platform_default)
return specs
@@ -3877,7 +4125,9 @@ class UnsatisfiableDependencySpecError(UnsatisfiableSpecError):
class AmbiguousHashError(SpecError):
def __init__(self, msg, *specs):
- specs_str = '\n ' + '\n '.join(spec.format('$.$@$%@+$+$=$/')
+ spec_fmt = '{namespace}.{name}{@version}{%compiler}{compiler_flags}'
+ spec_fmt += '{variants}{arch=architecture}{/hash:7}'
+ specs_str = '\n ' + '\n '.join(spec.format(spec_fmt)
for spec in specs)
super(AmbiguousHashError, self).__init__(msg + specs_str)
@@ -3904,6 +4154,18 @@ class RedundantSpecError(SpecError):
% (addition, spec))
+class SpecFormatStringError(SpecError):
+ """Called for errors in Spec format strings."""
+
+
+class SpecFormatSigilError(SpecFormatStringError):
+ """Called for mismatched sigils and attributes in format strings"""
+ def __init__(self, sigil, requirement, used):
+ msg = 'The sigil %s may only be used for %s.' % (sigil, requirement)
+ msg += ' It was used with the attribute %s.' % used
+ super(SpecFormatSigilError, self).__init__(msg)
+
+
class ConflictsInSpecError(SpecError, RuntimeError):
def __init__(self, spec, matches):
message = 'Conflicts in concretized spec "{0}"\n'.format(
diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py
index 152f3a5909..d06fad6b37 100644
--- a/lib/spack/spack/test/architecture.py
+++ b/lib/spack/spack/test/architecture.py
@@ -1,3 +1,4 @@
+
# Copyright 2013-2019 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
@@ -21,7 +22,7 @@ from spack.platforms.darwin import Darwin
def test_dict_functions_for_architecture():
arch = spack.architecture.Arch()
arch.platform = spack.architecture.platform()
- arch.platform_os = arch.platform.operating_system('default_os')
+ arch.os = arch.platform.operating_system('default_os')
arch.target = arch.platform.target('default_target')
new_arch = spack.architecture.Arch.from_dict(arch.to_dict())
@@ -29,26 +30,26 @@ def test_dict_functions_for_architecture():
assert arch == new_arch
assert isinstance(arch, spack.architecture.Arch)
assert isinstance(arch.platform, spack.architecture.Platform)
- assert isinstance(arch.platform_os, spack.architecture.OperatingSystem)
+ assert isinstance(arch.os, spack.architecture.OperatingSystem)
assert isinstance(arch.target, spack.architecture.Target)
assert isinstance(new_arch, spack.architecture.Arch)
assert isinstance(new_arch.platform, spack.architecture.Platform)
- assert isinstance(new_arch.platform_os, spack.architecture.OperatingSystem)
+ assert isinstance(new_arch.os, spack.architecture.OperatingSystem)
assert isinstance(new_arch.target, spack.architecture.Target)
def test_platform():
- output_platform_class = spack.architecture.real_platform()
- if os.environ.get('CRAYPE_VERSION') is not None:
- my_platform_class = Cray()
- elif os.path.exists('/bgsys'):
- my_platform_class = Bgq()
- elif 'Linux' in py_platform.system():
- my_platform_class = Linux()
- elif 'Darwin' in py_platform.system():
- my_platform_class = Darwin()
+ output_platform_class = spack.architecture.real_platform()
+ if os.environ.get('CRAYPE_VERSION') is not None:
+ my_platform_class = Cray()
+ elif os.path.exists('/bgsys'):
+ my_platform_class = Bgq()
+ elif 'Linux' in py_platform.system():
+ my_platform_class = Linux()
+ elif 'Darwin' in py_platform.system():
+ my_platform_class = Darwin()
- assert str(output_platform_class) == str(my_platform_class)
+ assert str(output_platform_class) == str(my_platform_class)
def test_boolness():
@@ -67,7 +68,7 @@ def test_boolness():
assert arch
arch = spack.architecture.Arch()
- arch.platform_os = plat_os
+ arch.os = plat_os
assert arch
arch = spack.architecture.Arch()
@@ -86,7 +87,7 @@ def test_user_front_end_input(config):
frontend_spec = Spec('libelf os=frontend target=frontend')
frontend_spec.concretize()
- assert frontend_os == frontend_spec.architecture.platform_os
+ assert frontend_os == frontend_spec.architecture.os
assert frontend_target == frontend_spec.architecture.target
@@ -101,7 +102,7 @@ def test_user_back_end_input(config):
backend_spec = Spec("libelf os=backend target=backend")
backend_spec.concretize()
- assert backend_os == backend_spec.architecture.platform_os
+ assert backend_os == backend_spec.architecture.os
assert backend_target == backend_spec.architecture.target
@@ -113,7 +114,7 @@ def test_user_defaults(config):
default_spec = Spec("libelf") # default is no args
default_spec.concretize()
- assert default_os == default_spec.architecture.platform_os
+ assert default_os == default_spec.architecture.os
assert default_target == default_spec.architecture.target
@@ -133,7 +134,7 @@ def test_user_input_combination(config):
spec = Spec("libelf os=%s target=%s" % (o, t))
spec.concretize()
results.append(
- spec.architecture.platform_os == str(platform.operating_system(o))
+ spec.architecture.os == str(platform.operating_system(o))
)
results.append(
spec.architecture.target == str(platform.target(t))
diff --git a/lib/spack/spack/test/cmd/view.py b/lib/spack/spack/test/cmd/view.py
index ea4b0cc4f5..f7375d8903 100644
--- a/lib/spack/spack/test/cmd/view.py
+++ b/lib/spack/spack/test/cmd/view.py
@@ -45,7 +45,7 @@ def test_view_projections(
viewpath = str(tmpdir.mkdir('view_{0}'.format(cmd)))
view_projection = {
'projections': {
- 'all': '${PACKAGE}-${VERSION}'
+ 'all': '{name}-{version}'
}
}
projection_file = create_projection_file(tmpdir, view_projection)
@@ -65,8 +65,8 @@ def test_view_multiple_projections(
viewpath = str(tmpdir.mkdir('view'))
view_projection = s_yaml.syaml_dict(
- [('extendee', '${PACKAGE}-${COMPILERNAME}'),
- ('all', '${PACKAGE}-${VERSION}')]
+ [('extendee', '{name}-{compiler.name}'),
+ ('all', '{name}-{version}')]
)
projection_file = create_projection_file(tmpdir, view_projection)
@@ -87,8 +87,8 @@ def test_view_multiple_projections_all_first(
viewpath = str(tmpdir.mkdir('view'))
view_projection = s_yaml.syaml_dict(
- [('all', '${PACKAGE}-${VERSION}'),
- ('extendee', '${PACKAGE}-${COMPILERNAME}')]
+ [('all', '{name}-{version}'),
+ ('extendee', '{name}-{compiler.name}')]
)
projection_file = create_projection_file(tmpdir, view_projection)
@@ -145,7 +145,7 @@ def test_view_extension_projection(
install('extension2@1.0')
viewpath = str(tmpdir.mkdir('view'))
- view_projection = {'all': '${PACKAGE}-${VERSION}'}
+ view_projection = {'all': '{name}-{version}'}
projection_file = create_projection_file(tmpdir, view_projection)
view('symlink', viewpath, '--projection-file={0}'.format(projection_file),
'extension1@1.0')
diff --git a/lib/spack/spack/test/data/modules/lmod/alter_environment.yaml b/lib/spack/spack/test/data/modules/lmod/alter_environment.yaml
index a963af1ff8..caa01560f1 100644
--- a/lib/spack/spack/test/data/modules/lmod/alter_environment.yaml
+++ b/lib/spack/spack/test/data/modules/lmod/alter_environment.yaml
@@ -13,7 +13,7 @@ lmod:
- CMAKE_PREFIX_PATH
environment:
set:
- '${PACKAGE}_ROOT': '${PREFIX}'
+ '{name}_ROOT': '{prefix}'
'platform=test target=x86_64':
environment:
diff --git a/lib/spack/spack/test/data/modules/tcl/alter_environment.yaml b/lib/spack/spack/test/data/modules/tcl/alter_environment.yaml
index c9f00c6360..a55ad94b0e 100644
--- a/lib/spack/spack/test/data/modules/tcl/alter_environment.yaml
+++ b/lib/spack/spack/test/data/modules/tcl/alter_environment.yaml
@@ -7,7 +7,7 @@ tcl:
- CMAKE_PREFIX_PATH
environment:
set:
- '${PACKAGE}_ROOT': '${PREFIX}'
+ '{name}_ROOT': '{prefix}'
'platform=test target=x86_64':
environment:
diff --git a/lib/spack/spack/test/data/modules/tcl/conflicts.yaml b/lib/spack/spack/test/data/modules/tcl/conflicts.yaml
index 4d0eb8d526..66494b1ce1 100644
--- a/lib/spack/spack/test/data/modules/tcl/conflicts.yaml
+++ b/lib/spack/spack/test/data/modules/tcl/conflicts.yaml
@@ -1,8 +1,8 @@
enable:
- tcl
tcl:
- naming_scheme: '${PACKAGE}/${VERSION}-${COMPILERNAME}'
+ naming_scheme: '{name}/{version}-{compiler.name}'
all:
conflict:
- - '${PACKAGE}'
+ - '{name}'
- 'intel/14.0.1'
diff --git a/lib/spack/spack/test/data/modules/tcl/invalid_naming_scheme.yaml b/lib/spack/spack/test/data/modules/tcl/invalid_naming_scheme.yaml
index 2f72ba4aab..f523f0bbef 100644
--- a/lib/spack/spack/test/data/modules/tcl/invalid_naming_scheme.yaml
+++ b/lib/spack/spack/test/data/modules/tcl/invalid_naming_scheme.yaml
@@ -1,5 +1,5 @@
enable:
- tcl
tcl:
- # ${OPTIONS} is not allowed in the naming scheme, see #2884
- naming_scheme: '${PACKAGE}/${VERSION}-${COMPILERNAME}-${OPTIONS}'
+ # {variants} is not allowed in the naming scheme, see #2884
+ naming_scheme: '{name}/{version}-{compiler.name}-{variants}'
diff --git a/lib/spack/spack/test/data/modules/tcl/invalid_token_in_env_var_name.yaml b/lib/spack/spack/test/data/modules/tcl/invalid_token_in_env_var_name.yaml
index 297028531b..d536c994fa 100644
--- a/lib/spack/spack/test/data/modules/tcl/invalid_token_in_env_var_name.yaml
+++ b/lib/spack/spack/test/data/modules/tcl/invalid_token_in_env_var_name.yaml
@@ -7,12 +7,12 @@ tcl:
- CMAKE_PREFIX_PATH
environment:
set:
- '${PACKAGE}_ROOT_${PREFIX}': '${PREFIX}'
+ '{name}_ROOT_{prefix}': '{prefix}'
'platform=test target=x86_64':
environment:
set:
- FOO_${OPTIONS}: 'foo'
+ FOO_{variants}: 'foo'
unset:
- BAR
diff --git a/lib/spack/spack/test/data/modules/tcl/wrong_conflicts.yaml b/lib/spack/spack/test/data/modules/tcl/wrong_conflicts.yaml
index 0568605248..a4bd97257b 100644
--- a/lib/spack/spack/test/data/modules/tcl/wrong_conflicts.yaml
+++ b/lib/spack/spack/test/data/modules/tcl/wrong_conflicts.yaml
@@ -1,7 +1,7 @@
enable:
- tcl
tcl:
- naming_scheme: '${PACKAGE}/${VERSION}-${COMPILERNAME}'
+ naming_scheme: '{name}/{version}-{compiler.name}'
all:
conflict:
- - '${PACKAGE}/${COMPILERNAME}'
+ - '{name}/{compiler.name}'
diff --git a/lib/spack/spack/test/directory_layout.py b/lib/spack/spack/test/directory_layout.py
index 7e8cda611f..0b6b31bef0 100644
--- a/lib/spack/spack/test/directory_layout.py
+++ b/lib/spack/spack/test/directory_layout.py
@@ -41,9 +41,9 @@ def test_yaml_directory_layout_parameters(
layout_default = YamlDirectoryLayout(str(tmpdir))
path_default = layout_default.relative_path_for_spec(spec)
assert(path_default == spec.format(
- "${ARCHITECTURE}/"
- "${COMPILERNAME}-${COMPILERVER}/"
- "${PACKAGE}-${VERSION}-${HASH}"))
+ "{architecture}/"
+ "{compiler.name}-{compiler.version}/"
+ "{name}-{version}-{hash}"))
# Test hash_length parameter works correctly
layout_10 = YamlDirectoryLayout(str(tmpdir), hash_len=10)
@@ -56,7 +56,7 @@ def test_yaml_directory_layout_parameters(
# Test path_scheme
arch, compiler, package7 = path_7.split('/')
- scheme_package7 = "${PACKAGE}-${VERSION}-${HASH:7}"
+ scheme_package7 = "{name}-{version}-{hash:7}"
layout_package7 = YamlDirectoryLayout(str(tmpdir),
path_scheme=scheme_package7)
path_package7 = layout_package7.relative_path_for_spec(spec)
@@ -64,7 +64,7 @@ def test_yaml_directory_layout_parameters(
assert(package7 == path_package7)
# Test separation of architecture
- arch_scheme_package = "${PLATFORM}/${TARGET}/${OS}/${PACKAGE}/${VERSION}/${HASH:7}" # NOQA: ignore=E501
+ arch_scheme_package = "{architecture.platform}/{architecture.target}/{architecture.os}/{name}/{version}/{hash:7}" # NOQA: ignore=E501
layout_arch_package = YamlDirectoryLayout(str(tmpdir),
path_scheme=arch_scheme_package)
arch_path_package = layout_arch_package.relative_path_for_spec(spec)
diff --git a/lib/spack/spack/test/graph.py b/lib/spack/spack/test/graph.py
index c0731a7257..a29779e3ca 100644
--- a/lib/spack/spack/test/graph.py
+++ b/lib/spack/spack/test/graph.py
@@ -65,16 +65,16 @@ def test_dynamic_dot_graph_mpileaks(mock_packages):
dot = stream.getvalue()
- mpileaks_hash, mpileaks_lbl = s.dag_hash(), s.format('$_$/')
- mpi_hash, mpi_lbl = s['mpi'].dag_hash(), s['mpi'].format('$_$/')
+ mpileaks_hash, mpileaks_lbl = s.dag_hash(), s.format('{name}{/hash:7}')
+ mpi_hash, mpi_lbl = s['mpi'].dag_hash(), s['mpi'].format('{name}{/hash:7}')
callpath_hash, callpath_lbl = (
- s['callpath'].dag_hash(), s['callpath'].format('$_$/'))
+ s['callpath'].dag_hash(), s['callpath'].format('{name}{/hash:7}'))
dyninst_hash, dyninst_lbl = (
- s['dyninst'].dag_hash(), s['dyninst'].format('$_$/'))
+ s['dyninst'].dag_hash(), s['dyninst'].format('{name}{/hash:7}'))
libdwarf_hash, libdwarf_lbl = (
- s['libdwarf'].dag_hash(), s['libdwarf'].format('$_$/'))
+ s['libdwarf'].dag_hash(), s['libdwarf'].format('{name}{/hash:7}'))
libelf_hash, libelf_lbl = (
- s['libelf'].dag_hash(), s['libelf'].format('$_$/'))
+ s['libelf'].dag_hash(), s['libelf'].format('{name}{/hash:7}'))
assert ' "%s" [label="%s"]\n' % (mpileaks_hash, mpileaks_lbl) in dot
assert ' "%s" [label="%s"]\n' % (callpath_hash, callpath_lbl) in dot
diff --git a/lib/spack/spack/test/modules/tcl.py b/lib/spack/spack/test/modules/tcl.py
index 852f553f9f..f240fbec35 100644
--- a/lib/spack/spack/test/modules/tcl.py
+++ b/lib/spack/spack/test/modules/tcl.py
@@ -151,7 +151,7 @@ class TestTcl(object):
# Test we read the expected configuration for the naming scheme
writer, _ = factory('mpileaks')
- expected = '${PACKAGE}/${VERSION}-${COMPILERNAME}'
+ expected = '{name}/{version}-{compiler.name}'
assert writer.conf.naming_scheme == expected
diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py
index bec16fc7ad..f65cc44ff5 100644
--- a/lib/spack/spack/test/spec_semantics.py
+++ b/lib/spack/spack/test/spec_semantics.py
@@ -8,6 +8,7 @@ import pytest
from spack.spec import Spec, UnsatisfiableSpecError, SpecError
from spack.spec import substitute_abstract_variants, parse_anonymous_spec
+from spack.spec import SpecFormatSigilError, SpecFormatStringError
from spack.variant import InvalidVariantValueError
from spack.variant import MultipleValuesInExclusiveVariantError
@@ -736,28 +737,133 @@ class TestSpecSematics(object):
Spec('libelf foo')
def test_spec_formatting(self):
+ spec = Spec("multivalue_variant cflags=-O2")
+ spec.concretize()
+
+ # Since the default is the full spec see if the string rep of
+ # spec is the same as the output of spec.format()
+ # ignoring whitespace (though should we?) and ignoring dependencies
+ spec_string = str(spec)
+ idx = spec_string.index(' ^')
+ assert spec_string[:idx] == spec.format().strip()
+
+ # Testing named strings ie {string} and whether we get
+ # the correct component
+ # Mixed case intentional to test both
+ package_segments = [("{NAME}", "name"),
+ ("{VERSION}", "versions"),
+ ("{compiler}", "compiler"),
+ ("{compiler_flags}", "compiler_flags"),
+ ("{variants}", "variants"),
+ ("{architecture}", "architecture")]
+
+ sigil_package_segments = [("{@VERSIONS}", '@' + str(spec.version)),
+ ("{%compiler}", '%' + str(spec.compiler)),
+ ("{arch=architecture}",
+ ' arch=' + str(spec.architecture))]
+
+ compiler_segments = [("{compiler.name}", "name"),
+ ("{compiler.version}", "versions")]
+
+ sigil_compiler_segments = [("{%compiler.name}",
+ '%' + spec.compiler.name),
+ ("{@compiler.version}",
+ '@' + str(spec.compiler.version))]
+
+ architecture_segments = [("{architecture.platform}", "platform"),
+ ("{architecture.os}", "os"),
+ ("{architecture.target}", "target")]
+
+ other_segments = [('{spack_root}', spack.paths.spack_root),
+ ('{spack_install}', spack.store.layout.root),
+ ('{hash:7}', spec.dag_hash(7)),
+ ('{/hash}', '/' + spec.dag_hash())]
+
+ for named_str, prop in package_segments:
+ expected = getattr(spec, prop, "")
+ actual = spec.format(named_str)
+ assert str(expected) == actual
+
+ for named_str, expected in sigil_package_segments:
+ actual = spec.format(named_str)
+ assert expected == actual
+
+ compiler = spec.compiler
+ for named_str, prop in compiler_segments:
+ expected = getattr(compiler, prop, "")
+ actual = spec.format(named_str)
+ assert str(expected) == actual
+
+ for named_str, expected in sigil_compiler_segments:
+ actual = spec.format(named_str)
+ assert expected == actual
+
+ arch = spec.architecture
+ for named_str, prop in architecture_segments:
+ expected = getattr(arch, prop, "")
+ actual = spec.format(named_str)
+ assert str(expected) == actual
+
+ for named_str, expected in other_segments:
+ actual = spec.format(named_str)
+ assert expected == actual
+
+ def test_spec_formatting_escapes(self):
+ spec = Spec('multivalue_variant cflags=-O2')
+ spec.concretize()
+
+ sigil_mismatches = [
+ '{@name}',
+ '{@version.concrete}',
+ '{%compiler.version}',
+ '{/hashd}',
+ '{arch=architecture.os}'
+ ]
+
+ for fmt_str in sigil_mismatches:
+ with pytest.raises(SpecFormatSigilError):
+ spec.format(fmt_str)
+
+ bad_formats = [
+ '{}',
+ 'name}',
+ '\{name}', # NOQA: ignore=W605
+ '{name',
+ '{name\}', # NOQA: ignore=W605
+ '{_concrete}',
+ '{dag_hash}',
+ '{foo}',
+ '{+variants.debug}'
+ ]
+
+ for fmt_str in bad_formats:
+ with pytest.raises(SpecFormatStringError):
+ spec.format(fmt_str)
+
+ def test_spec_deprecated_formatting(self):
spec = Spec("libelf cflags=-O2")
spec.concretize()
# Since the default is the full spec see if the string rep of
# spec is the same as the output of spec.format()
# ignoring whitespace (though should we?)
- assert str(spec) == spec.format().strip()
+ assert str(spec) == spec.format('$_$@$%@+$+$=').strip()
- # Testing named strings ie ${STRING} and whether we get
+ # Testing named strings ie {string} and whether we get
# the correct component
+ # Mixed case intentional for testing both
package_segments = [("${PACKAGE}", "name"),
("${VERSION}", "versions"),
- ("${COMPILER}", "compiler"),
- ("${COMPILERFLAGS}", "compiler_flags"),
- ("${OPTIONS}", "variants"),
- ("${ARCHITECTURE}", "architecture")]
+ ("${compiler}", "compiler"),
+ ("${compilerflags}", "compiler_flags"),
+ ("${options}", "variants"),
+ ("${architecture}", "architecture")]
- compiler_segments = [("${COMPILERNAME}", "name"),
- ("${COMPILERVER}", "versions")]
+ compiler_segments = [("${compilername}", "name"),
+ ("${compilerver}", "versions")]
architecture_segments = [("${PLATFORM}", "platform"),
- ("${OS}", "platform_os"),
+ ("${OS}", "os"),
("${TARGET}", "target")]
for named_str, prop in package_segments:
diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py
index e4797b5c1d..8ad987fbd6 100644
--- a/lib/spack/spack/test/spec_syntax.py
+++ b/lib/spack/spack/test/spec_syntax.py
@@ -203,8 +203,8 @@ class TestSpecSyntax(object):
"x ^y~f+e~d+c~b+a@4,2:3,1%intel@4,3,2,1")
self.check_parse(
- "x arch=test-redhat6-None "
- " ^y arch=test-None-x86_64 "
+ "x arch=test-redhat6-None"
+ " ^y arch=test-None-x86_64"
" ^z arch=linux-None-None",
"x os=fe "
@@ -212,11 +212,11 @@ class TestSpecSyntax(object):
"^z platform=linux")
self.check_parse(
- "x arch=test-debian6-x86_64 "
+ "x arch=test-debian6-x86_64"
" ^y arch=test-debian6-x86_64",
- "x os=default_os target=default_target "
- "^y os=default_os target=default_target")
+ "x os=default_os target=default_target"
+ " ^y os=default_os target=default_target")
self.check_parse("x ^y", "x@: ^y@:")