Rework compiler configuration and simplify config.py logic.
- `spack compiler` subcommands now take an optional --scope argument. - no more `remove_from_config` in `config.py` -- `update` just overwrites b/c it's easier to just call `get_config`, modify YAML structures directly, and then call `update`. - Implemented `spack compiler remove`.
This commit is contained in:
parent
ff0d871612
commit
1f8ba53ca7
@ -22,6 +22,7 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
@ -41,17 +42,26 @@ def setup_parser(subparser):
|
||||
sp = subparser.add_subparsers(
|
||||
metavar='SUBCOMMAND', dest='compiler_command')
|
||||
|
||||
update_parser = sp.add_parser(
|
||||
'add', help='Add compilers to the Spack configuration.')
|
||||
update_parser.add_argument('add_paths', nargs=argparse.REMAINDER)
|
||||
add_parser = sp.add_parser('add', help='Add compilers to the Spack configuration.')
|
||||
add_parser.add_argument('add_paths', nargs=argparse.REMAINDER)
|
||||
add_parser.add_argument('--scope', choices=spack.config.config_scopes,
|
||||
help="Configuration scope to modify.")
|
||||
|
||||
remove_parser = sp.add_parser('remove', help='remove compiler')
|
||||
remove_parser.add_argument('path')
|
||||
remove_parser = sp.add_parser('remove', help='Remove compiler by spec.')
|
||||
remove_parser.add_argument(
|
||||
'-a', '--all', action='store_true', help='Remove ALL compilers that match spec.')
|
||||
remove_parser.add_argument('compiler_spec')
|
||||
remove_parser.add_argument('--scope', choices=spack.config.config_scopes,
|
||||
help="Configuration scope to modify.")
|
||||
|
||||
list_parser = sp.add_parser('list', help='list available compilers')
|
||||
list_parser.add_argument('--scope', choices=spack.config.config_scopes,
|
||||
help="Configuration scope to read from.")
|
||||
|
||||
info_parser = sp.add_parser('info', help='Show compiler paths.')
|
||||
info_parser.add_argument('compiler_spec')
|
||||
info_parser.add_argument('--scope', choices=spack.config.config_scopes,
|
||||
help="Configuration scope to read from.")
|
||||
|
||||
|
||||
def compiler_add(args):
|
||||
@ -62,13 +72,13 @@ def compiler_add(args):
|
||||
paths = get_path('PATH')
|
||||
|
||||
compilers = [c for c in spack.compilers.find_compilers(*args.add_paths)
|
||||
if c.spec not in spack.compilers.all_compilers()]
|
||||
if c.spec not in spack.compilers.all_compilers(scope=args.scope)]
|
||||
|
||||
if compilers:
|
||||
spack.compilers.add_compilers_to_config('user', compilers)
|
||||
spack.compilers.add_compilers_to_config(compilers, scope=args.scope)
|
||||
n = len(compilers)
|
||||
s = 's' if n > 1 else ''
|
||||
filename = spack.config.get_config_filename('user', 'compilers')
|
||||
filename = spack.config.get_config_filename(args.scope, 'compilers')
|
||||
tty.msg("Added %d new compiler%s to %s" % (n, s, filename))
|
||||
colify(reversed(sorted(c.spec for c in compilers)), indent=4)
|
||||
else:
|
||||
@ -76,13 +86,26 @@ def compiler_add(args):
|
||||
|
||||
|
||||
def compiler_remove(args):
|
||||
pass
|
||||
cspec = CompilerSpec(args.compiler_spec)
|
||||
compilers = spack.compilers.compilers_for_spec(cspec, scope=args.scope)
|
||||
|
||||
if not compilers:
|
||||
tty.die("No compilers match spec %s." % cspec)
|
||||
elif not args.all and len(compilers) > 1:
|
||||
tty.error("Multiple compilers match spec %s. Choose one:" % cspec)
|
||||
colify(reversed(sorted([c.spec for c in compilers])), indent=4)
|
||||
tty.msg("Or, you can use `spack compiler remove -a` to remove all of them.")
|
||||
sys.exit(1)
|
||||
|
||||
for compiler in compilers:
|
||||
spack.compilers.remove_compiler_from_config(compiler.spec, scope=args.scope)
|
||||
tty.msg("Removed compiler %s." % compiler.spec)
|
||||
|
||||
|
||||
def compiler_info(args):
|
||||
"""Print info about all compilers matching a spec."""
|
||||
cspec = CompilerSpec(args.compiler_spec)
|
||||
compilers = spack.compilers.compilers_for_spec(cspec)
|
||||
compilers = spack.compilers.compilers_for_spec(cspec, scope=args.scope)
|
||||
|
||||
if not compilers:
|
||||
tty.error("No compilers match spec %s." % cspec)
|
||||
@ -97,7 +120,7 @@ def compiler_info(args):
|
||||
|
||||
def compiler_list(args):
|
||||
tty.msg("Available compilers")
|
||||
index = index_by(spack.compilers.all_compilers(), 'name')
|
||||
index = index_by(spack.compilers.all_compilers(scope=args.scope), 'name')
|
||||
for i, (name, compilers) in enumerate(index.items()):
|
||||
if i >= 1: print
|
||||
|
||||
|
@ -26,9 +26,14 @@
|
||||
from llnl.util.tty.colify import colify
|
||||
from llnl.util.lang import index_by
|
||||
|
||||
import spack
|
||||
from spack.cmd.compiler import compiler_list
|
||||
|
||||
description = "List available compilers. Same as 'spack compiler list'."
|
||||
|
||||
def setup_parser(subparser):
|
||||
subparser.add_argument('--scope', choices=spack.config.config_scopes,
|
||||
help="Configuration scope to read/modify.")
|
||||
|
||||
def compilers(parser, args):
|
||||
compiler_list(args)
|
||||
|
@ -49,10 +49,10 @@
|
||||
_default_order = ['gcc', 'intel', 'pgi', 'clang', 'xlc']
|
||||
|
||||
def _auto_compiler_spec(function):
|
||||
def converter(cspec_like):
|
||||
def converter(cspec_like, *args, **kwargs):
|
||||
if not isinstance(cspec_like, spack.spec.CompilerSpec):
|
||||
cspec_like = spack.spec.CompilerSpec(cspec_like)
|
||||
return function(cspec_like)
|
||||
return function(cspec_like, *args, **kwargs)
|
||||
return converter
|
||||
|
||||
|
||||
@ -65,39 +65,87 @@ def _to_dict(compiler):
|
||||
}
|
||||
|
||||
|
||||
def get_compiler_config(arch=None):
|
||||
def get_compiler_config(arch=None, scope=None):
|
||||
"""Return the compiler configuration for the specified architecture.
|
||||
|
||||
If the compiler configuration designates some compilers for
|
||||
'all' architectures, those are merged into the result, as well.
|
||||
|
||||
"""
|
||||
# If any configuration file has compilers, just stick with the
|
||||
# ones already configured.
|
||||
config = spack.config.get_config('compilers')
|
||||
config = spack.config.get_config('compilers', scope=scope)
|
||||
|
||||
my_arch = spack.architecture.sys_type()
|
||||
if arch is None:
|
||||
arch = spack.architecture.sys_type()
|
||||
arch = my_arch
|
||||
|
||||
if arch not in config:
|
||||
if arch in config:
|
||||
return config[arch]
|
||||
|
||||
# Only for the current arch in *highest* scope: automatically try to
|
||||
# find compilers if none are configured yet.
|
||||
if arch == my_arch and scope == 'user':
|
||||
config[arch] = {}
|
||||
compilers = find_compilers(*get_path('PATH'))
|
||||
for compiler in compilers:
|
||||
config[arch].update(_to_dict(compiler))
|
||||
spack.config.update_config('compilers', config)
|
||||
spack.config.update_config('compilers', config, scope=scope)
|
||||
return config[arch]
|
||||
|
||||
# Merge 'all' compilers with arch-specific ones.
|
||||
merged_config = config.get('all', {})
|
||||
merged_config = spack.config._merge_yaml(merged_config, config[arch])
|
||||
|
||||
return merged_config
|
||||
return {}
|
||||
|
||||
|
||||
def all_compilers(arch=None):
|
||||
def add_compilers_to_config(compilers, arch=None, scope=None):
|
||||
"""Add compilers to the config for the specified architecture.
|
||||
|
||||
Arguments:
|
||||
- compilers: a list of Compiler objects.
|
||||
- arch: arch to add compilers for.
|
||||
- scope: configuration scope to modify.
|
||||
"""
|
||||
if arch is None:
|
||||
arch = spack.architecture.sys_type()
|
||||
|
||||
compiler_config = get_compiler_config(arch, scope)
|
||||
for compiler in compilers:
|
||||
compiler_config[str(compiler.spec)] = dict(
|
||||
(c, getattr(compiler, c, "None"))
|
||||
for c in _required_instance_vars)
|
||||
|
||||
update = { arch : compiler_config }
|
||||
spack.config.update_config('compilers', update, scope)
|
||||
|
||||
|
||||
@_auto_compiler_spec
|
||||
def remove_compiler_from_config(compiler_spec, arch=None, scope=None):
|
||||
"""Remove compilers from the config, by spec.
|
||||
|
||||
Arguments:
|
||||
- compiler_specs: a list of CompilerSpec objects.
|
||||
- arch: arch to add compilers for.
|
||||
- scope: configuration scope to modify.
|
||||
"""
|
||||
if arch is None:
|
||||
arch = spack.architecture.sys_type()
|
||||
|
||||
compiler_config = get_compiler_config(arch, scope)
|
||||
del compiler_config[str(compiler_spec)]
|
||||
update = { arch : compiler_config }
|
||||
|
||||
spack.config.update_config('compilers', update, scope)
|
||||
|
||||
|
||||
def all_compilers(arch=None, scope=None):
|
||||
"""Return a set of specs for all the compiler versions currently
|
||||
available to build with. These are instances of CompilerSpec.
|
||||
"""
|
||||
return [spack.spec.CompilerSpec(s) for s in get_compiler_config(arch)]
|
||||
# Get compilers for this architecture.
|
||||
arch_config = get_compiler_config(arch, scope)
|
||||
|
||||
# Merge 'all' compilers with arch-specific ones.
|
||||
# Arch-specific compilers have higher precedence.
|
||||
merged_config = get_compiler_config('all', scope=scope)
|
||||
merged_config = spack.config._merge_yaml(merged_config, arch_config)
|
||||
|
||||
# Return compiler specs for the result.
|
||||
return [spack.spec.CompilerSpec(s) for s in merged_config]
|
||||
|
||||
|
||||
_cached_default_compiler = None
|
||||
@ -165,18 +213,18 @@ def supported(compiler_spec):
|
||||
|
||||
|
||||
@_auto_compiler_spec
|
||||
def find(compiler_spec):
|
||||
def find(compiler_spec, arch=None, scope=None):
|
||||
"""Return specs of available compilers that match the supplied
|
||||
compiler spec. Return an list if nothing found."""
|
||||
return [c for c in all_compilers() if c.satisfies(compiler_spec)]
|
||||
return [c for c in all_compilers(arch, scope) if c.satisfies(compiler_spec)]
|
||||
|
||||
|
||||
@_auto_compiler_spec
|
||||
def compilers_for_spec(compiler_spec):
|
||||
def compilers_for_spec(compiler_spec, arch=None, scope=None):
|
||||
"""This gets all compilers that satisfy the supplied CompilerSpec.
|
||||
Returns an empty list if none are found.
|
||||
"""
|
||||
config = get_compiler_config()
|
||||
config = get_compiler_config(arch, scope)
|
||||
|
||||
def get_compiler(cspec):
|
||||
items = config[str(cspec)]
|
||||
@ -195,7 +243,7 @@ def get_compiler(cspec):
|
||||
|
||||
return cls(cspec, *compiler_paths)
|
||||
|
||||
matches = find(compiler_spec)
|
||||
matches = find(compiler_spec, arch, scope)
|
||||
return [get_compiler(cspec) for cspec in matches]
|
||||
|
||||
|
||||
|
@ -311,7 +311,7 @@ def substitute_spack_prefix(path):
|
||||
return path.replace('$spack', spack.prefix)
|
||||
|
||||
|
||||
def get_config(section):
|
||||
def get_config(section, scope=None):
|
||||
"""Get configuration settings for a section.
|
||||
|
||||
Strips off the top-level section name from the YAML dict.
|
||||
@ -319,7 +319,12 @@ def get_config(section):
|
||||
validate_section(section)
|
||||
merged_section = {}
|
||||
|
||||
for scope in config_scopes.values():
|
||||
if scope is None:
|
||||
scopes = config_scopes.values()
|
||||
else:
|
||||
scopes = [validate_scope(scope)]
|
||||
|
||||
for scope in scopes:
|
||||
# read potentially cached data from the scope.
|
||||
data = scope.get_section(section)
|
||||
if not data or not section in data:
|
||||
@ -362,11 +367,11 @@ def get_config_filename(scope, section):
|
||||
def update_config(section, update_data, scope=None):
|
||||
"""Update the configuration file for a particular scope.
|
||||
|
||||
Merges contents of update_data into the scope's data for the
|
||||
specified section, then writes out the config file.
|
||||
Overwrites contents of a section in a scope with update_data,
|
||||
then writes out the config file.
|
||||
|
||||
update_data shoudl contain only the section's data, with the
|
||||
top-level name stripped off. This can be a list, dict, or any
|
||||
update_data should have the top-level section name stripped off
|
||||
(it will be re-added). Data itself can be a list, dict, or any
|
||||
other yaml-ish structure.
|
||||
|
||||
"""
|
||||
@ -377,37 +382,7 @@ def update_config(section, update_data, scope=None):
|
||||
scope = validate_scope(scope) # get ConfigScope object from string.
|
||||
|
||||
# read only the requested section's data.
|
||||
data = scope.get_section(section)
|
||||
data = _merge_yaml(data, { section : update_data })
|
||||
scope.write_section(section)
|
||||
|
||||
|
||||
def remove_from_config(section, key_to_rm, scope=None):
|
||||
"""Remove a configuration key and write updated configuration to disk.
|
||||
|
||||
Return True if something was removed, False otherwise.
|
||||
|
||||
"""
|
||||
# ensure configs are current by reading in.
|
||||
get_config(section)
|
||||
|
||||
# check args and get the objects we need.
|
||||
scope = validate_scope(scope)
|
||||
data = scope.get_section(section)
|
||||
filename = scope.get_section_filename(section)
|
||||
|
||||
# do some checks
|
||||
if not data:
|
||||
return False
|
||||
|
||||
if not section in data:
|
||||
raise ConfigFileError("Invalid configuration file: '%s'" % filename)
|
||||
|
||||
if key_to_rm not in section[section]:
|
||||
return False
|
||||
|
||||
# remove the key from the section's configuration
|
||||
del data[section][key_to_rm]
|
||||
scope.sections[section] = { section : update_data }
|
||||
scope.write_section(section)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user