-
Notifications
You must be signed in to change notification settings - Fork 219
support depends_on "load" statements in generated modules via --module-depends-on and module_depends_on easyconfig parameter #2391
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 6 commits
6f21c8f
fcb0e21
800bd90
63bda19
acf8cd1
2d9166a
8e02128
5e29702
279e4a3
631810d
4b1c65e
84094e8
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 |
|---|---|---|
|
|
@@ -172,6 +172,7 @@ | |
| 'moduleforceunload': [False, 'Force unload of all modules when loading the extension', MODULES], | ||
| 'moduleloadnoconflict': [False, "Don't check for conflicts, unload other versions instead ", MODULES], | ||
| 'recursive_module_unload': [False, 'Recursive unload of all dependencies when unloading module', MODULES], | ||
| 'recursive_module_unload_depends_on' : [False, 'Use depends_on (Lmod 7.6.1+) for dependencies in generated module', MODULES], | ||
|
||
|
|
||
| # MODULES documentation easyconfig parameters | ||
| # (docurls is part of MANDATORY) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -403,8 +403,9 @@ class ModuleGeneratorTcl(ModuleGenerator): | |
| MODULE_SHEBANG = '#%Module' | ||
| CHARS_TO_ESCAPE = ['$'] | ||
|
|
||
| LOAD_REGEX = r"^\s*module\s+load\s+(\S+)" | ||
| LOAD_REGEX = r"^\s*module\s+(?:load|depends-on)\s+(\S+)" | ||
| LOAD_TEMPLATE = "module load %(mod_name)s" | ||
| LOAD_TEMPLATE_DEPENDS_ON = "depends-on %(mod_name)s" | ||
|
|
||
| def check_group(self, group, error_msg=None): | ||
| """ | ||
|
|
@@ -505,9 +506,15 @@ def load_module(self, mod_name, recursive_unload=False, unload_modules=None): | |
| body = [] | ||
| if unload_modules: | ||
| body.extend([self.unload_module(m).strip() for m in unload_modules]) | ||
| body.append(self.LOAD_TEMPLATE) | ||
|
|
||
| if build_option('recursive_mod_unload') or recursive_unload: | ||
| load_template = self.LOAD_TEMPLATE | ||
| # Lmod 7.6.1+ supports depends-on which does this most nicely: | ||
| if (build_option('recursive_mod_unload_depends_on') or | ||
| recursive_unload == 'depends_on') and modules_tool().has_depends_on: | ||
|
||
| load_template = self.LOAD_TEMPLATE_DEPENDS_ON | ||
| body.append(load_template) | ||
|
|
||
| if (build_option('recursive_mod_unload') or recursive_unload or | ||
| load_template == self.LOAD_TEMPLATE_DEPENDS_ON): | ||
|
||
| # not wrapping the 'module load' with an is-loaded guard ensures recursive unloading; | ||
| # when "module unload" is called on the module in which the dependency "module load" is present, | ||
| # it will get translated to "module unload" | ||
|
|
@@ -668,8 +675,9 @@ class ModuleGeneratorLua(ModuleGenerator): | |
| MODULE_SHEBANG = '' # no 'shebang' in Lua module files | ||
| CHARS_TO_ESCAPE = [] | ||
|
|
||
| LOAD_REGEX = r'^\s*load\("(\S+)"' | ||
| LOAD_REGEX = r'^\s*(?:load|depends_on)\("(\S+)"' | ||
| LOAD_TEMPLATE = 'load("%(mod_name)s")' | ||
| LOAD_TEMPLATE_DEPENDS_ON = 'depends_on("%(mod_name)s")' | ||
|
|
||
| PATH_JOIN_TEMPLATE = 'pathJoin(root, "%s")' | ||
| UPDATE_PATH_TEMPLATE = '%s_path("%s", %s)' | ||
|
|
@@ -795,19 +803,28 @@ def load_module(self, mod_name, recursive_unload=False, unload_modules=None): | |
| body = [] | ||
| if unload_modules: | ||
| body.extend([self.unload_module(m).strip() for m in unload_modules]) | ||
| body.append(self.LOAD_TEMPLATE) | ||
|
|
||
| if build_option('recursive_mod_unload') or recursive_unload: | ||
| # wrapping the 'module load' with an 'is-loaded or mode == unload' | ||
| # guard ensures recursive unloading while avoiding load storms, | ||
| # when "module unload" is called on the module in which the | ||
| # depedency "module load" is present, it will get translated | ||
| # to "module unload" | ||
| # see also http://lmod.readthedocs.io/en/latest/210_load_storms.html | ||
| load_guard = 'isloaded("%(mod_name)s") or mode() == "unload"' | ||
|
|
||
| load_template = self.LOAD_TEMPLATE | ||
| # Lmod 7.6+ supports depends_on which does this most nicely: | ||
| if (build_option('recursive_mod_unload_depends_on') or | ||
| recursive_unload == 'depends_on') and modules_tool().has_depends_on: | ||
| load_template = self.LOAD_TEMPLATE_DEPENDS_ON | ||
|
|
||
| body.append(load_template) | ||
| if load_template == self.LOAD_TEMPLATE_DEPENDS_ON: | ||
| load_statement = body + [''] | ||
| else: | ||
| load_guard = 'isloaded("%(mod_name)s")' | ||
| load_statement = [self.conditional_statement(load_guard, '\n'.join(body), negative=True)] | ||
| if build_option('recursive_mod_unload') or recursive_unload: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make this
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, it really needs to be
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I overlooked that indeed, thanks or clarifying |
||
| # wrapping the 'module load' with an 'is-loaded or mode == unload' | ||
| # guard ensures recursive unloading while avoiding load storms, | ||
| # when "module unload" is called on the module in which the | ||
| # depedency "module load" is present, it will get translated | ||
| # to "module unload" | ||
| # see also http://lmod.readthedocs.io/en/latest/210_load_storms.html | ||
| load_guard = 'isloaded("%(mod_name)s") or mode() == "unload"' | ||
| else: | ||
| load_guard = 'isloaded("%(mod_name)s")' | ||
| load_statement = [self.conditional_statement(load_guard, '\n'.join(body), negative=True)] | ||
|
|
||
| return '\n'.join([''] + load_statement) % {'mod_name': mod_name} | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -209,8 +209,11 @@ def modules(self): | |
|
|
||
| def set_and_check_version(self): | ||
| """Get the module version, and check any requirements""" | ||
| lmod_depends_on_min = '7.6.1' | ||
| if self.COMMAND in MODULE_VERSION_CACHE: | ||
| self.version = MODULE_VERSION_CACHE[self.COMMAND] | ||
| self.has_depends_on = (isinstance(self, Lmod) and | ||
|
||
| StrictVersion(self.version) >= StrictVersion(lmod_depends_on_min)) | ||
| self.log.debug("Found cached version for %s: %s", self.COMMAND, self.version) | ||
| return | ||
|
|
||
|
|
@@ -259,6 +262,8 @@ def set_and_check_version(self): | |
| self.log.debug('Version %s matches requirement <= %s', self.version, self.MAX_VERSION) | ||
|
|
||
| MODULE_VERSION_CACHE[self.COMMAND] = self.version | ||
| self.has_depends_on = (isinstance(self, Lmod) and | ||
| StrictVersion(self.version) >= StrictVersion(lmod_depends_on_min)) | ||
|
||
|
|
||
| def check_cmd_avail(self): | ||
| """Check whether modules tool command is available.""" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -474,6 +474,8 @@ def config_options(self): | |
| None, 'store', None), | ||
| 'recursive-module-unload': ("Enable generating of modules that unload recursively.", | ||
| None, 'store_true', False), | ||
| 'recursive-module-unload-depends-on': ("Use depends_on (Lmod 7.6.1+) for dependencies in all generated modules.", | ||
|
||
| None, 'store_true', False), | ||
| 'repository': ("Repository type, using repositorypath", | ||
| 'choice', 'store', DEFAULT_REPOSITORY, sorted(avail_repositories().keys())), | ||
| 'repositorypath': (("Repository path, used by repository " | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -258,6 +258,17 @@ def test_load(self): | |
|
|
||
| init_config(build_options={'recursive_mod_unload': True}) | ||
| self.assertEqual(expected, self.modgen.load_module("mod_name")) | ||
|
|
||
| # Lmod 7.6+ depends-on | ||
| if self.modtool.has_depends_on: | ||
| expected = '\n'.join([ | ||
| '', | ||
| "depends-on mod_name", | ||
| '', | ||
| ]) | ||
| self.assertEqual(expected, self.modgen.load_module("mod_name", recursive_unload="depends_on")) | ||
| init_config(build_options={'recursive_mod_unload_depends_on': 'True'}) | ||
| self.assertEqual(expected, self.modgen.load_module("mod_name")) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also check the other case, with |
||
| else: | ||
| # default: guarded module load (which implies no recursive unloading) | ||
| expected = '\n'.join([ | ||
|
|
@@ -283,6 +294,17 @@ def test_load(self): | |
| init_config(build_options={'recursive_mod_unload': True}) | ||
| self.assertEqual(expected, self.modgen.load_module("mod_name")) | ||
|
|
||
| # Lmod 7.6+ depends_on | ||
| if self.modtool.has_depends_on: | ||
| expected = '\n'.join([ | ||
| '', | ||
| 'depends_on("mod_name")', | ||
| '', | ||
| ]) | ||
| self.assertEqual(expected, self.modgen.load_module("mod_name", recursive_unload="depends_on")) | ||
| init_config(build_options={'recursive_mod_unload_depends_on': 'True'}) | ||
| self.assertEqual(expected, self.modgen.load_module("mod_name")) | ||
|
|
||
| def test_unload(self): | ||
| """Test unload part in generated module file.""" | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1156,23 +1156,27 @@ def test_recursive_module_unload(self): | |
| eb_file = os.path.join(os.path.dirname(__file__), 'easyconfigs', 'test_ecs', 't', 'toy', 'toy-0.0-deps.eb') | ||
|
|
||
| # check log message with --skip for existing module | ||
| args = [ | ||
| eb_file, | ||
| '--sourcepath=%s' % self.test_sourcepath, | ||
| '--buildpath=%s' % self.test_buildpath, | ||
| '--installpath=%s' % self.test_installpath, | ||
| '--debug', | ||
| '--force', | ||
| '--recursive-module-unload', | ||
| ] | ||
| self.eb_main(args, do_build=True, verbose=True) | ||
|
|
||
| toy_module = os.path.join(self.test_installpath, 'modules', 'all', 'toy', '0.0-deps') | ||
| if get_module_syntax() == 'Lua': | ||
| toy_module += '.lua' | ||
| toy_module_txt = read_file(toy_module) | ||
| is_loaded_regex = re.compile(r"if { !\[is-loaded gompi/1.3.12\] }", re.M) | ||
| self.assertFalse(is_loaded_regex.search(toy_module_txt), "Recursive unloading is used: %s" % toy_module_txt) | ||
| lastargs = ['--recursive-module-unload'] | ||
| if self.modtool.has_depends_on: | ||
| lastargs.append(lastargs[0]+'-depends-on') | ||
|
||
| for lastarg in lastargs: | ||
| args = [ | ||
| eb_file, | ||
| '--sourcepath=%s' % self.test_sourcepath, | ||
| '--buildpath=%s' % self.test_buildpath, | ||
| '--installpath=%s' % self.test_installpath, | ||
| '--debug', | ||
| '--force', | ||
| lastarg, | ||
| ] | ||
| self.eb_main(args, do_build=True, verbose=True) | ||
|
|
||
| toy_module = os.path.join(self.test_installpath, 'modules', 'all', 'toy', '0.0-deps') | ||
| if get_module_syntax() == 'Lua': | ||
| toy_module += '.lua' | ||
| toy_module_txt = read_file(toy_module) | ||
| is_loaded_regex = re.compile(r"if { !\[is-loaded gompi/1.3.12\] }", re.M) | ||
| self.assertFalse(is_loaded_regex.search(toy_module_txt), "Recursive unloading is used: %s" % toy_module_txt) | ||
|
|
||
| def test_tmpdir(self): | ||
| """Test setting temporary directory to use by EasyBuild.""" | ||
|
|
||
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.
rather than introducing a magic value for the
recursive_unloadnamed argument ofload_module, why not add a new named argumentuse_depends_on?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.
Also, you should take the
build_optioninto account here (rather than inload_module)?