Consolidate most module code into spack.modules and spack.cmd.module
- One file with all the module classes (spack/modules.py) - Has an EnvModule superclass that does most of the work and consolidates common code - Subclasses have specializations for different module systems (TclModule, Dotkit) - One command (spack module) for all the types of modules to use - the one command is used by the scripts, only need to maintain in one place - has some subcommands for different module types, but they're handled mostly generically. - Consolidate zsh support into a single setup-env.sh script.
This commit is contained in:
		| @@ -75,6 +75,13 @@ for cmd in spack.cmd.commands: | ||||
|     module = spack.cmd.get_module(cmd) | ||||
|     subparser = subparsers.add_parser(cmd, help=module.description) | ||||
|     module.setup_parser(subparser) | ||||
|  | ||||
| # Just print help and exit if run with no arguments at all | ||||
| if len(sys.argv) == 1: | ||||
|     parser.print_help() | ||||
|     sys.exit(1) | ||||
|  | ||||
| # actually parse the args. | ||||
| args = parser.parse_args() | ||||
|  | ||||
| # Set up environment based on args. | ||||
|   | ||||
| @@ -58,8 +58,6 @@ | ||||
| stage_path     = join_path(var_path, "stage") | ||||
| install_path   = join_path(prefix, "opt") | ||||
| share_path     = join_path(prefix, "share", "spack") | ||||
| dotkit_path    = join_path(share_path, "dotkit") | ||||
| tclmodule_path    = join_path(share_path, "modules") | ||||
|  | ||||
| # | ||||
| # Set up the packages database. | ||||
|   | ||||
| @@ -23,28 +23,16 @@ | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| ############################################################################## | ||||
| import argparse | ||||
| import llnl.util.tty as tty | ||||
| import spack | ||||
| import spack.modules | ||||
|  | ||||
| description ="Add package to environment using module." | ||||
| description ="Add package to environment using modules." | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     """Parser is only constructed so that this prints a nice help | ||||
|        message with -h. """ | ||||
|     subparser.add_argument( | ||||
|         'spec', nargs=argparse.REMAINDER, help='Spec of package to add.') | ||||
|  | ||||
|  | ||||
| def print_help(): | ||||
|     tty.msg("Spack module support is not initialized.", | ||||
|             "", | ||||
|             "To use module with Spack, you must first run the command", | ||||
|             "below, which you can copy and paste:", | ||||
|             "", | ||||
|             "For bash:", | ||||
|             "    . %s/setup-env.bash" % spack.share_path, | ||||
|             "", | ||||
|             "ksh/csh/tcsh shells are currently unsupported", | ||||
|             "") | ||||
|         'spec', nargs=argparse.REMAINDER, help='Spec of package to load with modules.') | ||||
|  | ||||
|  | ||||
| def load(parser, args): | ||||
|     print_help() | ||||
|     spack.modules.print_help() | ||||
|   | ||||
| @@ -32,34 +32,43 @@ | ||||
| from llnl.util.filesystem import mkdirp | ||||
| 
 | ||||
| import spack.cmd | ||||
| import spack.hooks.dotkit | ||||
| import spack.modules | ||||
| from spack.util.string import * | ||||
| 
 | ||||
| from spack.spec import Spec | ||||
| 
 | ||||
| description ="Manipulate modules and dotkits." | ||||
| 
 | ||||
| module_types = { | ||||
|     'dotkit' : spack.modules.Dotkit, | ||||
|     'tcl'    : spack.modules.TclModule | ||||
| } | ||||
| 
 | ||||
| description ="Find dotkits for packages if they exist." | ||||
| 
 | ||||
| def setup_parser(subparser): | ||||
|     subparser.add_argument( | ||||
|         '--refresh', action='store_true', help='Regenerate all dotkits') | ||||
|     sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='module_command') | ||||
| 
 | ||||
|     subparser.add_argument( | ||||
|         'spec', nargs=argparse.REMAINDER, help='spec to find a dotkit for.') | ||||
|     refresh_parser = sp.add_parser('refresh', help='Regenerate all module files.') | ||||
| 
 | ||||
|     find_parser = sp.add_parser('find', help='Find module files for packages.') | ||||
|     find_parser.add_argument( | ||||
|         'module_type', help="Type of module to find file for. [" + '|'.join(module_types) + "]") | ||||
|     find_parser.add_argument('spec', nargs='+', help='spec to find a module file for.') | ||||
| 
 | ||||
| 
 | ||||
| def dotkit_find(parser, args): | ||||
|     if not args.spec: | ||||
|         parser.parse_args(['dotkit', '-h']) | ||||
| 
 | ||||
|     spec = spack.cmd.parse_specs(args.spec) | ||||
|     if len(spec) > 1: | ||||
| def module_find(mtype, spec_array): | ||||
|     specs = spack.cmd.parse_specs(spec_array) | ||||
|     if len(specs) > 1: | ||||
|         tty.die("You can only pass one spec.") | ||||
|     spec = spec[0] | ||||
|     spec = specs[0] | ||||
| 
 | ||||
|     if not spack.db.exists(spec.name): | ||||
|         tty.die("No such package: %s" % spec.name) | ||||
| 
 | ||||
|     specs = [s for s in spack.db.installed_package_specs() if s.satisfies(spec)] | ||||
|     if mtype not in module_types: | ||||
|         tty.die("Invalid module type: '%s'.  Options are " + comma_and(module_types)) | ||||
| 
 | ||||
|     specs = [s for s in spack.db.installed_package_specs() if s.satisfies(spec)] | ||||
|     if len(specs) == 0: | ||||
|         tty.die("No installed packages match spec %s" % spec) | ||||
| 
 | ||||
| @@ -69,31 +78,27 @@ def dotkit_find(parser, args): | ||||
|             sys.stderr.write(s.tree(color=True)) | ||||
|         sys.exit(1) | ||||
| 
 | ||||
|     match = specs[0] | ||||
|     if not os.path.isfile(spack.hooks.dotkit.dotkit_file(match.package)): | ||||
|     mt = module_types[mtype] | ||||
|     mod = mt(spec.package) | ||||
|     if not os.path.isfile(mod.file_name): | ||||
|         tty.die("No dotkit is installed for package %s." % spec) | ||||
| 
 | ||||
|     print match.format('$_$@$+$%@$=$#') | ||||
|     print mod.file_name | ||||
| 
 | ||||
| 
 | ||||
| def dotkit_refresh(parser, args): | ||||
|     query_specs = spack.cmd.parse_specs(args.spec) | ||||
| def module_refresh(): | ||||
|     shutil.rmtree(spack.dotkit_path, ignore_errors=False) | ||||
|     mkdirp(spack.dotkit_path) | ||||
| 
 | ||||
|     specs = spack.db.installed_package_specs() | ||||
|     if query_specs: | ||||
|         specs = [s for s in specs | ||||
|                  if any(s.satisfies(q) for q in query_specs)] | ||||
|     else: | ||||
|         shutil.rmtree(spack.dotkit_path, ignore_errors=False) | ||||
|         mkdirp(spack.dotkit_path) | ||||
| 
 | ||||
|     for spec in specs: | ||||
|         spack.hooks.dotkit.post_install(spec.package) | ||||
|         for mt in module_types: | ||||
|             mt(spec.package).write() | ||||
| 
 | ||||
| 
 | ||||
| def module(parser, args): | ||||
|     if args.module_command == 'refresh': | ||||
|         module_refresh() | ||||
| 
 | ||||
| def dotkit(parser, args): | ||||
|     if args.refresh: | ||||
|         dotkit_refresh(parser, args) | ||||
|     else: | ||||
|         dotkit_find(parser, args) | ||||
|     elif args.module_command == 'find': | ||||
|         module_find(args.module_type, args.spec) | ||||
| @@ -1,99 +0,0 @@ | ||||
| ############################################################################## | ||||
| # Copyright (c) 2013, Lawrence Livermore National Security, LLC. | ||||
| # Produced at the Lawrence Livermore National Laboratory. | ||||
| # | ||||
| # This file is part of Spack. | ||||
| # Written by David Beckingsale, david@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 sys | ||||
| import os | ||||
| import shutil | ||||
| import argparse | ||||
|  | ||||
| import llnl.util.tty as tty | ||||
| from llnl.util.lang import partition_list | ||||
| from llnl.util.filesystem import mkdirp | ||||
|  | ||||
| import spack.cmd | ||||
| import spack.hooks.tclmodule | ||||
| from spack.spec import Spec | ||||
|  | ||||
|  | ||||
| description ="Find modules for packages if they exist." | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     subparser.add_argument( | ||||
|         '--refresh', action='store_true', help='Regenerate all modules') | ||||
|  | ||||
|     subparser.add_argument( | ||||
|         'spec', nargs=argparse.REMAINDER, help='spec to find a module for.') | ||||
|  | ||||
|  | ||||
| def module_find(parser, args): | ||||
|     if not args.spec: | ||||
|         parser.parse_args(['tclmodule', '-h']) | ||||
|  | ||||
|     spec = spack.cmd.parse_specs(args.spec) | ||||
|     if len(spec) > 1: | ||||
|         tty.die("You can only pass one spec.") | ||||
|     spec = spec[0] | ||||
|  | ||||
|     if not spack.db.exists(spec.name): | ||||
|         tty.die("No such package: %s" % spec.name) | ||||
|  | ||||
|     specs = [s for s in spack.db.installed_package_specs() if s.satisfies(spec)] | ||||
|  | ||||
|     if len(specs) == 0: | ||||
|         tty.die("No installed packages match spec %s" % spec) | ||||
|  | ||||
|     if len(specs) > 1: | ||||
|         tty.error("Multiple matches for spec %s.  Choose one:" % spec) | ||||
|         for s in specs: | ||||
|             sys.stderr.write(s.tree(color=True)) | ||||
|         sys.exit(1) | ||||
|  | ||||
|     match = specs[0] | ||||
|     if not os.path.isfile(spack.hooks.tclmodule.module_file(match.package)): | ||||
|         tty.die("No module is installed for package %s." % spec) | ||||
|  | ||||
|     print match.format('$_$@$+$%@$=$#') | ||||
|  | ||||
|  | ||||
| def module_refresh(parser, args): | ||||
|     query_specs = spack.cmd.parse_specs(args.spec) | ||||
|  | ||||
|     specs = spack.db.installed_package_specs() | ||||
|     if query_specs: | ||||
|         specs = [s for s in specs | ||||
|                  if any(s.satisfies(q) for q in query_specs)] | ||||
|     else: | ||||
|         shutil.rmtree(spack.tclmodule_path, ignore_errors=False) | ||||
|         mkdirp(spack.tclmodule_path) | ||||
|  | ||||
|     for spec in specs: | ||||
|         spack.hooks.tclmodule.post_install(spec.package) | ||||
|  | ||||
|  | ||||
|  | ||||
| def tclmodule(parser, args): | ||||
|     if args.refresh: | ||||
|         module_refresh(parser, args) | ||||
|     else: | ||||
|         module_find(parser, args) | ||||
| @@ -23,14 +23,16 @@ | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| ############################################################################## | ||||
| import argparse | ||||
| import spack.cmd.tclmodule | ||||
| import spack.modules | ||||
|  | ||||
| description ="Remove package from environment using module." | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     """Parser is only constructed so that this prints a nice help | ||||
|        message with -h. """ | ||||
|     subparser.add_argument( | ||||
|         'spec', nargs=argparse.REMAINDER, help='Spec of package to remove.') | ||||
|         'spec', nargs=argparse.REMAINDER, help='Spec of package to unload with modules.') | ||||
|  | ||||
|  | ||||
| def unload(parser, args): | ||||
|     spack.cmd.load.print_help() | ||||
|     spack.modules.print_help() | ||||
|   | ||||
| @@ -23,14 +23,16 @@ | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| ############################################################################## | ||||
| import argparse | ||||
| import spack.cmd.use | ||||
| import spack.modules | ||||
|  | ||||
| description ="Remove package from environment using dotkit." | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     """Parser is only constructed so that this prints a nice help | ||||
|        message with -h. """ | ||||
|     subparser.add_argument( | ||||
|         'spec', nargs=argparse.REMAINDER, help='Spec of package to remove.') | ||||
|         'spec', nargs=argparse.REMAINDER, help='Spec of package to unuse with dotkit.') | ||||
|  | ||||
|  | ||||
| def unuse(parser, args): | ||||
|     spack.cmd.use.print_help() | ||||
|     spack.modules.print_help() | ||||
|   | ||||
| @@ -23,28 +23,16 @@ | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| ############################################################################## | ||||
| import argparse | ||||
| import llnl.util.tty as tty | ||||
| import spack | ||||
| import spack.modules | ||||
|  | ||||
| description ="Add package to environment using dotkit." | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     """Parser is only constructed so that this prints a nice help | ||||
|        message with -h. """ | ||||
|     subparser.add_argument( | ||||
|         'spec', nargs=argparse.REMAINDER, help='Spec of package to add.') | ||||
|  | ||||
|  | ||||
| def print_help(): | ||||
|     tty.msg("Spack dotkit support is not initialized.", | ||||
|             "", | ||||
|             "To use dotkit with Spack, you must first run the command", | ||||
|             "below, which you can copy and paste:", | ||||
|             "", | ||||
|             "For bash:", | ||||
|             "    . %s/setup-env.bash" % spack.share_path, | ||||
|             "", | ||||
|             "ksh/csh/tcsh shells are currently unsupported", | ||||
|             "") | ||||
|         'spec', nargs=argparse.REMAINDER, help='Spec of package to use with dotkit.') | ||||
|  | ||||
|  | ||||
| def use(parser, args): | ||||
|     print_help() | ||||
|     spack.modules.print_help() | ||||
|   | ||||
| @@ -22,62 +22,14 @@ | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| ############################################################################## | ||||
| import os | ||||
| import re | ||||
| import textwrap | ||||
| import shutil | ||||
| from contextlib import closing | ||||
|  | ||||
| from llnl.util.filesystem import join_path, mkdirp | ||||
|  | ||||
| import spack | ||||
|  | ||||
|  | ||||
| def dotkit_file(pkg): | ||||
|     dk_file_name = pkg.spec.format('$_$@$%@$+$=$#') + ".dk" | ||||
|     return join_path(spack.dotkit_path, dk_file_name) | ||||
| import spack.modules | ||||
|  | ||||
|  | ||||
| def post_install(pkg): | ||||
|     if not os.path.exists(spack.dotkit_path): | ||||
|         mkdirp(spack.dotkit_path) | ||||
|  | ||||
|     alterations = [] | ||||
|     for var, path in [ | ||||
|         ('PATH', pkg.prefix.bin), | ||||
|         ('MANPATH', pkg.prefix.man), | ||||
|         ('MANPATH', pkg.prefix.share_man), | ||||
|         ('LD_LIBRARY_PATH', pkg.prefix.lib), | ||||
|         ('LD_LIBRARY_PATH', pkg.prefix.lib64)]: | ||||
|  | ||||
|         if os.path.isdir(path): | ||||
|             alterations.append("dk_alter %s %s\n" % (var, path)) | ||||
|  | ||||
|     if not alterations: | ||||
|         return | ||||
|  | ||||
|     alterations.append("dk_alter CMAKE_PREFIX_PATH %s\n" % pkg.prefix) | ||||
|  | ||||
|     dk_file = dotkit_file(pkg) | ||||
|     with closing(open(dk_file, 'w')) as dk: | ||||
|         # Put everything in the spack category. | ||||
|         dk.write('#c spack\n') | ||||
|  | ||||
|         dk.write('#d %s\n' % pkg.spec.format("$_ $@")) | ||||
|  | ||||
|         # Recycle the description | ||||
|         if pkg.__doc__: | ||||
|             doc = re.sub(r'\s+', ' ', pkg.__doc__) | ||||
|             for line in textwrap.wrap(doc, 72): | ||||
|                 dk.write("#h %s\n" % line) | ||||
|  | ||||
|         # Write alterations | ||||
|         for alter in alterations: | ||||
|             dk.write(alter) | ||||
|     dk = spack.modules.Dotkit(pkg) | ||||
|     dk.write() | ||||
|  | ||||
|  | ||||
| def post_uninstall(pkg): | ||||
|     dk_file = dotkit_file(pkg) | ||||
|     if os.path.exists(dk_file): | ||||
|         shutil.rmtree(dk_file, ignore_errors=True) | ||||
|  | ||||
|     dk = spack.modules.Dotkit(pkg) | ||||
|     dk.remove() | ||||
|   | ||||
| @@ -22,65 +22,14 @@ | ||||
| # along with this program; if not, write to the Free Software Foundation, | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| ############################################################################## | ||||
| import os | ||||
| import re | ||||
| import textwrap | ||||
| import shutil | ||||
| from contextlib import closing | ||||
|  | ||||
| from llnl.util.filesystem import join_path, mkdirp | ||||
|  | ||||
| import spack | ||||
|  | ||||
|  | ||||
| def module_file(pkg): | ||||
|     m_file_name = pkg.spec.format('$_$@$%@$+$=$#') | ||||
|     return join_path(spack.tclmodule_path, m_file_name) | ||||
| import spack.modules | ||||
|  | ||||
|  | ||||
| def post_install(pkg): | ||||
|     if not os.path.exists(spack.module_path): | ||||
|         mkdirp(spack.module_path) | ||||
|  | ||||
|     alterations = [] | ||||
|     for var, path in [ | ||||
|         ('PATH', pkg.prefix.bin), | ||||
|         ('MANPATH', pkg.prefix.man), | ||||
|         ('MANPATH', pkg.prefix.share_man), | ||||
|         ('LD_LIBRARY_PATH', pkg.prefix.lib), | ||||
|         ('LD_LIBRARY_PATH', pkg.prefix.lib64)]: | ||||
|  | ||||
|         if os.path.isdir(path): | ||||
|             alterations.append("prepend-path %s \"%s\"\n" % (var, path)) | ||||
|  | ||||
|     if not alterations: | ||||
|         return | ||||
|  | ||||
|     alterations.append("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % pkg.prefix) | ||||
|  | ||||
|     m_file = module_file(pkg) | ||||
|     with closing(open(m_file, 'w')) as m: | ||||
|         # Put everything in the spack category. | ||||
|         m.write('#%Module1.0\n') | ||||
|  | ||||
|         m.write('module-whatis \"%s\"\n\n' % pkg.spec.format("$_ $@")) | ||||
|  | ||||
|         # Recycle the description | ||||
|         if pkg.__doc__: | ||||
|             m.write('proc ModulesHelp { } {\n') | ||||
|             doc = re.sub(r'\s+', ' ', pkg.__doc__) | ||||
|             doc = re.sub(r'"', '\"', pkg.__doc__) | ||||
|             m.write("puts stderr \"%s\"\n" % doc) | ||||
|             m.write('}\n\n') | ||||
|  | ||||
|  | ||||
|         # Write alterations | ||||
|         for alter in alterations: | ||||
|             m.write(alter) | ||||
|     dk = spack.modules.TclModule(pkg) | ||||
|     dk.write() | ||||
|  | ||||
|  | ||||
| def post_uninstall(pkg): | ||||
|     m_file = module_file(pkg) | ||||
|     if os.path.exists(m_file): | ||||
|         shutil.rmtree(m_file, ignore_errors=True) | ||||
|  | ||||
|     dk = spack.modules.TclModule(pkg) | ||||
|     dk.remove() | ||||
|   | ||||
							
								
								
									
										216
									
								
								lib/spack/spack/modules.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								lib/spack/spack/modules.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
| ############################################################################## | ||||
| # 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 | ||||
| ############################################################################## | ||||
| """This module contains code for creating environment modules, which | ||||
| can include dotkits, tcl modules, lmod, and others. | ||||
|  | ||||
| The various types of modules are installed by post-install hooks and | ||||
| removed after an uninstall by post-uninstall hooks.  This class | ||||
| consolidates the logic for creating an abstract description of the | ||||
| information that module systems need.  Currently that includes a | ||||
| number directories to be appended to paths in the user's environment: | ||||
|  | ||||
|   * /bin directories to be appended to PATH | ||||
|   * /lib* directories for LD_LIBRARY_PATH | ||||
|   * /man* and /share/man* directories for LD_LIBRARY_PATH | ||||
|   * the package prefix for CMAKE_PREFIX_PATH | ||||
|  | ||||
| This module also includes logic for coming up with unique names for | ||||
| the module files so that they can be found by the various | ||||
| shell-support files in $SPACK/share/spack/setup-env.*. | ||||
|  | ||||
| Each hook in hooks/ implements the logic for writing its specific type | ||||
| of module file. | ||||
| """ | ||||
| __all__ = ['EnvModule', 'Dotkit', 'TclModule'] | ||||
|  | ||||
| import os | ||||
| import re | ||||
| import textwrap | ||||
| import shutil | ||||
| from contextlib import closing | ||||
|  | ||||
| import llnl.util.tty as tty | ||||
| from llnl.util.filesystem import join_path, mkdirp | ||||
|  | ||||
| import spack | ||||
|  | ||||
| dotkit_path  = join_path(spack.share_path, "dotkit") | ||||
| tcl_mod_path = join_path(spack.share_path, "modules") | ||||
|  | ||||
| def print_help(): | ||||
|     """For use by commands to tell user how to activate shell support.""" | ||||
|  | ||||
|     tty.msg("Spack module/dotkit support is not initialized.", | ||||
|             "", | ||||
|             "To use dotkit or modules with Spack, you must first run", | ||||
|             "one of the commands below.  You can copy/paste them.", | ||||
|             "", | ||||
|             "For bash and zsh:", | ||||
|             "    . %s/setup-env.sh" % spack.share_path, | ||||
|             "", | ||||
|             "For csh and tcsh:", | ||||
|             "    source %s/setup-env.csh" % spack.share_path, | ||||
|             "") | ||||
|  | ||||
|  | ||||
| class EnvModule(object): | ||||
|     def __init__(self, pkg=None): | ||||
|         # category in the modules system | ||||
|         # TODO: come up with smarter category names. | ||||
|         self.category = "spack" | ||||
|  | ||||
|         # Descriptions for the module system's UI | ||||
|         self.short_description = "" | ||||
|         self.long_description = "" | ||||
|  | ||||
|         # dict pathname -> list of directories to be prepended to in | ||||
|         # the module file. | ||||
|         self._paths = None | ||||
|         self.pkg = pkg | ||||
|  | ||||
|  | ||||
|     @property | ||||
|     def paths(self): | ||||
|         if self._paths is None: | ||||
|             self._paths = {} | ||||
|  | ||||
|             def add_path(self, path_name, directory): | ||||
|                 path = self._paths.setdefault(path_name, []) | ||||
|                 path.append(directory) | ||||
|  | ||||
|             # Add paths if they exist. | ||||
|             for var, directory in [ | ||||
|                     ('PATH', self.pkg.prefix.bin), | ||||
|                     ('MANPATH', self.pkg.prefix.man), | ||||
|                     ('MANPATH', self.pkg.prefix.share_man), | ||||
|                     ('LD_LIBRARY_PATH', self.pkg.prefix.lib), | ||||
|                     ('LD_LIBRARY_PATH', self.pkg.prefix.lib64)]: | ||||
|  | ||||
|                 if os.path.isdir(directory): | ||||
|                     add_path(var, directory) | ||||
|  | ||||
|             # short description is just the package + version | ||||
|             # TODO: maybe packages can optionally provide it. | ||||
|             self.short_description = self.pkg.spec.format("$_ $@") | ||||
|  | ||||
|             # long description is the docstring with reduced whitespace. | ||||
|             if self.pkg.__doc__: | ||||
|                 self.long_description = re.sub(r'\s+', ' ', self.pkg.__doc__) | ||||
|  | ||||
|         return self._paths | ||||
|  | ||||
|  | ||||
|     def write(self): | ||||
|         """Write out a module file for this object.""" | ||||
|         module_dir = os.path.dirname(self.file_name) | ||||
|         if not os.path.exists(): | ||||
|             mkdirp(module_dir) | ||||
|  | ||||
|         # If there are no paths, no need for a dotkit. | ||||
|         if not self.paths: | ||||
|             return | ||||
|  | ||||
|         with closing(open(self.file_name)) as f: | ||||
|             self._write(f) | ||||
|  | ||||
|  | ||||
|     def _write(self, stream): | ||||
|         """To be implemented by subclasses.""" | ||||
|         raise NotImplementedError() | ||||
|  | ||||
|  | ||||
|     @property | ||||
|     def file_name(self): | ||||
|         """Subclasses should implement this to return the name of the file | ||||
|            where this module lives.""" | ||||
|         return self.pkg.spec.format('$_$@$%@$+$=$#') | ||||
|  | ||||
|  | ||||
|     def remove(self): | ||||
|         mod_file = self.file_name | ||||
|         if os.path.exists(mod_file): | ||||
|             shutil.rmtree(mod_file, ignore_errors=True) | ||||
|  | ||||
|  | ||||
| class Dotkit(EnvModule): | ||||
|     @property | ||||
|     def file_name(self): | ||||
|         spec = self.pkg.spec | ||||
|         return join_path(dotkit_path, spec.architecture, | ||||
|                          spec.format('$_$@$%@$+$#.dk')) | ||||
|  | ||||
|  | ||||
|     def _write(self, dk_file): | ||||
|         # Category | ||||
|         if self.category: | ||||
|             dk_file.write('#c %s\n' % self.category) | ||||
|  | ||||
|         # Short description | ||||
|         if self.short_description: | ||||
|             dk_file.write('#d %s\n' % self.short_description) | ||||
|  | ||||
|         # Long description | ||||
|         if self.long_description: | ||||
|             for line in textwrap.wrap(self.long_description, 72): | ||||
|                 dk_file.write("#h %s\n" % line) | ||||
|  | ||||
|         # Path alterations | ||||
|         for var, dirs in self.paths.items(): | ||||
|             for directory in dirs: | ||||
|                 dk_file.write("dk_alter %s %s\n" % (var, directory)) | ||||
|  | ||||
|         # Let CMake find this package. | ||||
|         dk_file.write("dk_alter CMAKE_PREFIX_PATH %s\n" % pkg.prefix) | ||||
|  | ||||
|  | ||||
| class TclModule(EnvModule): | ||||
|     @property | ||||
|     def file_name(self): | ||||
|         spec = self.pkg.spec | ||||
|         return join_path(tcl_mod_path, spec.architecture, | ||||
|                          spec.format('$_$@$%@$+$#')) | ||||
|  | ||||
|  | ||||
|     def _write(self, m_file): | ||||
|         # TODO: cateogry? | ||||
|         m_file.write('#%Module1.0\n') | ||||
|  | ||||
|         # Short description | ||||
|         if self.short_description: | ||||
|             m_file.write('module-whatis \"%s\"\n\n' % self.short_description) | ||||
|  | ||||
|         # Long description | ||||
|         if self.long_description: | ||||
|             m_file.write('proc ModulesHelp { } {\n') | ||||
|             doc = re.sub(r'"', '\"', self.long_description) | ||||
|             m_file.write("puts stderr \"%s\"\n" % doc) | ||||
|             m_file.write('}\n\n') | ||||
|  | ||||
|         # Path alterations | ||||
|         for var, dirs in self.paths.items(): | ||||
|             for directory in dirs: | ||||
|                 m_file.write("prepend-path %s \"%s\"\n" % (var, directory)) | ||||
|  | ||||
|         m_file.write("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % pkg.prefix) | ||||
| @@ -23,16 +23,13 @@ | ||||
| # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| ############################################################################## | ||||
| 
 | ||||
| # | ||||
| # | ||||
| # This file is part of Spack and sets up the spack environment for | ||||
| # bash shells.  This includes dotkit support as well as putting spack | ||||
| # in your path.  Source it like this: | ||||
| # bash and zsh.  This includes dotkit support, module support, and | ||||
| # it also puts spack in your path.  Source it like this: | ||||
| # | ||||
| #    . /path/to/spack/share/spack/setup-env.bash | ||||
| #    . /path/to/spack/share/spack/setup-env.sh | ||||
| # | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| ######################################################################## | ||||
| # This is a wrapper around the spack command that forwards calls to | ||||
| @@ -59,56 +56,46 @@ | ||||
| # spack dotfiles. | ||||
| ######################################################################## | ||||
| function spack { | ||||
|     _spack_subcommand=$1; shift | ||||
|     _spack_spec="$@" | ||||
|     _sp_subcommand=$1; shift | ||||
|     _sp_spec="$@" | ||||
| 
 | ||||
|     # Filter out use and unuse.  For any other commands, just run the | ||||
|     # command. | ||||
|     case $_spack_subcommand in | ||||
|         "use"|"unuse") | ||||
|     case $_sp_subcommand in | ||||
|         "use"|"unuse"|"load"|"unload") | ||||
|             # Shift any other args for use off before parsing spec. | ||||
|             _spack_use_args="" | ||||
|             _sp_module_args="" | ||||
|             if [[ "$1" =~ ^- ]]; then | ||||
|                 _spack_use_args="$1"; shift | ||||
|                 _spack_spec="$@" | ||||
|                 _sp_module_args="$1"; shift | ||||
|                 _sp_spec="$@" | ||||
|             fi | ||||
| 
 | ||||
|             # Here the user has run use or unuse with a spec.  Find a matching | ||||
|             # spec with a dotkit using spack dotkit, then use or unuse the | ||||
|             # result.  If spack dotkit comes back with an error, do nothing. | ||||
|             if _spack_full_spec=$(command spack dotkit $_spack_spec); then | ||||
|                 $_spack_subcommand $_spack_use_args $_spack_full_spec | ||||
|             fi | ||||
|             return | ||||
|             ;; | ||||
|         "load"|"unload") | ||||
|             # Shift any other args for module off before parsing spec. | ||||
|             _spack_module_args="" | ||||
|             if [[ "$1" =~ ^- ]]; then | ||||
|                 _spack_module_args="$1"; shift | ||||
|                 _spack_spec="$@" | ||||
|             fi | ||||
|             # Translate the parameter into pieces of a command. | ||||
|             # _sp_modtype is an arg to spack module find, and | ||||
|             # _sp_sh_cmd is the equivalent shell command. | ||||
|             case $_sp_subcommand in | ||||
|                 "use"|"unuse") | ||||
|                     _sp_modtype=dotkit | ||||
|                     _sp_sh_cmd=$_sp_subcommand | ||||
|                     ;; | ||||
|                 "load"|"unload") | ||||
|                     _sp_modtype=tcl | ||||
|                     _sp_sh_cmd="module $_sp_subcommand" | ||||
|                     ;; | ||||
|             esac | ||||
| 
 | ||||
|             # Here the user has run use or unuse with a spec.  Find a matching | ||||
|             # spec with a dotkit using spack dotkit, then use or unuse the | ||||
|             # result.  If spack dotkit comes back with an error, do nothing. | ||||
|             if _spack_full_spec=$(command spack tclmodule $_spack_spec); then | ||||
|                 $_spack_subcommand $_spack_module_args $_spack_full_spec | ||||
|             # spec using 'spack module find', then use the appropriate module | ||||
|             # tool's commands to add/remove the result from the environment. | ||||
|             # If spack module command comes back with an error, do nothing. | ||||
|             if _sp_full_spec=$(command spack module find $_sp_modtype $_sp_spec); then | ||||
|                 $_sp_sh_cmd $_sp_module_args $_sp_full_spec | ||||
|             fi | ||||
|             return | ||||
|             ;; | ||||
|         *) | ||||
|             command spack $_spack_subcommand "$@" | ||||
|             return | ||||
|             ;; | ||||
|             command spack $_sp_subcommand $_sp_spec | ||||
|     esac | ||||
| 
 | ||||
|     # If no args or -h, just run that command as well. | ||||
|     if [ -z "$1" -o "$1" = "-h" ]; then | ||||
|         command spack $_spack_subcommand -h | ||||
|         return | ||||
|     fi | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| ######################################################################## | ||||
| @@ -119,31 +106,45 @@ function spack { | ||||
| function _spack_pathadd { | ||||
|     # If no variable name is supplied, just append to PATH | ||||
|     # otherwise append to that variable. | ||||
|     varname=PATH | ||||
|     path="$1" | ||||
|     _pa_varname=PATH | ||||
|     _pa_new_path="$1" | ||||
|     if [ -n "$2" ]; then | ||||
|         varname="$1" | ||||
|         path="$2" | ||||
|         _pa_varname="$1" | ||||
|         _pa_new_path="$2" | ||||
|     fi | ||||
| 
 | ||||
|     # Do the actual prepending here. | ||||
|     eval "oldvalue=\"\$$varname\"" | ||||
|     if [ -d "$path" ] && [[ ":$oldvalue:" != *":$path:"* ]]; then | ||||
|         if [ -n "$oldvalue" ]; then | ||||
|             eval "export $varname=\"$path:$oldvalue\"" | ||||
|     eval "_pa_oldvalue=\$${_pa_varname}" | ||||
| 
 | ||||
|     if [ -d "$_pa_new_path" ] && [[ ":$_pa_oldvalue:" != *":$_pa_new_path:"* ]]; then | ||||
|         if [ -n "$_pa_oldvalue" ]; then | ||||
|             eval "export $_pa_varname=\"$_pa_new_path:$_pa_oldvalue\"" | ||||
|         else | ||||
|             export $varname="$path" | ||||
|             export $_pa_varname="$_pa_new_path" | ||||
|         fi | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| # | ||||
| # Figure out where this file is.  Below code needs to be portable to | ||||
| # bash and zsh. | ||||
| # | ||||
| _sp_source_file="${BASH_SOURCE[0]}"  # Bash's location of last sourced file. | ||||
| if [ -z "$_sp_source_file" ]; then | ||||
|     _sp_source_file="$0:A"           # zsh way to do it | ||||
|     if [[ "$_sp_source_file" == *":A" ]]; then | ||||
|         # Not zsh either... bail out with plain old $0, | ||||
|         # which WILL NOT work if this is sourced indirectly. | ||||
|         _sp_source_file="$0" | ||||
|     fi | ||||
| fi | ||||
| 
 | ||||
| # | ||||
| # Set up dotkit and path in the user environment | ||||
| # Set up modules and dotkit search paths in the user environment | ||||
| # | ||||
| _spack_share_dir="$(dirname ${BASH_SOURCE[0]})" | ||||
| _spack_prefix="$(dirname $(dirname $_spack_share_dir))" | ||||
| _sp_share_dir="$(dirname $_sp_source_file)" | ||||
| _sp_prefix="$(dirname $(dirname $_sp_share_dir))" | ||||
| 
 | ||||
| _spack_pathadd DK_NODE "$_spack_share_dir/dotkit" | ||||
| _spack_pathadd MODULEPATH "$_spack_share_dir/modules" | ||||
| _spack_pathadd PATH    "$_spack_prefix/bin" | ||||
| _spack_pathadd DK_NODE    "$_sp_share_dir/dotkit" | ||||
| _spack_pathadd MODULEPATH "$_sp_share_dir/modules" | ||||
| _spack_pathadd PATH       "$_sp_prefix/bin" | ||||
| @@ -1,122 +0,0 @@ | ||||
| ############################################################################## | ||||
| # Copyright (c) 2013, Lawrence Livermore National Security, LLC. | ||||
| # Produced at the Lawrence Livermore National Laboratory. | ||||
| # | ||||
| # This file is part of Spack. | ||||
| # Written by David Beckingsale, david@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 | ||||
| ############################################################################## | ||||
|  | ||||
| # | ||||
| # | ||||
| # This file is part of Spack and sets up the spack environment for zsh shells. | ||||
| # This includes dotkit and module support as well as putting spack | ||||
| # in your path.  Source it like this: | ||||
| # | ||||
| #    source /path/to/spack/share/spack/setup-env.zsh | ||||
| # | ||||
| # | ||||
|  | ||||
|  | ||||
| ######################################################################## | ||||
| # This is a wrapper around the spack command that forwards calls to | ||||
| # 'spack use' and 'spack unuse' to shell functions.  This in turn | ||||
| # allows them to be used to invoke dotkit functions. | ||||
| # | ||||
| # 'spack use' is smarter than just 'use' because it converts its | ||||
| # arguments into a unique spack spec that is then passed to dotkit | ||||
| # commands.  This allows the user to use packages without knowing all | ||||
| # their installation details. | ||||
| # | ||||
| # e.g., rather than requring a full spec for libelf, the user can type: | ||||
| # | ||||
| #     spack use libelf | ||||
| # | ||||
| # This will first find the available libelf dotkits and use a | ||||
| # matching one.  If there are two versions of libelf, the user would | ||||
| # need to be more specific, e.g.: | ||||
| # | ||||
| #     spack use libelf@0.8.13 | ||||
| # | ||||
| # This is very similar to how regular spack commands work and it | ||||
| # avoids the need to come up with a user-friendly naming scheme for | ||||
| # spack dotfiles. | ||||
| ######################################################################## | ||||
| function spack { | ||||
|     _spack_subcommand=${1}; shift | ||||
|     _spack_spec="$@" | ||||
|  | ||||
|     # Filter out use and unuse.  For any other commands, just run the | ||||
|     # command. | ||||
|     case ${_spack_subcommand} in | ||||
|         "use"|"unuse") | ||||
|             # Shift any other args for use off before parsing spec. | ||||
|             _spack_use_args="" | ||||
|             if [[ "$1" =~ ^- ]]; then | ||||
|                 _spack_use_args="$1"; shift | ||||
|                 _spack_spec="$@" | ||||
|             fi | ||||
|  | ||||
|             # Here the user has run use or unuse with a spec.  Find a matching | ||||
|             # spec with a dotkit using spack dotkit, then use or unuse the | ||||
|             # result.  If spack dotkit comes back with an error, do nothing. | ||||
|             if _spack_full_spec=$(command spack dotkit $_spack_spec); then | ||||
|                 $_spack_subcommand $_spack_use_args $_spack_full_spec | ||||
|             fi | ||||
|             return | ||||
|             ;; | ||||
|         "load"|"unload") | ||||
|             # Shift any other args for module off before parsing spec. | ||||
|             _spack_module_args="" | ||||
|             if [[ "$1" =~ ^- ]]; then | ||||
|                 _spack_module_args="$1"; shift | ||||
|                 _spack_spec="$@" | ||||
|             fi | ||||
|  | ||||
|             # Here the user has run use or unuse with a spec.  Find a matching | ||||
|             # spec with a dotkit using spack dotkit, then use or unuse the | ||||
|             # result.  If spack dotkit comes back with an error, do nothing. | ||||
|             if _spack_full_spec=$(command spack tclmodule ${_spack_spec}); then | ||||
|                 module ${_spack_subcommand} ${_spack_module_args} ${_spack_full_spec} | ||||
|             fi | ||||
|             return | ||||
|             ;; | ||||
|         *) | ||||
|             command spack $_spack_subcommand "$@" | ||||
|             return | ||||
|             ;; | ||||
|     esac | ||||
|  | ||||
|     # If no args or -h, just run that command as well. | ||||
|     if [ -z "$1" -o "$1" = "-h" ]; then | ||||
|         command spack $_spack_subcommand -h | ||||
|         return | ||||
|     fi | ||||
|  | ||||
| } | ||||
|  | ||||
| # | ||||
| # Set up dotkit and path in the user environment | ||||
| # | ||||
| _spack_share_dir="$(dirname $0:A)" | ||||
| _spack_prefix="$(dirname $(dirname ${_spack_share_dir}))" | ||||
|  | ||||
| export DK_NODE="$_spack_share_dir/dotkit:$DK_NODE" | ||||
| export MODULEPATH="$_spack_share_dir/modules:$MODULEPATH" | ||||
| export PATH="$_spack_prefix/bin:$PATH" | ||||
		Reference in New Issue
	
	Block a user
	 Todd Gamblin
					Todd Gamblin