lmod : added support for the creation of hierarchical lua module files (#1723)
Includes : - treatment of a generic hierarchy (i.e. lapack + mpi + compiler) - possibility to specify which compilers are to be considered Core - correct treatment of the 'family' directive - unit tests for most new features
This commit is contained in:
		 Massimiliano Culpo
					Massimiliano Culpo
				
			
				
					committed by
					
						 Todd Gamblin
						Todd Gamblin
					
				
			
			
				
	
			
			
			 Todd Gamblin
						Todd Gamblin
					
				
			
						parent
						
							efadc0e299
						
					
				
				
					commit
					ea446c0f0e
				
			
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -12,6 +12,7 @@ | |||||||
| /etc/spackconfig | /etc/spackconfig | ||||||
| /share/spack/dotkit | /share/spack/dotkit | ||||||
| /share/spack/modules | /share/spack/modules | ||||||
|  | /share/spack/lmod | ||||||
| /TAGS | /TAGS | ||||||
| /htmlcov | /htmlcov | ||||||
| .coverage | .coverage | ||||||
|   | |||||||
| @@ -69,8 +69,8 @@ def get_cmd_function_name(name): | |||||||
| def get_module(name): | def get_module(name): | ||||||
|     """Imports the module for a particular command name and returns it.""" |     """Imports the module for a particular command name and returns it.""" | ||||||
|     module_name = "%s.%s" % (__name__, name) |     module_name = "%s.%s" % (__name__, name) | ||||||
|     module = __import__( |     module = __import__(module_name, | ||||||
|         module_name, fromlist=[name, SETUP_PARSER, DESCRIPTION], |                         fromlist=[name, SETUP_PARSER, DESCRIPTION], | ||||||
|                         level=0) |                         level=0) | ||||||
|  |  | ||||||
|     attr_setdefault(module, SETUP_PARSER, lambda *args: None)  # null-op |     attr_setdefault(module, SETUP_PARSER, lambda *args: None)  # null-op | ||||||
| @@ -78,8 +78,8 @@ def get_module(name): | |||||||
|  |  | ||||||
|     fn_name = get_cmd_function_name(name) |     fn_name = get_cmd_function_name(name) | ||||||
|     if not hasattr(module, fn_name): |     if not hasattr(module, fn_name): | ||||||
|         tty.die("Command module %s (%s) must define function '%s'." |         tty.die("Command module %s (%s) must define function '%s'." % | ||||||
|                 % (module.__name__, module.__file__, fn_name)) |                 (module.__name__, module.__file__, fn_name)) | ||||||
|  |  | ||||||
|     return module |     return module | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,10 +29,10 @@ | |||||||
| import shutil | import shutil | ||||||
| import sys | import sys | ||||||
|  |  | ||||||
|  | import llnl.util.filesystem as filesystem | ||||||
| import llnl.util.tty as tty | import llnl.util.tty as tty | ||||||
| import spack.cmd | import spack.cmd | ||||||
| import spack.cmd.common.arguments as arguments | import spack.cmd.common.arguments as arguments | ||||||
| import llnl.util.filesystem as filesystem |  | ||||||
| from spack.modules import module_types | from spack.modules import module_types | ||||||
|  |  | ||||||
| description = "Manipulate module files" | description = "Manipulate module files" | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ | |||||||
| ############################################################################## | ############################################################################## | ||||||
| """This package contains modules with hooks for various stages in the | """This package contains modules with hooks for various stages in the | ||||||
|    Spack install process.  You can add modules here and they'll be |    Spack install process.  You can add modules here and they'll be | ||||||
|    executaed by package at various times during the package lifecycle. |    executed by package at various times during the package lifecycle. | ||||||
|  |  | ||||||
|    Each hook is just a function that takes a package as a parameter. |    Each hook is just a function that takes a package as a parameter. | ||||||
|    Hooks are not executed in any particular order. |    Hooks are not executed in any particular order. | ||||||
| @@ -41,9 +41,10 @@ | |||||||
|    features. |    features. | ||||||
| """ | """ | ||||||
| import imp | import imp | ||||||
| from llnl.util.lang import memoized, list_modules |  | ||||||
| from llnl.util.filesystem import join_path |  | ||||||
| import spack | import spack | ||||||
|  | from llnl.util.filesystem import join_path | ||||||
|  | from llnl.util.lang import memoized, list_modules | ||||||
|  |  | ||||||
|  |  | ||||||
| @memoized | @memoized | ||||||
| @@ -70,7 +71,6 @@ def __call__(self, pkg): | |||||||
|                 if hasattr(hook, '__call__'): |                 if hasattr(hook, '__call__'): | ||||||
|                     hook(pkg) |                     hook(pkg) | ||||||
|  |  | ||||||
|  |  | ||||||
| # | # | ||||||
| # Define some functions that can be called to fire off hooks. | # Define some functions that can be called to fire off hooks. | ||||||
| # | # | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								lib/spack/spack/hooks/lmodmodule.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								lib/spack/spack/hooks/lmodmodule.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | ############################################################################## | ||||||
|  | # Copyright (c) 2013, Lawrence Livermore National Security, LLC. | ||||||
|  | # Produced at the Lawrence Livermore National Laboratory. | ||||||
|  | # | ||||||
|  | # This file is part of Spack. | ||||||
|  | # Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. | ||||||
|  | # LLNL-CODE-647188 | ||||||
|  | # | ||||||
|  | # For details, see https://scalability-llnl.github.io/spack | ||||||
|  | # Please also see the LICENSE file for our notice and the LGPL. | ||||||
|  | # | ||||||
|  | # This program is free software; you can redistribute it and/or modify | ||||||
|  | # it under the terms of the GNU General Public License (as published by | ||||||
|  | # the Free Software Foundation) version 2.1 dated February 1999. | ||||||
|  | # | ||||||
|  | # This program is distributed in the hope that it will be useful, but | ||||||
|  | # WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF | ||||||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and | ||||||
|  | # conditions of the GNU General Public License for more details. | ||||||
|  | # | ||||||
|  | # You should have received a copy of the GNU Lesser General Public License | ||||||
|  | # along with this program; if not, write to the Free Software Foundation, | ||||||
|  | # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||||
|  | ############################################################################## | ||||||
|  | import spack.modules | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def post_install(pkg): | ||||||
|  |     dk = spack.modules.LmodModule(pkg.spec) | ||||||
|  |     dk.write() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def post_uninstall(pkg): | ||||||
|  |     dk = spack.modules.LmodModule(pkg.spec) | ||||||
|  |     dk.remove() | ||||||
| @@ -40,6 +40,7 @@ | |||||||
| """ | """ | ||||||
| import copy | import copy | ||||||
| import datetime | import datetime | ||||||
|  | import itertools | ||||||
| import os | import os | ||||||
| import os.path | import os.path | ||||||
| import re | import re | ||||||
| @@ -48,6 +49,7 @@ | |||||||
|  |  | ||||||
| import llnl.util.tty as tty | import llnl.util.tty as tty | ||||||
| import spack | import spack | ||||||
|  | import spack.compilers  # Needed by LmodModules | ||||||
| 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 | from spack.build_environment import parent_class_modules | ||||||
| @@ -56,7 +58,8 @@ | |||||||
|  |  | ||||||
| __all__ = ['EnvModule', 'Dotkit', 'TclModule'] | __all__ = ['EnvModule', 'Dotkit', 'TclModule'] | ||||||
|  |  | ||||||
| # Registry of all types of modules.  Entries created by EnvModule's metaclass | """Registry of all types of modules.  Entries created by EnvModule's | ||||||
|  |    metaclass.""" | ||||||
| module_types = {} | module_types = {} | ||||||
|  |  | ||||||
| CONFIGURATION = spack.config.get_config('modules') | CONFIGURATION = spack.config.get_config('modules') | ||||||
| @@ -633,3 +636,237 @@ def module_specific_content(self, configuration): | |||||||
|                         raise SystemExit('Module generation aborted.') |                         raise SystemExit('Module generation aborted.') | ||||||
|                 line = line.format(**naming_tokens) |                 line = line.format(**naming_tokens) | ||||||
|             yield line |             yield line | ||||||
|  |  | ||||||
|  | # To construct an arbitrary hierarchy of module files: | ||||||
|  | # 1. Parse the configuration file and check that all the items in | ||||||
|  | #    hierarchical_scheme are indeed virtual packages | ||||||
|  | #    This needs to be done only once at start-up | ||||||
|  | # 2. Order the stack as `hierarchical_scheme + ['mpi, 'compiler'] | ||||||
|  | # 3. Check which of the services are provided by the package | ||||||
|  | #    -> may be more than one | ||||||
|  | # 4. Check which of the services are needed by the package | ||||||
|  | #    -> this determines where to write the module file | ||||||
|  | # 5. For each combination of services in which we have at least one provider | ||||||
|  | #    here add the appropriate conditional MODULEPATH modifications | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class LmodModule(EnvModule): | ||||||
|  |     name = 'lmod' | ||||||
|  |     path = join_path(spack.share_path, "lmod") | ||||||
|  |  | ||||||
|  |     environment_modifications_formats = { | ||||||
|  |         PrependPath: 'prepend_path("{name}", "{value}")\n', | ||||||
|  |         AppendPath: 'append_path("{name}", "{value}")\n', | ||||||
|  |         RemovePath: 'remove_path("{name}", "{value}")\n', | ||||||
|  |         SetEnv: 'setenv("{name}", "{value}")\n', | ||||||
|  |         UnsetEnv: 'unsetenv("{name}")\n' | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     autoload_format = ('if not isloaded("{module_file}") then\n' | ||||||
|  |                        '    LmodMessage("Autoloading {module_file}")\n' | ||||||
|  |                        '    load("{module_file}")\n' | ||||||
|  |                        'end\n\n') | ||||||
|  |  | ||||||
|  |     prerequisite_format = 'prereq("{module_file}")\n' | ||||||
|  |  | ||||||
|  |     family_format = 'family("{family}")\n' | ||||||
|  |  | ||||||
|  |     path_part_with_hash = join_path('{token.name}', '{token.version}-{token.hash}')  # NOQA: ignore=E501 | ||||||
|  |     path_part_without_hash = join_path('{token.name}', '{token.version}') | ||||||
|  |  | ||||||
|  |     # TODO : Check that extra tokens specified in configuration file | ||||||
|  |     # TODO : are actually virtual dependencies | ||||||
|  |     configuration = CONFIGURATION.get('lmod', {}) | ||||||
|  |     hierarchy_tokens = configuration.get('hierarchical_scheme', []) | ||||||
|  |     hierarchy_tokens = hierarchy_tokens + ['mpi', 'compiler'] | ||||||
|  |  | ||||||
|  |     def __init__(self, spec=None): | ||||||
|  |         super(LmodModule, self).__init__(spec) | ||||||
|  |         # Sets the root directory for this architecture | ||||||
|  |         self.modules_root = join_path(LmodModule.path, self.spec.architecture) | ||||||
|  |         # Retrieve core compilers | ||||||
|  |         self.core_compilers = self.configuration.get('core_compilers', []) | ||||||
|  |         # Keep track of the requirements that this package has in terms | ||||||
|  |         # of virtual packages | ||||||
|  |         # that participate in the hierarchical structure | ||||||
|  |         self.requires = {'compiler': self.spec.compiler} | ||||||
|  |         # For each virtual dependency in the hierarchy | ||||||
|  |         for x in self.hierarchy_tokens: | ||||||
|  |             if x in self.spec and not self.spec.package.provides( | ||||||
|  |                     x):  # if I depend on it | ||||||
|  |                 self.requires[x] = self.spec[x]  # record the actual provider | ||||||
|  |         # Check what are the services I need (this will determine where the | ||||||
|  |         # module file will be written) | ||||||
|  |         self.substitutions = {} | ||||||
|  |         self.substitutions.update(self.requires) | ||||||
|  |         # TODO : complete substitutions | ||||||
|  |         # Check what service I provide to others | ||||||
|  |         self.provides = {} | ||||||
|  |         # If it is in the list of supported compilers family -> compiler | ||||||
|  |         if self.spec.name in spack.compilers.supported_compilers(): | ||||||
|  |             self.provides['compiler'] = spack.spec.CompilerSpec(str(self.spec)) | ||||||
|  |         # Special case for llvm | ||||||
|  |         if self.spec.name == 'llvm': | ||||||
|  |             self.provides['compiler'] = spack.spec.CompilerSpec(str(self.spec)) | ||||||
|  |             self.provides['compiler'].name = 'clang' | ||||||
|  |  | ||||||
|  |         for x in self.hierarchy_tokens: | ||||||
|  |             if self.spec.package.provides(x): | ||||||
|  |                 self.provides[x] = self.spec[x] | ||||||
|  |  | ||||||
|  |     def _hierarchy_token_combinations(self): | ||||||
|  |         """ | ||||||
|  |         Yields all the relevant combinations that could appear in the hierarchy | ||||||
|  |         """ | ||||||
|  |         for ii in range(len(self.hierarchy_tokens) + 1): | ||||||
|  |             for item in itertools.combinations(self.hierarchy_tokens, ii): | ||||||
|  |                 if 'compiler' in item: | ||||||
|  |                     yield item | ||||||
|  |  | ||||||
|  |     def _hierarchy_to_be_provided(self): | ||||||
|  |         """ | ||||||
|  |         Filters a list of hierarchy tokens and yields only the one that we | ||||||
|  |         need to provide | ||||||
|  |         """ | ||||||
|  |         for item in self._hierarchy_token_combinations(): | ||||||
|  |             if any(x in self.provides for x in item): | ||||||
|  |                 yield item | ||||||
|  |  | ||||||
|  |     def token_to_path(self, name, value): | ||||||
|  |         # If we are dealing with a core compiler, return 'Core' | ||||||
|  |         if name == 'compiler' and str(value) in self.core_compilers: | ||||||
|  |             return 'Core' | ||||||
|  |         # CompilerSpec does not have an hash | ||||||
|  |         if name == 'compiler': | ||||||
|  |             return self.path_part_without_hash.format(token=value) | ||||||
|  |         # For virtual providers add a small part of the hash | ||||||
|  |         # to distinguish among different variants in a directory hierarchy | ||||||
|  |         value.hash = value.dag_hash(length=6) | ||||||
|  |         return self.path_part_with_hash.format(token=value) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def file_name(self): | ||||||
|  |         parts = [self.token_to_path(x, self.requires[x]) | ||||||
|  |                  for x in self.hierarchy_tokens if x in self.requires] | ||||||
|  |         hierarchy_name = join_path(*parts) | ||||||
|  |         fullname = join_path(self.modules_root, hierarchy_name, | ||||||
|  |                              self.use_name + '.lua') | ||||||
|  |         return fullname | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def use_name(self): | ||||||
|  |         return self.token_to_path('', self.spec) | ||||||
|  |  | ||||||
|  |     def modulepath_modifications(self): | ||||||
|  |         # What is available is what we require plus what we provide | ||||||
|  |         entry = '' | ||||||
|  |         available = {} | ||||||
|  |         available.update(self.requires) | ||||||
|  |         available.update(self.provides) | ||||||
|  |         available_parts = [self.token_to_path(x, available[x]) | ||||||
|  |                            for x in self.hierarchy_tokens if x in available] | ||||||
|  |         # Missing parts | ||||||
|  |         missing = [x for x in self.hierarchy_tokens if x not in available] | ||||||
|  |         # Direct path we provide on top of compilers | ||||||
|  |         modulepath = join_path(self.modules_root, *available_parts) | ||||||
|  |         env = EnvironmentModifications() | ||||||
|  |         env.prepend_path('MODULEPATH', modulepath) | ||||||
|  |         for line in self.process_environment_command(env): | ||||||
|  |             entry += line | ||||||
|  |  | ||||||
|  |         def local_variable(x): | ||||||
|  |             lower, upper = x.lower(), x.upper() | ||||||
|  |             fmt = 'local {lower}_name = os.getenv("LMOD_{upper}_NAME")\n' | ||||||
|  |             fmt += 'local {lower}_version = os.getenv("LMOD_{upper}_VERSION")\n'  # NOQA: ignore=501 | ||||||
|  |             return fmt.format(lower=lower, upper=upper) | ||||||
|  |  | ||||||
|  |         def set_variables_for_service(env, x): | ||||||
|  |             upper = x.upper() | ||||||
|  |             s = self.provides[x] | ||||||
|  |             name, version = os.path.split(self.token_to_path(x, s)) | ||||||
|  |  | ||||||
|  |             env.set('LMOD_{upper}_NAME'.format(upper=upper), name) | ||||||
|  |             env.set('LMOD_{upper}_VERSION'.format(upper=upper), version) | ||||||
|  |  | ||||||
|  |         def conditional_modulepath_modifications(item): | ||||||
|  |             entry = 'if ' | ||||||
|  |             needed = [] | ||||||
|  |             for x in self.hierarchy_tokens: | ||||||
|  |                 if x in missing: | ||||||
|  |                     needed.append('{x}_name '.format(x=x)) | ||||||
|  |             entry += 'and '.join(needed) + 'then\n' | ||||||
|  |             entry += '  local t = pathJoin("{root}"'.format( | ||||||
|  |                 root=self.modules_root) | ||||||
|  |             for x in item: | ||||||
|  |                 if x in missing: | ||||||
|  |                     entry += ', {lower}_name, {lower}_version'.format( | ||||||
|  |                         lower=x.lower()) | ||||||
|  |                 else: | ||||||
|  |                     entry += ', "{x}"'.format( | ||||||
|  |                         x=self.token_to_path(x, available[x])) | ||||||
|  |             entry += ')\n' | ||||||
|  |             entry += '  prepend_path("MODULEPATH", t)\n' | ||||||
|  |             entry += 'end\n\n' | ||||||
|  |             return entry | ||||||
|  |  | ||||||
|  |         if 'compiler' not in self.provides: | ||||||
|  |             # Retrieve variables | ||||||
|  |             entry += '\n' | ||||||
|  |             for x in missing: | ||||||
|  |                 entry += local_variable(x) | ||||||
|  |             entry += '\n' | ||||||
|  |             # Conditional modifications | ||||||
|  |             conditionals = [x | ||||||
|  |                             for x in self._hierarchy_to_be_provided() | ||||||
|  |                             if any(t in missing for t in x)] | ||||||
|  |             for item in conditionals: | ||||||
|  |                 entry += conditional_modulepath_modifications(item) | ||||||
|  |  | ||||||
|  |             # Set environment variables for the services we provide | ||||||
|  |             env = EnvironmentModifications() | ||||||
|  |             for x in self.provides: | ||||||
|  |                 set_variables_for_service(env, x) | ||||||
|  |             for line in self.process_environment_command(env): | ||||||
|  |                 entry += line | ||||||
|  |  | ||||||
|  |         return entry | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def header(self): | ||||||
|  |         timestamp = datetime.datetime.now() | ||||||
|  |         # Header as in | ||||||
|  |         # https://www.tacc.utexas.edu/research-development/tacc-projects/lmod/advanced-user-guide/more-about-writing-module-files | ||||||
|  |         header = "-- -*- lua -*-\n" | ||||||
|  |         header += '-- Module file created by spack (https://github.com/LLNL/spack) on %s\n' % timestamp  # NOQA: ignore=E501 | ||||||
|  |         header += '--\n' | ||||||
|  |         header += '-- %s\n' % self.spec.short_spec | ||||||
|  |         header += '--\n' | ||||||
|  |  | ||||||
|  |         # Short description -> whatis() | ||||||
|  |         if self.short_description: | ||||||
|  |             header += "whatis([[Name : {name}]])\n".format(name=self.spec.name) | ||||||
|  |             header += "whatis([[Version : {version}]])\n".format( | ||||||
|  |                 version=self.spec.version) | ||||||
|  |  | ||||||
|  |         # Long description -> help() | ||||||
|  |         if self.long_description: | ||||||
|  |             doc = re.sub(r'"', '\"', self.long_description) | ||||||
|  |             header += "help([[{documentation}]])\n".format(documentation=doc) | ||||||
|  |  | ||||||
|  |         # Certain things need to be done only if we provide a service | ||||||
|  |         if self.provides: | ||||||
|  |             # Add family directives | ||||||
|  |             header += '\n' | ||||||
|  |             for x in self.provides: | ||||||
|  |                 header += self.family_format.format(family=x) | ||||||
|  |             header += '\n' | ||||||
|  |             header += '-- MODULEPATH modifications\n' | ||||||
|  |             header += '\n' | ||||||
|  |             # Modify MODULEPATH | ||||||
|  |             header += self.modulepath_modifications() | ||||||
|  |             # Set environment variables for services we provide | ||||||
|  |             header += '\n' | ||||||
|  |             header += '-- END MODULEPATH modifications\n' | ||||||
|  |             header += '\n' | ||||||
|  |  | ||||||
|  |         return header | ||||||
|   | |||||||
| @@ -139,7 +139,20 @@ | |||||||
|                     'default': [], |                     'default': [], | ||||||
|                     'items': { |                     'items': { | ||||||
|                         'type': 'string', |                         'type': 'string', | ||||||
|                         'enum': ['tcl', 'dotkit']}}, |                         'enum': ['tcl', 'dotkit', 'lmod']}}, | ||||||
|  |                 'lmod': { | ||||||
|  |                     'allOf': [ | ||||||
|  |                         # Base configuration | ||||||
|  |                         {'$ref': '#/definitions/module_type_configuration'}, | ||||||
|  |                         { | ||||||
|  |                             'core_compilers': { | ||||||
|  |                                 '$ref': '#/definitions/array_of_strings' | ||||||
|  |                             }, | ||||||
|  |                             'hierarchical_scheme': { | ||||||
|  |                                 '$ref': '#/definitions/array_of_strings' | ||||||
|  |                             } | ||||||
|  |                         }  # Specific lmod extensions | ||||||
|  |                     ]}, | ||||||
|                 'tcl': { |                 'tcl': { | ||||||
|                     'allOf': [ |                     'allOf': [ | ||||||
|                         # Base configuration |                         # Base configuration | ||||||
|   | |||||||
| @@ -26,8 +26,8 @@ | |||||||
| These tests check the database is functioning properly, | These tests check the database is functioning properly, | ||||||
| both in memory and in its file | both in memory and in its file | ||||||
| """ | """ | ||||||
| import os.path |  | ||||||
| import multiprocessing | import multiprocessing | ||||||
|  | import os.path | ||||||
|  |  | ||||||
| import spack | import spack | ||||||
| from llnl.util.filesystem import join_path | from llnl.util.filesystem import join_path | ||||||
|   | |||||||
| @@ -49,105 +49,10 @@ def mock_open(filename, mode): | |||||||
|         handle.close() |         handle.close() | ||||||
|  |  | ||||||
|  |  | ||||||
| configuration_autoload_direct = { | # Spec strings that will be used throughout the tests | ||||||
|     'enable': ['tcl'], | mpich_spec_string = 'mpich@3.0.4' | ||||||
|     'tcl': { | mpileaks_spec_string = 'mpileaks' | ||||||
|         'all': { | libdwarf_spec_string = 'libdwarf arch=x64-linux' | ||||||
|             'autoload': 'direct' |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| configuration_autoload_all = { |  | ||||||
|     'enable': ['tcl'], |  | ||||||
|     'tcl': { |  | ||||||
|         'all': { |  | ||||||
|             'autoload': 'all' |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| configuration_prerequisites_direct = { |  | ||||||
|     'enable': ['tcl'], |  | ||||||
|     'tcl': { |  | ||||||
|         'all': { |  | ||||||
|             'prerequisites': 'direct' |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| configuration_prerequisites_all = { |  | ||||||
|     'enable': ['tcl'], |  | ||||||
|     'tcl': { |  | ||||||
|         'all': { |  | ||||||
|             'prerequisites': 'all' |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| configuration_alter_environment = { |  | ||||||
|     'enable': ['tcl'], |  | ||||||
|     'tcl': { |  | ||||||
|         'all': { |  | ||||||
|             'filter': {'environment_blacklist': ['CMAKE_PREFIX_PATH']}, |  | ||||||
|             'environment': { |  | ||||||
|                 'set': {'{name}_ROOT': '{prefix}'} |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         'platform=test target=x86_64': { |  | ||||||
|             'environment': { |  | ||||||
|                 'set': {'FOO': 'foo'}, |  | ||||||
|                 'unset': ['BAR'] |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         'platform=test target=x86_32': { |  | ||||||
|             'load': ['foo/bar'] |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| configuration_blacklist = { |  | ||||||
|     'enable': ['tcl'], |  | ||||||
|     'tcl': { |  | ||||||
|         'whitelist': ['zmpi'], |  | ||||||
|         'blacklist': ['callpath', 'mpi'], |  | ||||||
|         'all': { |  | ||||||
|             'autoload': 'direct' |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| configuration_conflicts = { |  | ||||||
|     'enable': ['tcl'], |  | ||||||
|     'tcl': { |  | ||||||
|         'naming_scheme': '{name}/{version}-{compiler.name}', |  | ||||||
|         'all': { |  | ||||||
|             'conflict': ['{name}', 'intel/14.0.1'] |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| configuration_wrong_conflicts = { |  | ||||||
|     'enable': ['tcl'], |  | ||||||
|     'tcl': { |  | ||||||
|         'naming_scheme': '{name}/{version}-{compiler.name}', |  | ||||||
|         'all': { |  | ||||||
|             'conflict': ['{name}/{compiler.name}'] |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| configuration_suffix = { |  | ||||||
|     'enable': ['tcl'], |  | ||||||
|     'tcl': { |  | ||||||
|         'mpileaks': { |  | ||||||
|             'suffixes': { |  | ||||||
|                 '+debug': 'foo', |  | ||||||
|                 '~debug': 'bar' |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HelperFunctionsTests(MockPackagesTest): | class HelperFunctionsTests(MockPackagesTest): | ||||||
| @@ -187,44 +92,156 @@ def test_inspect_path(self): | |||||||
|         self.assertTrue('CPATH' in names) |         self.assertTrue('CPATH' in names) | ||||||
|  |  | ||||||
|  |  | ||||||
| class TclTests(MockPackagesTest): | class ModuleFileGeneratorTests(MockPackagesTest): | ||||||
|  |     """ | ||||||
|  |     Base class to test module file generators. Relies on child having defined | ||||||
|  |     a 'factory' attribute to create an instance of the generator to be tested. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super(TclTests, self).setUp() |         super(ModuleFileGeneratorTests, self).setUp() | ||||||
|         self.configuration_obj = spack.modules.CONFIGURATION |         self.configuration_instance = spack.modules.CONFIGURATION | ||||||
|  |         self.module_types_instance = spack.modules.module_types | ||||||
|         spack.modules.open = mock_open |         spack.modules.open = mock_open | ||||||
|         # Make sure that a non-mocked configuration will trigger an error |         # Make sure that a non-mocked configuration will trigger an error | ||||||
|         spack.modules.CONFIGURATION = None |         spack.modules.CONFIGURATION = None | ||||||
|  |         spack.modules.module_types = {self.factory.name: self.factory} | ||||||
|  |  | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
|         del spack.modules.open |         del spack.modules.open | ||||||
|         spack.modules.CONFIGURATION = self.configuration_obj |         spack.modules.module_types = self.module_types_instance | ||||||
|         super(TclTests, self).tearDown() |         spack.modules.CONFIGURATION = self.configuration_instance | ||||||
|  |         super(ModuleFileGeneratorTests, self).tearDown() | ||||||
|  |  | ||||||
|     def get_modulefile_content(self, spec): |     def get_modulefile_content(self, spec): | ||||||
|         spec.concretize() |         spec.concretize() | ||||||
|         generator = spack.modules.TclModule(spec) |         generator = self.factory(spec) | ||||||
|         generator.write() |         generator.write() | ||||||
|         content = FILE_REGISTRY[generator.file_name].split('\n') |         content = FILE_REGISTRY[generator.file_name].split('\n') | ||||||
|         return content |         return content | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TclTests(ModuleFileGeneratorTests): | ||||||
|  |  | ||||||
|  |     factory = spack.modules.TclModule | ||||||
|  |  | ||||||
|  |     configuration_autoload_direct = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'all': { | ||||||
|  |                 'autoload': 'direct' | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_autoload_all = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'all': { | ||||||
|  |                 'autoload': 'all' | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_prerequisites_direct = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'all': { | ||||||
|  |                 'prerequisites': 'direct' | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_prerequisites_all = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'all': { | ||||||
|  |                 'prerequisites': 'all' | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_alter_environment = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'all': { | ||||||
|  |                 'filter': {'environment_blacklist': ['CMAKE_PREFIX_PATH']}, | ||||||
|  |                 'environment': { | ||||||
|  |                     'set': {'{name}_ROOT': '{prefix}'} | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             'platform=test target=x86_64': { | ||||||
|  |                 'environment': { | ||||||
|  |                     'set': {'FOO': 'foo'}, | ||||||
|  |                     'unset': ['BAR'] | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             'platform=test target=x86_32': { | ||||||
|  |                 'load': ['foo/bar'] | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_blacklist = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'whitelist': ['zmpi'], | ||||||
|  |             'blacklist': ['callpath', 'mpi'], | ||||||
|  |             'all': { | ||||||
|  |                 'autoload': 'direct' | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_conflicts = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'naming_scheme': '{name}/{version}-{compiler.name}', | ||||||
|  |             'all': { | ||||||
|  |                 'conflict': ['{name}', 'intel/14.0.1'] | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_wrong_conflicts = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'naming_scheme': '{name}/{version}-{compiler.name}', | ||||||
|  |             'all': { | ||||||
|  |                 'conflict': ['{name}/{compiler.name}'] | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_suffix = { | ||||||
|  |         'enable': ['tcl'], | ||||||
|  |         'tcl': { | ||||||
|  |             'mpileaks': { | ||||||
|  |                 'suffixes': { | ||||||
|  |                     '+debug': 'foo', | ||||||
|  |                     '~debug': 'bar' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     def test_simple_case(self): |     def test_simple_case(self): | ||||||
|         spack.modules.CONFIGURATION = configuration_autoload_direct |         spack.modules.CONFIGURATION = self.configuration_autoload_direct | ||||||
|         spec = spack.spec.Spec('mpich@3.0.4') |         spec = spack.spec.Spec(mpich_spec_string) | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertTrue('module-whatis "mpich @3.0.4"' in content) |         self.assertTrue('module-whatis "mpich @3.0.4"' in content) | ||||||
|         self.assertRaises(TypeError, spack.modules.dependencies, |         self.assertRaises(TypeError, spack.modules.dependencies, | ||||||
|                           spec, 'non-existing-tag') |                           spec, 'non-existing-tag') | ||||||
|  |  | ||||||
|     def test_autoload(self): |     def test_autoload(self): | ||||||
|         spack.modules.CONFIGURATION = configuration_autoload_direct |         spack.modules.CONFIGURATION = self.configuration_autoload_direct | ||||||
|         spec = spack.spec.Spec('mpileaks') |         spec = spack.spec.Spec(mpileaks_spec_string) | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 2) |         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 2) | ||||||
|         self.assertEqual(len([x for x in content if 'module load ' in x]), 2) |         self.assertEqual(len([x for x in content if 'module load ' in x]), 2) | ||||||
|  |  | ||||||
|         spack.modules.CONFIGURATION = configuration_autoload_all |         spack.modules.CONFIGURATION = self.configuration_autoload_all | ||||||
|         spec = spack.spec.Spec('mpileaks') |         spec = spack.spec.Spec(mpileaks_spec_string) | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 5) |         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 5) | ||||||
|         self.assertEqual(len([x for x in content if 'module load ' in x]), 5) |         self.assertEqual(len([x for x in content if 'module load ' in x]), 5) | ||||||
| @@ -252,18 +269,18 @@ def test_autoload(self): | |||||||
|         self.assertEqual(len([x for x in content if 'module load ' in x]), 2) |         self.assertEqual(len([x for x in content if 'module load ' in x]), 2) | ||||||
|  |  | ||||||
|     def test_prerequisites(self): |     def test_prerequisites(self): | ||||||
|         spack.modules.CONFIGURATION = configuration_prerequisites_direct |         spack.modules.CONFIGURATION = self.configuration_prerequisites_direct | ||||||
|         spec = spack.spec.Spec('mpileaks arch=x86-linux') |         spec = spack.spec.Spec('mpileaks arch=x86-linux') | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertEqual(len([x for x in content if 'prereq' in x]), 2) |         self.assertEqual(len([x for x in content if 'prereq' in x]), 2) | ||||||
|  |  | ||||||
|         spack.modules.CONFIGURATION = configuration_prerequisites_all |         spack.modules.CONFIGURATION = self.configuration_prerequisites_all | ||||||
|         spec = spack.spec.Spec('mpileaks arch=x86-linux') |         spec = spack.spec.Spec('mpileaks arch=x86-linux') | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertEqual(len([x for x in content if 'prereq' in x]), 5) |         self.assertEqual(len([x for x in content if 'prereq' in x]), 5) | ||||||
|  |  | ||||||
|     def test_alter_environment(self): |     def test_alter_environment(self): | ||||||
|         spack.modules.CONFIGURATION = configuration_alter_environment |         spack.modules.CONFIGURATION = self.configuration_alter_environment | ||||||
|         spec = spack.spec.Spec('mpileaks platform=test target=x86_64') |         spec = spack.spec.Spec('mpileaks platform=test target=x86_64') | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertEqual( |         self.assertEqual( | ||||||
| @@ -293,7 +310,7 @@ def test_alter_environment(self): | |||||||
|             len([x for x in content if 'setenv LIBDWARF_ROOT' in x]), 1) |             len([x for x in content if 'setenv LIBDWARF_ROOT' in x]), 1) | ||||||
|  |  | ||||||
|     def test_blacklist(self): |     def test_blacklist(self): | ||||||
|         spack.modules.CONFIGURATION = configuration_blacklist |         spack.modules.CONFIGURATION = self.configuration_blacklist | ||||||
|         spec = spack.spec.Spec('mpileaks ^zmpi') |         spec = spack.spec.Spec('mpileaks ^zmpi') | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 1) |         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 1) | ||||||
| @@ -307,7 +324,7 @@ def test_blacklist(self): | |||||||
|         self.assertEqual(len([x for x in content if 'module load ' in x]), 1) |         self.assertEqual(len([x for x in content if 'module load ' in x]), 1) | ||||||
|  |  | ||||||
|     def test_conflicts(self): |     def test_conflicts(self): | ||||||
|         spack.modules.CONFIGURATION = configuration_conflicts |         spack.modules.CONFIGURATION = self.configuration_conflicts | ||||||
|         spec = spack.spec.Spec('mpileaks') |         spec = spack.spec.Spec('mpileaks') | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertEqual( |         self.assertEqual( | ||||||
| @@ -317,11 +334,11 @@ def test_conflicts(self): | |||||||
|         self.assertEqual( |         self.assertEqual( | ||||||
|             len([x for x in content if x == 'conflict intel/14.0.1']), 1) |             len([x for x in content if x == 'conflict intel/14.0.1']), 1) | ||||||
|  |  | ||||||
|         spack.modules.CONFIGURATION = configuration_wrong_conflicts |         spack.modules.CONFIGURATION = self.configuration_wrong_conflicts | ||||||
|         self.assertRaises(SystemExit, self.get_modulefile_content, spec) |         self.assertRaises(SystemExit, self.get_modulefile_content, spec) | ||||||
|  |  | ||||||
|     def test_suffixes(self): |     def test_suffixes(self): | ||||||
|         spack.modules.CONFIGURATION = configuration_suffix |         spack.modules.CONFIGURATION = self.configuration_suffix | ||||||
|         spec = spack.spec.Spec('mpileaks+debug arch=x86-linux') |         spec = spack.spec.Spec('mpileaks+debug arch=x86-linux') | ||||||
|         spec.concretize() |         spec.concretize() | ||||||
|         generator = spack.modules.TclModule(spec) |         generator = spack.modules.TclModule(spec) | ||||||
| @@ -333,17 +350,122 @@ def test_suffixes(self): | |||||||
|         self.assertTrue('bar' in generator.use_name) |         self.assertTrue('bar' in generator.use_name) | ||||||
|  |  | ||||||
|  |  | ||||||
| configuration_dotkit = { | class LmodTests(ModuleFileGeneratorTests): | ||||||
|  |     factory = spack.modules.LmodModule | ||||||
|  |  | ||||||
|  |     configuration_autoload_direct = { | ||||||
|  |         'enable': ['lmod'], | ||||||
|  |         'lmod': { | ||||||
|  |             'all': { | ||||||
|  |                 'autoload': 'direct' | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_autoload_all = { | ||||||
|  |         'enable': ['lmod'], | ||||||
|  |         'lmod': { | ||||||
|  |             'all': { | ||||||
|  |                 'autoload': 'all' | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_alter_environment = { | ||||||
|  |         'enable': ['lmod'], | ||||||
|  |         'lmod': { | ||||||
|  |             'all': { | ||||||
|  |                 'filter': {'environment_blacklist': ['CMAKE_PREFIX_PATH']} | ||||||
|  |             }, | ||||||
|  |             'platform=test target=x86_64': { | ||||||
|  |                 'environment': { | ||||||
|  |                     'set': {'FOO': 'foo'}, | ||||||
|  |                     'unset': ['BAR'] | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             'platform=test target=x86_32': { | ||||||
|  |                 'load': ['foo/bar'] | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     configuration_blacklist = { | ||||||
|  |         'enable': ['lmod'], | ||||||
|  |         'lmod': { | ||||||
|  |             'blacklist': ['callpath'], | ||||||
|  |             'all': { | ||||||
|  |                 'autoload': 'direct' | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     def test_simple_case(self): | ||||||
|  |         spack.modules.CONFIGURATION = self.configuration_autoload_direct | ||||||
|  |         spec = spack.spec.Spec(mpich_spec_string) | ||||||
|  |         content = self.get_modulefile_content(spec) | ||||||
|  |         self.assertTrue('-- -*- lua -*-' in content) | ||||||
|  |         self.assertTrue('whatis([[Name : mpich]])' in content) | ||||||
|  |         self.assertTrue('whatis([[Version : 3.0.4]])' in content) | ||||||
|  |  | ||||||
|  |     def test_autoload(self): | ||||||
|  |         spack.modules.CONFIGURATION = self.configuration_autoload_direct | ||||||
|  |         spec = spack.spec.Spec(mpileaks_spec_string) | ||||||
|  |         content = self.get_modulefile_content(spec) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x for x in content if 'if not isloaded(' in x]), 2) | ||||||
|  |         self.assertEqual(len([x for x in content if 'load(' in x]), 2) | ||||||
|  |  | ||||||
|  |         spack.modules.CONFIGURATION = self.configuration_autoload_all | ||||||
|  |         spec = spack.spec.Spec(mpileaks_spec_string) | ||||||
|  |         content = self.get_modulefile_content(spec) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x for x in content if 'if not isloaded(' in x]), 5) | ||||||
|  |         self.assertEqual(len([x for x in content if 'load(' in x]), 5) | ||||||
|  |  | ||||||
|  |     def test_alter_environment(self): | ||||||
|  |         spack.modules.CONFIGURATION = self.configuration_alter_environment | ||||||
|  |         spec = spack.spec.Spec('mpileaks platform=test target=x86_64') | ||||||
|  |         content = self.get_modulefile_content(spec) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x | ||||||
|  |                  for x in content | ||||||
|  |                  if x.startswith('prepend_path("CMAKE_PREFIX_PATH"')]), 0) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x for x in content if 'setenv("FOO", "foo")' in x]), 1) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x for x in content if 'unsetenv("BAR")' in x]), 1) | ||||||
|  |  | ||||||
|  |         spec = spack.spec.Spec('libdwarf %clang platform=test target=x86_32') | ||||||
|  |         content = self.get_modulefile_content(spec) | ||||||
|  |         print('\n'.join(content)) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x | ||||||
|  |                  for x in content | ||||||
|  |                  if x.startswith('prepend-path("CMAKE_PREFIX_PATH"')]), 0) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x for x in content if 'setenv("FOO", "foo")' in x]), 0) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x for x in content if 'unsetenv("BAR")' in x]), 0) | ||||||
|  |  | ||||||
|  |     def test_blacklist(self): | ||||||
|  |         spack.modules.CONFIGURATION = self.configuration_blacklist | ||||||
|  |         spec = spack.spec.Spec(mpileaks_spec_string) | ||||||
|  |         content = self.get_modulefile_content(spec) | ||||||
|  |         self.assertEqual( | ||||||
|  |             len([x for x in content if 'if not isloaded(' in x]), 1) | ||||||
|  |         self.assertEqual(len([x for x in content if 'load(' in x]), 1) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DotkitTests(MockPackagesTest): | ||||||
|  |  | ||||||
|  |     configuration_dotkit = { | ||||||
|         'enable': ['dotkit'], |         'enable': ['dotkit'], | ||||||
|         'dotkit': { |         'dotkit': { | ||||||
|             'all': { |             'all': { | ||||||
|                 'prerequisites': 'direct' |                 'prerequisites': 'direct' | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| class DotkitTests(MockPackagesTest): |  | ||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super(DotkitTests, self).setUp() |         super(DotkitTests, self).setUp() | ||||||
| @@ -365,7 +487,7 @@ def get_modulefile_content(self, spec): | |||||||
|         return content |         return content | ||||||
|  |  | ||||||
|     def test_dotkit(self): |     def test_dotkit(self): | ||||||
|         spack.modules.CONFIGURATION = configuration_dotkit |         spack.modules.CONFIGURATION = self.configuration_dotkit | ||||||
|         spec = spack.spec.Spec('mpileaks arch=x86-linux') |         spec = spack.spec.Spec('mpileaks arch=x86-linux') | ||||||
|         content = self.get_modulefile_content(spec) |         content = self.get_modulefile_content(spec) | ||||||
|         self.assertTrue('#c spack' in content) |         self.assertTrue('#c spack' in content) | ||||||
|   | |||||||
| @@ -22,9 +22,10 @@ | |||||||
| # License along with this program; if not, write to the Free Software | # License along with this program; if not, write to the Free Software | ||||||
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||||
| ############################################################################## | ############################################################################## | ||||||
| from spack import * |  | ||||||
| import os | import os | ||||||
|  |  | ||||||
|  | from spack import * | ||||||
|  |  | ||||||
|  |  | ||||||
| class Llvm(Package): | class Llvm(Package): | ||||||
|     """The LLVM Project is a collection of modular and reusable compiler and |     """The LLVM Project is a collection of modular and reusable compiler and | ||||||
| @@ -37,9 +38,11 @@ class Llvm(Package): | |||||||
|     homepage = 'http://llvm.org/' |     homepage = 'http://llvm.org/' | ||||||
|     url = 'http://llvm.org/releases/3.7.1/llvm-3.7.1.src.tar.xz' |     url = 'http://llvm.org/releases/3.7.1/llvm-3.7.1.src.tar.xz' | ||||||
|  |  | ||||||
|  |     family = 'compiler'  # Used by lmod | ||||||
|  |  | ||||||
|     # currently required by mesa package |     # currently required by mesa package | ||||||
|     version('3.0', 'a8e5f5f1c1adebae7b4a654c376a6005', |     version('3.0', 'a8e5f5f1c1adebae7b4a654c376a6005', | ||||||
|             url='http://llvm.org/releases/3.0/llvm-3.0.tar.gz') |             url='http://llvm.org/releases/3.0/llvm-3.0.tar.gz')  # currently required by mesa package | ||||||
|  |  | ||||||
|     variant('debug', default=False, |     variant('debug', default=False, | ||||||
|             description="Build a debug version of LLVM, this increases " |             description="Build a debug version of LLVM, this increases " | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user