modules : more sensible name to blacklist environment variables

modules : added skeleton to permit modifications based on specs
This commit is contained in:
alalazo 2016-04-06 13:42:47 +02:00
parent 670cb423f9
commit d636b4fdde
3 changed files with 68 additions and 56 deletions

View file

@ -250,7 +250,7 @@
'type': 'string', 'type': 'string',
'enum': ['None', 'Direct', 'All'] 'enum': ['None', 'Direct', 'All']
}, },
'module_type_configuration': { 'module_file_configuration': {
'type': 'object', 'type': 'object',
'default': {}, 'default': {},
'additionalProperties': False, 'additionalProperties': False,
@ -260,7 +260,7 @@
'default': {}, 'default': {},
'additionalProperties': False, 'additionalProperties': False,
'properties': { 'properties': {
'environment_modifications': { 'environment_blacklist': {
'type': 'array', 'type': 'array',
'default': [], 'default': [],
'items': { 'items': {
@ -270,7 +270,21 @@
} }
}, },
'autoload': {'$ref': '#/definitions/dependency_selection'}, 'autoload': {'$ref': '#/definitions/dependency_selection'},
'prerequisites': {'$ref': '#/definitions/dependency_selection'} 'prerequisites': {'$ref': '#/definitions/dependency_selection'},
'environment': {
'type': 'object',
'default': {}
}
}
},
'module_type_configuration': {
'type': 'object',
'default': {},
'properties': {
'all': {'$ref': '#/definitions/module_file_configuration'}
},
'patternProperties': {
r'\w[\w-]*': {'$ref': '#/definitions/module_file_configuration'}
} }
} }
}, },

View file

@ -252,7 +252,7 @@ def validate(env, errstream):
set_or_unset_not_first(variable, list_of_changes, errstream) set_or_unset_not_first(variable, list_of_changes, errstream)
def filter_environment_modifications(env, variables): def filter_environment_blacklist(env, variables):
""" """
Generator that filters out any change to environment variables present in the input list Generator that filters out any change to environment variables present in the input list

View file

@ -49,6 +49,7 @@
import llnl.util.tty as tty import llnl.util.tty as tty
import spack import spack
import spack.config import spack.config
from llnl.util.filesystem import join_path, mkdirp from llnl.util.filesystem import join_path, mkdirp
from spack.build_environment import parent_class_modules, set_module_variables_for_package from spack.build_environment import parent_class_modules, set_module_variables_for_package
from spack.environment import * from spack.environment import *
@ -137,7 +138,6 @@ def __init__(self, spec=None):
if self.spec.package.__doc__: if self.spec.package.__doc__:
self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__) self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__)
@property @property
def category(self): def category(self):
# Anything defined at the package level takes precedence # Anything defined at the package level takes precedence
@ -150,11 +150,33 @@ def category(self):
return 'spack installed package' return 'spack installed package'
def write(self): def write(self):
"""Write out a module file for this object.""" """
Writes out a module file for this object.
This method employs a template pattern and expects derived classes to:
- override the header property
- provide formats for autoload, prerequisites and environment changes
"""
module_dir = os.path.dirname(self.file_name) module_dir = os.path.dirname(self.file_name)
if not os.path.exists(module_dir): if not os.path.exists(module_dir):
mkdirp(module_dir) mkdirp(module_dir)
def dependencies(request='All'):
if request == 'None':
return []
l = [xx for xx in sorted(self.spec.traverse(order='post', depth=True, cover='nodes', root=False), reverse=True)]
if request == 'Direct':
return [xx for ii, xx in l if ii == 1]
# FIXME : during module file creation nodes seem to be visited multiple times even if cover='nodes'
# FIXME : is given. This work around permits to get a unique list of spec anyhow.
# FIXME : Possibly we miss a merge step among nodes that refer to the same package.
seen = set()
seen_add = seen.add
return [xx for ii, xx in l if not (xx in seen or seen_add(xx))]
# Environment modifications guessed by inspecting the # Environment modifications guessed by inspecting the
# installation prefix # installation prefix
env = inspect_path(self.spec.prefix) env = inspect_path(self.spec.prefix)
@ -162,23 +184,6 @@ def write(self):
# Let the extendee/dependency modify their extensions/dependencies before asking for # Let the extendee/dependency modify their extensions/dependencies before asking for
# package-specific modifications # package-specific modifications
spack_env = EnvironmentModifications() spack_env = EnvironmentModifications()
def dependencies(request='All'):
if request == 'None':
return []
l = [x for x in sorted(self.spec.traverse(order='post', depth=True, cover='nodes', root=False), reverse=True)]
if request == 'Direct':
return [x for ii, x in l if ii == 1]
# FIXME : during module file creation nodes seem to be visited multiple times even if cover='nodes'
# FIXME : is given. This work around permits to get a unique list of spec anyhow.
# FIXME : Possibly we miss a merge step among nodes that refer to the same package.
seen = set()
seen_add = seen.add
return [x for ii, x in l if not (x in seen or seen_add(x))]
# TODO : the code down below is quite similar to build_environment.setup_package and needs to be # TODO : the code down below is quite similar to build_environment.setup_package and needs to be
# TODO : factored out to a single place # TODO : factored out to a single place
for item in dependencies('All'): for item in dependencies('All'):
@ -207,43 +212,43 @@ def dependencies(request='All'):
# Filter modifications to environment variables # Filter modifications to environment variables
try: try:
filter_list = CONFIGURATION[self.name]['filter']['environment_modifications'] filter_list = CONFIGURATION[self.name]['filter']['environment_blacklist']
except KeyError: except KeyError:
filter_list = [] filter_list = []
with open(self.file_name, 'w') as f: # Build up the module file content
# Header module_file_content = self.header
f.write(self.header)
# Automatic loads
for x in autoload_list: for x in autoload_list:
f.write(self.autoload(x)) module_file_content += self.autoload(x)
# Prerequisites
for x in prerequisites_list: for x in prerequisites_list:
f.write(self.prerequisite(x)) module_file_content += self.prerequisite(x)
# Modifications to the environment for line in self.process_environment_command(filter_environment_blacklist(env, filter_list)):
iterable = self.process_environment_command(filter_environment_modifications(env, filter_list)) module_file_content += line
for line in iterable:
f.write(line) # Dump to file
with open(self.file_name, 'w') as f:
f.write(module_file_content)
@property @property
def header(self): def header(self):
raise NotImplementedError() raise NotImplementedError()
def autoload(self, spec): def autoload(self, spec):
raise NotImplementedError() m = TclModule(spec)
return self.autoload_format.format(module_file=m.use_name)
def prerequisite(self, spec): def prerequisite(self, spec):
raise NotImplementedError() m = TclModule(spec)
return self.prerequisite_format.format(module_file=m.use_name)
def process_environment_command(self, env): def process_environment_command(self, env):
for command in env: for command in env:
try: try:
yield self.formats[type(command)].format(**command.args) yield self.environment_modifications_formats[type(command)].format(**command.args)
except KeyError: except KeyError:
tty.warn('Cannot handle command of type {command} : skipping request'.format(command=type(command))) tty.warn('Cannot handle command of type {command} : skipping request'.format(command=type(command)))
tty.warn('{context} at {filename}:{lineno}'.format(**command.args)) tty.warn('{context} at {filename}:{lineno}'.format(**command.args))
@property @property
def file_name(self): def file_name(self):
"""Subclasses should implement this to return the name of the file """Subclasses should implement this to return the name of the file
@ -266,7 +271,7 @@ class Dotkit(EnvModule):
name = 'dotkit' name = 'dotkit'
path = join_path(spack.share_path, "dotkit") path = join_path(spack.share_path, "dotkit")
formats = { environment_modifications_formats = {
PrependPath: 'dk_alter {name} {value}\n', PrependPath: 'dk_alter {name} {value}\n',
SetEnv: 'dk_setenv {name} {value}\n' SetEnv: 'dk_setenv {name} {value}\n'
} }
@ -304,7 +309,7 @@ class TclModule(EnvModule):
name = 'tcl' name = 'tcl'
path = join_path(spack.share_path, "modules") path = join_path(spack.share_path, "modules")
formats = { environment_modifications_formats = {
PrependPath: 'prepend-path {name} \"{value}\"\n', PrependPath: 'prepend-path {name} \"{value}\"\n',
AppendPath: 'append-path {name} \"{value}\"\n', AppendPath: 'append-path {name} \"{value}\"\n',
RemovePath: 'remove-path {name} \"{value}\"\n', RemovePath: 'remove-path {name} \"{value}\"\n',
@ -312,6 +317,13 @@ class TclModule(EnvModule):
UnsetEnv: 'unsetenv {name}\n' UnsetEnv: 'unsetenv {name}\n'
} }
autoload_format = ('if ![ is-loaded {module_file} ] {{'
' puts stderr "Autoloading {module_file}"'
' module load {module_file}'
'}}')
prerequisite_format = 'prereq {module_file}\n'
@property @property
def file_name(self): def file_name(self):
return join_path(TclModule.path, self.spec.architecture, self.use_name) return join_path(TclModule.path, self.spec.architecture, self.use_name)
@ -339,17 +351,3 @@ def header(self):
header += 'puts stderr "%s"\n' % line header += 'puts stderr "%s"\n' % line
header += '}\n\n' header += '}\n\n'
return header return header
def autoload(self, spec):
autoload_format = '''
if ![ is-loaded {module_file} ] {{
puts stderr "Autoloading {module_file}"
module load {module_file}
}}
'''''
m = TclModule(spec)
return autoload_format.format(module_file=m.use_name)
def prerequisite(self, spec):
m = TclModule(spec)
return 'prereq {module_file}\n'.format(module_file=m.use_name)