From d636b4fdde5b9a37dff9a354368d36fa6969cec9 Mon Sep 17 00:00:00 2001
From: alalazo <massimiliano.culpo@googlemail.com>
Date: Wed, 6 Apr 2016 13:42:47 +0200
Subject: [PATCH] modules : more sensible name to blacklist environment
 variables modules : added skeleton to permit modifications based on specs

---
 lib/spack/spack/config.py      | 20 ++++++--
 lib/spack/spack/environment.py |  2 +-
 lib/spack/spack/modules.py     | 90 +++++++++++++++++-----------------
 3 files changed, 62 insertions(+), 50 deletions(-)

diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index ff5fba24f8..2067c6146e 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -250,7 +250,7 @@
                 'type': 'string',
                 'enum': ['None', 'Direct', 'All']
             },
-            'module_type_configuration': {
+            'module_file_configuration': {
                 'type': 'object',
                 'default': {},
                 'additionalProperties': False,
@@ -260,7 +260,7 @@
                         'default': {},
                         'additionalProperties': False,
                         'properties': {
-                            'environment_modifications': {
+                            'environment_blacklist': {
                                 'type': 'array',
                                 'default': [],
                                 'items': {
@@ -270,7 +270,21 @@
                         }
                     },
                     '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'}
                 }
             }
         },
diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py
index 3d18d3a63f..92ab4e6bea 100644
--- a/lib/spack/spack/environment.py
+++ b/lib/spack/spack/environment.py
@@ -252,7 +252,7 @@ def validate(env, 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
 
diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py
index 115d4d9a37..62cd2a8a8b 100644
--- a/lib/spack/spack/modules.py
+++ b/lib/spack/spack/modules.py
@@ -49,6 +49,7 @@
 import llnl.util.tty as tty
 import spack
 import spack.config
+
 from llnl.util.filesystem import join_path, mkdirp
 from spack.build_environment import parent_class_modules, set_module_variables_for_package
 from spack.environment import *
@@ -137,7 +138,6 @@ def __init__(self, spec=None):
         if self.spec.package.__doc__:
             self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__)
 
-
     @property
     def category(self):
         # Anything defined at the package level takes precedence
@@ -150,35 +150,40 @@ def category(self):
         return 'spack installed package'
 
     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)
         if not os.path.exists(module_dir):
             mkdirp(module_dir)
 
-        # Environment modifications guessed by inspecting the
-        # installation prefix
-        env = inspect_path(self.spec.prefix)
-
-        # Let the extendee/dependency modify their extensions/dependencies before asking for
-        # package-specific modifications
-        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)]
+            l = [xx for xx 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]
+                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 [x for ii, x in l if not (x in seen or seen_add(x))]
+            return [xx for ii, xx in l if not (xx in seen or seen_add(xx))]
+
+        # Environment modifications guessed by inspecting the
+        # installation prefix
+        env = inspect_path(self.spec.prefix)
 
+        # Let the extendee/dependency modify their extensions/dependencies before asking for
+        # package-specific modifications
+        spack_env = EnvironmentModifications()
         # TODO : the code down below is quite similar to build_environment.setup_package and needs to be
         # TODO : factored out to a single place
         for item in dependencies('All'):
@@ -207,43 +212,43 @@ def dependencies(request='All'):
 
         # Filter modifications to environment variables
         try:
-            filter_list = CONFIGURATION[self.name]['filter']['environment_modifications']
+            filter_list = CONFIGURATION[self.name]['filter']['environment_blacklist']
         except KeyError:
             filter_list = []
 
+        # Build up the module file content
+        module_file_content = self.header
+        for x in autoload_list:
+            module_file_content += self.autoload(x)
+        for x in prerequisites_list:
+            module_file_content += self.prerequisite(x)
+        for line in self.process_environment_command(filter_environment_blacklist(env, filter_list)):
+            module_file_content += line
+
+        # Dump to file
         with open(self.file_name, 'w') as f:
-            # Header
-            f.write(self.header)
-            # Automatic loads
-            for x in autoload_list:
-                f.write(self.autoload(x))
-            # Prerequisites
-            for x in prerequisites_list:
-                f.write(self.prerequisite(x))
-            # Modifications to the environment
-            iterable = self.process_environment_command(filter_environment_modifications(env, filter_list))
-            for line in iterable:
-                f.write(line)
+            f.write(module_file_content)
 
     @property
     def header(self):
         raise NotImplementedError()
 
     def autoload(self, spec):
-        raise NotImplementedError()
+        m = TclModule(spec)
+        return self.autoload_format.format(module_file=m.use_name)
 
     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):
         for command in env:
             try:
-                yield self.formats[type(command)].format(**command.args)
+                yield self.environment_modifications_formats[type(command)].format(**command.args)
             except KeyError:
                 tty.warn('Cannot handle command of type {command} : skipping request'.format(command=type(command)))
                 tty.warn('{context} at {filename}:{lineno}'.format(**command.args))
 
-
     @property
     def file_name(self):
         """Subclasses should implement this to return the name of the file
@@ -266,7 +271,7 @@ class Dotkit(EnvModule):
     name = 'dotkit'
     path = join_path(spack.share_path, "dotkit")
 
-    formats = {
+    environment_modifications_formats = {
         PrependPath: 'dk_alter {name} {value}\n',
         SetEnv: 'dk_setenv {name} {value}\n'
     }
@@ -304,7 +309,7 @@ class TclModule(EnvModule):
     name = 'tcl'
     path = join_path(spack.share_path, "modules")
 
-    formats = {
+    environment_modifications_formats = {
         PrependPath: 'prepend-path {name} \"{value}\"\n',
         AppendPath: 'append-path {name} \"{value}\"\n',
         RemovePath: 'remove-path {name} \"{value}\"\n',
@@ -312,6 +317,13 @@ class TclModule(EnvModule):
         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
     def file_name(self):
         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 += '}\n\n'
         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)
-- 
GitLab