diff options
author | Massimiliano Culpo <massimiliano.culpo@googlemail.com> | 2017-09-19 21:34:20 +0200 |
---|---|---|
committer | becker33 <becker33@llnl.gov> | 2017-09-19 12:34:20 -0700 |
commit | b1d129e68199a94b6210af0a6d8e2aa5b4df576e (patch) | |
tree | 6e908253c13ba3e3a538a5fb731f7df15cdcbe46 /templates | |
parent | 081403f2805f77ba6a1e555cf99b2034062428e2 (diff) | |
download | spack-b1d129e68199a94b6210af0a6d8e2aa5b4df576e.tar.gz spack-b1d129e68199a94b6210af0a6d8e2aa5b4df576e.tar.bz2 spack-b1d129e68199a94b6210af0a6d8e2aa5b4df576e.tar.xz spack-b1d129e68199a94b6210af0a6d8e2aa5b4df576e.zip |
Modulefiles generated with a template engine (#3183)
* Module files now are generated using a template engine refers #2902 #3173
jinja2 has been hooked into Spack.
The python module `modules.py` has been splitted into several modules
under the python package `spack/modules`. Unit tests stressing module
file generation have been refactored accordingly.
The module file generator for Lmod has been extended to multi-providers
and deeper hierarchies.
* Improved the support for templates in module files.
Added an entry in `config.yaml` (`template_dirs`) to list all the
directories where Spack could find templates for `jinja2`.
Module file generators have a simple override mechanism to override
template selection ('modules.yaml' beats 'package.py' beats 'default').
* Added jinja2 and MarkupSafe to vendored packages.
* Spec.concretize() sets mutual spec-package references
The correct place to set the mutual references between spec and package
objects at the end of concretization. After a call to concretize we
should now be ensured that spec is the same object as spec.package.spec.
Code in `build_environment.py` that was performing the same operation
has been turned into an assertion to be defensive on the new behavior.
* Improved code and data layout for modules and related tests.
Common fixtures related to module file generation have been extracted
in `conftest.py`. All the mock configurations for module files have been
extracted from python code and have been put into their own yaml file.
Added a `context_property` decorator for the template engine, to make
it easy to define dictionaries out of properties.
The default for `verbose` in `modules.yaml` is now False instead of True.
* Extendable module file contexts + short description from docstring
The contexts that are used in conjunction with `jinja2` templates to
generate module files can now be extended from package.py and
modules.yaml.
Module files generators now infer the short description from package.py
docstring (and as you may expect it's the first paragraph)
* 'module refresh' regenerates all modules by default
`module refresh` without `--module-type` specified tries to
regenerate all known module types. The same holds true for `module rm`
Configure options used at build time are extracted and written into the
module files where possible.
* Fixed python3 compatibility, tests for Lmod and Tcl.
Added test for exceptional paths of execution when generating Lmod
module files.
Fixed a few compatibility issues with python3.
Fixed a bug in Tcl with naming_scheme and autoload + unit tests
* Updated module file tutorial docs. Fixed a few typos in docstrings.
The reference section for module files has been reorganized. The idea is
to have only three topics at the highest level:
- shell support + spack load/unload use/unuse
- module file generation (a.k.a. APIs + modules.yaml)
- module file maintenance (spack module refresh/rm)
Module file generation will cover the entries in modules.yaml
Also:
- Licenses have been updated to include NOTICE and extended to 2017
- docstrings have been reformatted according to Google style
* Removed redundant arguments to RPackage and WafPackage.
All the callbacks in `RPackage` and `WafPackage` that are not build
phases have been modified not to accept a `spec` and a `prefix`
argument. This permits to leverage the common `configure_args` signature
to insert by default the configuration arguments into the generated
module files. I think it's preferable to handling those packages
differently than `AutotoolsPackage`. Besides only one package seems
to override one of these methods.
* Fixed broken indentation + improved resiliency of refresh
Fixed broken indentation in `spack module refresh` (probably a rebase
gone silently wrong?). Filter the writers for blacklisted specs before
searching for name clashes. An error with a single writer will not
stop regeneration, but instead will print a warning and continue
the command.
Diffstat (limited to 'templates')
-rw-r--r-- | templates/modules/modulefile.dk | 31 | ||||
-rw-r--r-- | templates/modules/modulefile.lua | 91 | ||||
-rw-r--r-- | templates/modules/modulefile.tcl | 82 |
3 files changed, 204 insertions, 0 deletions
diff --git a/templates/modules/modulefile.dk b/templates/modules/modulefile.dk new file mode 100644 index 0000000000..c3f6d2dce1 --- /dev/null +++ b/templates/modules/modulefile.dk @@ -0,0 +1,31 @@ +{% block header %} +{% if category %} +#c {{ category }} +{% endif %} +{% if short_description %} +#d {{ short_description }} +{% endif %} +{% if long_description %} +{{ long_description| textwrap(72)| prepend_to_line('#h ')| join() }} +{% endif %} +{% endblock %} + +{% block autoloads %} +{% for module in autoload %} +dk_op {{ module }} +{% endfor %} +{% endblock %} + +{% block environment %} +{% for command_name, cmd in environment_modifications %} +{% if command_name == 'PrependPath' %} +dk_alter {{ cmd.name }} {{ cmd.value }} +{% endif %} +{% if command_name == 'RemovePath' %} +dk_unalter {{ cmd.name }} {{ cmd.value }} +{% endif %} +{% if command_name == 'SetEnv' %} +dk_setenv {{ cmd.name }} {{ cmd.value }} +{% endif %} +{% endfor %} +{% endblock %} diff --git a/templates/modules/modulefile.lua b/templates/modules/modulefile.lua new file mode 100644 index 0000000000..5550f8929a --- /dev/null +++ b/templates/modules/modulefile.lua @@ -0,0 +1,91 @@ +-- -*- lua -*- +-- Module file created by spack (https://github.com/LLNL/spack) on {{ timestamp }} +-- +-- {{ spec.short_spec }} +-- + +{% block header %} +{% if short_description %} +whatis([[Name : {{ spec.name }}]]) +whatis([[Version : {{ spec.version }}]]) +whatis([[Short description : {{ short_description }}]]) +{% endif %} +{% if configure_options %} +whatis([[Configure options : {{ configure_options }}]]) +{% endif %} + +{% if long_description %} +help([[{{ long_description| textwrap(72)| join() }}]]) +{% endif %} +{% endblock %} + +{% block provides %} +{# Prepend the path I unlock as a provider of #} +{# services and set the families of services I provide #} +{% if has_modulepath_modifications %} +-- Services provided by the package +{% for name in provides %} +family("{{ name }}") +{% endfor %} + +-- Loading this module unlocks the path below unconditionally +{% for path in unlocked_paths %} +prepend_path("MODULEPATH", "{{ path }}") +{% endfor %} + +{# Try to see if missing providers have already #} +{# been loaded into the environment #} +{% if has_conditional_modifications %} +-- Try to load variables into path to see if providers are there +{% for name in missing %} +local {{ name }}_name = os.getenv("LMOD_{{ name|upper() }}_NAME") +local {{ name }}_version = os.getenv("LMOD_{{ name|upper() }}_VERSION") +{% endfor %} + +-- Change MODULEPATH based on the result of the tests above +{% for condition, path in conditionally_unlocked_paths %} +if {{ condition }} then + local t = pathJoin({{ path }}) + prepend_path("MODULEPATH", t) +end +{% endfor %} + +-- Set variables to notify the provider of the new services +{% for name in provides %} +setenv("LMOD_{{ name|upper() }}_NAME", "{{ name_part }}") +setenv("LMOD_{{ name|upper() }}_VERSION", "{{ version_part }}") +{% endfor %} +{% endif %} +{% endif %} +{% endblock %} + +{% block autoloads %} +{% for module in autoload %} +if not isloaded("{{ module }}") then +{% if verbose %} + LmodMessage("Autoloading {{ module }}") +{% endif %} + load("{{ module }}") +end +{% endfor %} +{% endblock %} + +{% block environment %} +{% for command_name, cmd in environment_modifications %} +{% if command_name == 'PrependPath' %} +prepend_path("{{ cmd.name }}", "{{ cmd.value }}") +{% elif command_name == 'AppendPath' %} +append_path("{{ cmd.name }}", "{{ cmd.value }}") +{% elif command_name == 'RemovePath' %} +remove_path("{{ cmd.name }}", "{{ cmd.value }}") +{% elif command_name == 'SetEnv' %} +setenv("{{ cmd.name }}", "{{ cmd.value }}") +{% elif command_name == 'UnsetEnv' %} +unsetenv("{{ cmd.name }}") +{% endif %} +{% endfor %} +{% endblock %} + +{% block footer %} +{# In case the module needs to be extended with custom LUA code #} +{% endblock %}
\ No newline at end of file diff --git a/templates/modules/modulefile.tcl b/templates/modules/modulefile.tcl new file mode 100644 index 0000000000..c3eb9db078 --- /dev/null +++ b/templates/modules/modulefile.tcl @@ -0,0 +1,82 @@ +#%Module1.0 +## Module file created by spack (https://github.com/LLNL/spack) on {{ timestamp }} +## +## {{ spec.short_spec }} +## +{% if configure_options %} +## Configure options: {{ configure_options }} +## +{% endif %} + + +{% block header %} +{% if short_description %} +module-whatis "{{ short_description }}" +{% endif %} + +{% if long_description %} +proc ModulesHelp { } { +{{ long_description| textwrap(72)| quote()| prepend_to_line('puts stderr ')| join() }} +} +{% endif %} +{% endblock %} + +{% block autoloads %} +{% for module in autoload %} +if ![ is-loaded {{ module }} ] {{ '{' }} +{% if verbose %} + puts stderr "Autoloading {{ module }}" +{% endif %} + module load {{ module }} +{{ '}' }} +{% endfor %} +{% endblock %} +{# #} +{% block prerequisite %} +{% for module in prerequisites %} +prereq {{ module }} +{% endfor %} +{% endblock %} +{# #} +{% block conflict %} +{% for name in conflicts %} +conflict {{ name }} +{% endfor %} +{% endblock %} + +{% block environment %} +{% for command_name, cmd in environment_modifications %} +{% if cmd.separator != ':' %} +{# A non-standard separator is required #} +{% if command_name == 'PrependPath' %} +prepend-path --delim "{{ cmd.separator }}" {{ cmd.name }} "{{ cmd.value }}" +{% elif command_name == 'AppendPath' %} +append-path --delim "{{ cmd.separator }}" {{ cmd.name }} "{{ cmd.value }}" +{% elif command_name == 'RemovePath' %} +remove-path --delim "{{ cmd.separator }}" {{ cmd.name }} "{{ cmd.value }}" +{% elif command_name == 'SetEnv' %} +setenv --delim "{{ cmd.separator }}" {{ cmd.name }} "{{ cmd.value }}" +{% elif command_name == 'UnsetEnv' %} +unsetenv {{ cmd.name }} +{% endif %} +{% else %} +{# We are using the usual separator #} +{% if command_name == 'PrependPath' %} +prepend-path {{ cmd.name }} "{{ cmd.value }}" +{% elif command_name == 'AppendPath' %} +append-path {{ cmd.name }} "{{ cmd.value }}" +{% elif command_name == 'RemovePath' %} +remove-path {{ cmd.name }} "{{ cmd.value }}" +{% elif command_name == 'SetEnv' %} +setenv {{ cmd.name }} "{{ cmd.value }}" +{% elif command_name == 'UnsetEnv' %} +unsetenv {{ cmd.name }} +{% endif %} +{# #} +{% endif %} +{% endfor %} +{% endblock %} + +{% block footer %} +{# In case he module needs to be extended with custom TCL code #} +{% endblock %}
\ No newline at end of file |