-
Notifications
You must be signed in to change notification settings - Fork 219
Additional easyconfig parameters for documentation (REVIEW) #2113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 19 commits
b4098a3
836b61e
e5d642a
b7cf1f3
1f9a152
7a74752
d44debf
2e51c8c
2fa6786
503f4ed
9923d99
13245c8
7174fa9
68c7897
f2f0f3c
e3e3852
4a589db
502fdb9
c5db8a6
59bfa95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -157,7 +157,6 @@ | |
| 'exts_list': [[], 'List with extensions added to the base installation', EXTENSIONS], | ||
|
|
||
| # MODULES easyconfig parameters | ||
| 'whatis': [None, "List of brief (one line) package description entries", MODULES], | ||
| 'modaliases': [{}, "Aliases to be defined in module file", MODULES], | ||
| 'modextrapaths': [{}, "Extra paths to be prepended in module file", MODULES], | ||
| 'modextravars': [{}, "Extra environment variables to be added to module file", MODULES], | ||
|
|
@@ -171,6 +170,16 @@ | |
| 'include_modpath_extensions': [True, "Include $MODULEPATH extensions specified by module naming scheme.", MODULES], | ||
| 'recursive_module_unload': [False, 'Recursive unload of all dependencies when unloading module', MODULES], | ||
|
|
||
| # MODULES documentation easyconfig parameters | ||
| # (docurls is part of MANDATORY) | ||
| 'docpaths': [None, "List of paths of installed documentation relative to package root dir", MODULES], | ||
| 'examples': [None, "Free-form text with examples", MODULES], | ||
|
||
| 'site_contact': [None, "String/list of strings with site contacts for the package", MODULES], | ||
|
||
| 'upstream_contact': [None, ("String/list of strings with upstream contact addresses " | ||
|
||
| "(e.g., support e-mail, mailing list, bugtracker)"), MODULES], | ||
| 'usage': [None, "Usage instructions for the package", MODULES], | ||
|
||
| 'whatis': [None, "List of brief (one line) package description entries", MODULES], | ||
|
||
|
|
||
| # OTHER easyconfig parameters | ||
| 'buildstats': [None, "A list of dicts with build statistics", OTHER], | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,13 +36,14 @@ | |
| import re | ||
| import sys | ||
| import tempfile | ||
| from textwrap import wrap | ||
| from vsc.utils import fancylogger | ||
| from vsc.utils.missing import get_subclasses | ||
|
|
||
| from easybuild.tools.build_log import EasyBuildError | ||
| from easybuild.tools.config import build_option, get_module_syntax, install_path | ||
| from easybuild.tools.filetools import mkdir, read_file, remove_file, resolve_path, symlink, write_file | ||
| from easybuild.tools.modules import modules_tool | ||
| from easybuild.tools.filetools import convert_name, mkdir, read_file, remove_file, resolve_path, symlink, write_file | ||
| from easybuild.tools.modules import ROOT_ENV_VAR_NAME_PREFIX, modules_tool | ||
| from easybuild.tools.utilities import quote_str | ||
|
|
||
|
|
||
|
|
@@ -298,6 +299,100 @@ def use(self, paths, prefix=None, guarded=False): | |
| """ | ||
| raise NotImplementedError | ||
|
|
||
| def _generate_help_text(self): | ||
| """ | ||
| Generate syntax-independent help text used for `module help`. | ||
| """ | ||
|
|
||
| def generate_section(sec_name, sec_txt, strip=False): | ||
| """ | ||
| Generate section with given name and contents. | ||
| """ | ||
| if sec_txt: | ||
| if strip: | ||
| text = sec_txt.strip() | ||
| else: | ||
| text = sec_txt | ||
|
|
||
| return [ | ||
| '', | ||
| '', | ||
| sec_name, | ||
| '=' * len(sec_name), | ||
| text, | ||
| ] | ||
| else: | ||
| return [] | ||
|
||
|
|
||
| # General package description (mandatory) | ||
| lines = generate_section('Description', self.app.cfg['description'], strip=True) | ||
|
|
||
| # Package usage instructions (optional) | ||
| lines.extend(generate_section('Usage', self.app.cfg['usage'], strip=True)) | ||
|
|
||
| # Examples (optional) | ||
| lines.extend(generate_section('Examples', self.app.cfg['examples'], strip=True)) | ||
|
|
||
| # Additional information: homepage + (if available) doc paths/urls, upstream/site contact | ||
| lines.extend(generate_section("More information", " - Homepage: %s" % self.app.cfg['homepage'])) | ||
|
|
||
| docpaths = self.app.cfg['docpaths'] or [] | ||
| docurls = self.app.cfg['docurls'] or [] | ||
| if docpaths or docurls: | ||
| env_name = convert_name(self.app.name, upper=True) | ||
| root_envvar = ROOT_ENV_VAR_NAME_PREFIX + env_name | ||
|
||
| lines.extend([" - Documentation:"]) | ||
| lines.extend([" - $%s/%s" % (root_envvar,path) for path in docpaths]) | ||
|
||
| lines.extend([" - %s" % url for url in docurls]) | ||
|
|
||
| upstream = self.app.cfg['upstream_contact'] | ||
| if upstream: | ||
|
||
| if isinstance(upstream, list): | ||
| lines.extend([" - Upstream contacts:"]) | ||
| lines.extend([" - %s" % address for address in upstream]) | ||
|
||
| else: | ||
| lines.extend([" - Upstream contact: %s" % upstream]) | ||
|
|
||
| site_contact = self.app.cfg['site_contact'] | ||
| if site_contact: | ||
| if isinstance(site_contact, list): | ||
| lines.extend([" - Site contacts:"]) | ||
|
||
| lines.extend([" - %s" % address for address in site_contact]) | ||
|
||
| else: | ||
| lines.extend([" - Site contact: %s" % site_contact]) | ||
|
||
|
|
||
| # Extensions (if any) | ||
| extensions = self._generate_extension_list() | ||
| lines.extend(generate_section("Included extensions", '\n'.join(wrap(extensions, 78)))) | ||
|
|
||
| return '\n'.join(lines) | ||
|
|
||
| def _generate_whatis_lines(self): | ||
| """ | ||
| Generate a list of entries used for `module whatis`. | ||
| """ | ||
| whatis = self.app.cfg['whatis'] | ||
| if whatis is None: | ||
| # default: include 'whatis' statements with description, homepage, and extensions (if any) | ||
| whatis = [ | ||
| "Description: %s" % self.app.cfg['description'], | ||
| "Homepage: %s" % self.app.cfg['homepage'] | ||
| ] | ||
| extensions = self._generate_extension_list() | ||
| if extensions: | ||
| whatis.append("Extensions: %s" % extensions) | ||
|
|
||
| return whatis | ||
|
|
||
| def _generate_extension_list(self): | ||
|
||
| """ | ||
| Generate a string with a comma-separated list of extensions. | ||
| """ | ||
| exts_list = self.app.cfg['exts_list'] | ||
| extensions = ', '.join(sorted(['%s-%s' % (ext[0], ext[1]) for ext in exts_list], key=str.lower)) | ||
|
||
|
|
||
| return extensions | ||
|
|
||
|
|
||
| class ModuleGeneratorTcl(ModuleGenerator): | ||
| """ | ||
|
|
@@ -346,16 +441,9 @@ def get_description(self, conflict=True): | |
| """ | ||
| Generate a description. | ||
| """ | ||
| description = "%s - Homepage: %s" % (self.app.cfg['description'], self.app.cfg['homepage']) | ||
|
|
||
| whatis = self.app.cfg['whatis'] | ||
| if whatis is None: | ||
| # default: include single 'whatis' statement with description as contents | ||
| whatis = ["Description: %s" % description] | ||
|
|
||
| lines = [ | ||
| "proc ModulesHelp { } {", | ||
| " puts stderr { %(description)s", | ||
| " puts stderr {%s" % self._generate_help_text(), | ||
| " }", | ||
| '}', | ||
| '', | ||
|
|
@@ -376,10 +464,11 @@ def get_description(self, conflict=True): | |
| # - 'conflict Compiler/GCC/4.8.2/OpenMPI' for 'Compiler/GCC/4.8.2/OpenMPI/1.6.4' | ||
| lines.extend(['', "conflict %s" % os.path.dirname(self.app.short_mod_name)]) | ||
|
|
||
| whatis = self._generate_whatis_lines() | ||
|
||
| txt = '\n'.join(lines + ['']) % { | ||
| 'name': self.app.name, | ||
| 'version': self.app.version, | ||
| 'description': description, | ||
| 'description': self.app.cfg['description'], | ||
| 'whatis_lines': '\n'.join(["module-whatis {%s}" % line for line in whatis]), | ||
| 'installdir': self.app.installdir, | ||
| } | ||
|
|
@@ -601,16 +690,9 @@ def get_description(self, conflict=True): | |
| """ | ||
| Generate a description. | ||
| """ | ||
|
|
||
| description = "%s - Homepage: %s" % (self.app.cfg['description'], self.app.cfg['homepage']) | ||
|
|
||
| whatis = self.app.cfg['whatis'] | ||
| if whatis is None: | ||
| # default: include single 'whatis' statement with description as contents | ||
| whatis = ["Description: %s" % description] | ||
|
|
||
| lines = [ | ||
| "help([[%(description)s]])", | ||
| 'help([[%s' % self._generate_help_text(), | ||
| ']])', | ||
| '', | ||
| "%(whatis_lines)s", | ||
| '', | ||
|
|
@@ -624,10 +706,11 @@ def get_description(self, conflict=True): | |
| # conflict on 'name' part of module name (excluding version part at the end) | ||
| lines.extend(['', 'conflict("%s")' % os.path.dirname(self.app.short_mod_name)]) | ||
|
|
||
| whatis = self._generate_whatis_lines() | ||
|
||
| txt = '\n'.join(lines + ['']) % { | ||
| 'name': self.app.name, | ||
| 'version': self.app.version, | ||
| 'description': description, | ||
| 'description': self.app.cfg['description'], | ||
| 'whatis_lines': '\n'.join(["whatis([[%s]])" % line for line in whatis]), | ||
| 'installdir': self.app.installdir, | ||
| 'homepage': self.app.cfg['homepage'], | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,17 +74,27 @@ def setUp(self): | |
| def test_descr(self): | ||
| """Test generation of module description (which includes '#%Module' header).""" | ||
|
|
||
| gzip_txt = "gzip (GNU zip) is a popular data compression program as a replacement for compress " | ||
| gzip_txt += "- Homepage: http://www.gzip.org/" | ||
| gzip_txt = "gzip (GNU zip) is a popular data compression program as a replacement for compress" | ||
|
||
| homepage = "http://www.gzip.org/" | ||
|
|
||
| if self.MODULE_GENERATOR_CLASS == ModuleGeneratorTcl: | ||
| expected = '\n'.join([ | ||
| "proc ModulesHelp { } {", | ||
| " puts stderr { %s" % gzip_txt, | ||
| " puts stderr {", | ||
| '', | ||
| 'Description', | ||
| '===========', | ||
| "%s" % gzip_txt, | ||
| '', | ||
| '', | ||
| "More information", | ||
| "================", | ||
| " - Homepage: %s" % homepage, | ||
| " }", | ||
| "}", | ||
| '', | ||
| "module-whatis {Description: %s}" % gzip_txt, | ||
| "module-whatis {Homepage: %s}" % homepage, | ||
| '', | ||
| "set root %s" % self.modgen.app.installdir, | ||
| '', | ||
|
|
@@ -94,9 +104,20 @@ def test_descr(self): | |
|
|
||
| else: | ||
| expected = '\n'.join([ | ||
| 'help([[%s]])' % gzip_txt, | ||
| "help([[", | ||
| '', | ||
| 'Description', | ||
| '===========', | ||
| "%s" % gzip_txt, | ||
| '', | ||
| '', | ||
| "More information", | ||
| "================", | ||
| " - Homepage: %s" % homepage, | ||
| ']])', | ||
| '', | ||
| "whatis([[Description: %s]])" % gzip_txt, | ||
| "whatis([[Homepage: %s]])" % homepage, | ||
| '', | ||
| 'local root = "%s"' % self.modgen.app.installdir, | ||
| '', | ||
|
|
@@ -112,7 +133,16 @@ def test_descr(self): | |
| if self.MODULE_GENERATOR_CLASS == ModuleGeneratorTcl: | ||
| expected = '\n'.join([ | ||
| "proc ModulesHelp { } {", | ||
| " puts stderr { %s" % gzip_txt, | ||
| " puts stderr {", | ||
| '', | ||
| 'Description', | ||
| '===========', | ||
| "%s" % gzip_txt, | ||
| '', | ||
| '', | ||
| "More information", | ||
| "================", | ||
| " - Homepage: %s" % homepage, | ||
| " }", | ||
| "}", | ||
| '', | ||
|
|
@@ -127,7 +157,17 @@ def test_descr(self): | |
|
|
||
| else: | ||
| expected = '\n'.join([ | ||
| 'help([[%s]])' % gzip_txt, | ||
| "help([[", | ||
| '', | ||
| 'Description', | ||
| '===========', | ||
| "%s" % gzip_txt, | ||
| '', | ||
| '', | ||
| "More information", | ||
| "================", | ||
| " - Homepage: %s" % homepage, | ||
| ']])', | ||
| '', | ||
| "whatis([[foo]])", | ||
| "whatis([[bar]])", | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
List of paths for documentation relative to installation directory