From 94c5c9667c786e05a635787e803d2cf7e22de73a Mon Sep 17 00:00:00 2001 From: David Beckingsale Date: Thu, 31 Jul 2014 13:42:34 -0700 Subject: Added inital module support --- lib/spack/spack/__init__.py | 1 + lib/spack/spack/cmd/load.py | 50 +++++++++++++++++++ lib/spack/spack/cmd/tclmodule.py | 99 ++++++++++++++++++++++++++++++++++++++ lib/spack/spack/cmd/unload.py | 36 ++++++++++++++ lib/spack/spack/hooks/tclmodule.py | 85 ++++++++++++++++++++++++++++++++ share/spack/setup-env.bash | 49 +++++++++++++------ 6 files changed, 304 insertions(+), 16 deletions(-) create mode 100644 lib/spack/spack/cmd/load.py create mode 100644 lib/spack/spack/cmd/tclmodule.py create mode 100644 lib/spack/spack/cmd/unload.py create mode 100644 lib/spack/spack/hooks/tclmodule.py diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index 50fe453cfb..bc24766510 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -59,6 +59,7 @@ 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, "tclmodule") # # Set up the packages database. diff --git a/lib/spack/spack/cmd/load.py b/lib/spack/spack/cmd/load.py new file mode 100644 index 0000000000..1389740df1 --- /dev/null +++ b/lib/spack/spack/cmd/load.py @@ -0,0 +1,50 @@ +############################################################################## +# 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 argparse +import llnl.util.tty as tty +import spack + +description ="Add package to environment using module." + +def setup_parser(subparser): + 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", + "") + + +def load(parser, args): + print_help() diff --git a/lib/spack/spack/cmd/tclmodule.py b/lib/spack/spack/cmd/tclmodule.py new file mode 100644 index 0000000000..da5c4f95fc --- /dev/null +++ b/lib/spack/spack/cmd/tclmodule.py @@ -0,0 +1,99 @@ +############################################################################## +# 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.tclmodules.tclmodules_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.module_path, ignore_errors=False) + mkdirp(spack.module_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) diff --git a/lib/spack/spack/cmd/unload.py b/lib/spack/spack/cmd/unload.py new file mode 100644 index 0000000000..df009c840b --- /dev/null +++ b/lib/spack/spack/cmd/unload.py @@ -0,0 +1,36 @@ +############################################################################## +# 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 argparse +import spack.cmd.tclmodule + +description ="Remove package from environment using module." + +def setup_parser(subparser): + subparser.add_argument( + 'spec', nargs=argparse.REMAINDER, help='Spec of package to remove.') + + +def unload(parser, args): + spack.cmd.load.print_help() diff --git a/lib/spack/spack/hooks/tclmodule.py b/lib/spack/spack/hooks/tclmodule.py new file mode 100644 index 0000000000..7df41e267c --- /dev/null +++ b/lib/spack/spack/hooks/tclmodule.py @@ -0,0 +1,85 @@ +############################################################################## +# 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 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.module_path, m_file_name) + + +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' % pkg.spec.format("$_ $@")) + + # Recycle the description + if pkg.__doc__: + m.write('proc ModulesHelp { } {\n') + doc = re.sub(r'\s+', ' ', pkg.__doc__) + m.write("puts str \"%s\"\n" % doc) + m.write('}') + + + # Write alterations + for alter in alterations: + m.write(alter) + + +def post_uninstall(pkg): + m_file = module_file(pkg) + if os.path.exists(m_file): + shutil.rmtree(m_file, ignore_errors=True) + diff --git a/share/spack/setup-env.bash b/share/spack/setup-env.bash index e22a259167..c23a5acab4 100755 --- a/share/spack/setup-env.bash +++ b/share/spack/setup-env.bash @@ -65,8 +65,38 @@ function spack { # Filter out use and unuse. For any other commands, just run the # command. case $_spack_subcommand in - "use") ;; - "unuse") ;; + "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 + $_spack_subcommand $_spack_module_args $_spack_full_spec + fi + return + ;; *) command spack $_spack_subcommand "$@" return @@ -79,19 +109,6 @@ function spack { return fi - # 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 } ######################################################################## @@ -128,5 +145,5 @@ _spack_share_dir="$(dirname ${BASH_SOURCE[0]})" _spack_prefix="$(dirname $(dirname $_spack_share_dir))" _spack_pathadd DK_NODE "$_spack_share_dir/dotkit" +_spack_pathadd MODULEPATH "$_spack_share_dir/modules" _spack_pathadd PATH "$_spack_prefix/bin" - -- cgit v1.2.3-70-g09d2 From 57ddbd282aa58b084c1e2f3a2204a6fb9e7ac6e4 Mon Sep 17 00:00:00 2001 From: David Beckingsale Date: Thu, 31 Jul 2014 14:56:45 -0700 Subject: Fixed up module support --- lib/spack/spack/__init__.py | 2 +- lib/spack/spack/cmd/tclmodule.py | 6 +- lib/spack/spack/hooks/tclmodule.py | 13 ++-- share/spack/setup-env.zsh | 122 +++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 10 deletions(-) create mode 100755 share/spack/setup-env.zsh diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index bc24766510..0b69ccde38 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -59,7 +59,7 @@ 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, "tclmodule") +tclmodule_path = join_path(share_path, "modules") # # Set up the packages database. diff --git a/lib/spack/spack/cmd/tclmodule.py b/lib/spack/spack/cmd/tclmodule.py index da5c4f95fc..270ee65b7b 100644 --- a/lib/spack/spack/cmd/tclmodule.py +++ b/lib/spack/spack/cmd/tclmodule.py @@ -70,7 +70,7 @@ def module_find(parser, args): sys.exit(1) match = specs[0] - if not os.path.isfile(spack.hooks.tclmodules.tclmodules_file(match.package)): + 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('$_$@$+$%@$=$#') @@ -84,8 +84,8 @@ def module_refresh(parser, args): specs = [s for s in specs if any(s.satisfies(q) for q in query_specs)] else: - shutil.rmtree(spack.module_path, ignore_errors=False) - mkdirp(spack.module_path) + shutil.rmtree(spack.tclmodule_path, ignore_errors=False) + mkdirp(spack.tclmodule_path) for spec in specs: spack.hooks.tclmodule.post_install(spec.package) diff --git a/lib/spack/spack/hooks/tclmodule.py b/lib/spack/spack/hooks/tclmodule.py index 7df41e267c..d9b4a43831 100644 --- a/lib/spack/spack/hooks/tclmodule.py +++ b/lib/spack/spack/hooks/tclmodule.py @@ -35,7 +35,7 @@ import spack def module_file(pkg): m_file_name = pkg.spec.format('$_$@$%@$+$=$#') - return join_path(spack.module_path, m_file_name) + return join_path(spack.tclmodule_path, m_file_name) def post_install(pkg): @@ -51,26 +51,27 @@ def post_install(pkg): ('LD_LIBRARY_PATH', pkg.prefix.lib64)]: if os.path.isdir(path): - alterations.append("prepend_path %s %s\n" % (var, 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) + 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' % pkg.spec.format("$_ $@")) + 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__) - m.write("puts str \"%s\"\n" % doc) - m.write('}') + doc = re.sub(r'"', '\"', pkg.__doc__) + m.write("puts stderr \"%s\"\n" % doc) + m.write('}\n\n') # Write alterations diff --git a/share/spack/setup-env.zsh b/share/spack/setup-env.zsh new file mode 100755 index 0000000000..9aba92818d --- /dev/null +++ b/share/spack/setup-env.zsh @@ -0,0 +1,122 @@ +############################################################################## +# 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" -- cgit v1.2.3-70-g09d2 From 221cf6acb932442f5964243eb3413a1d921920c8 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 16 Aug 2014 14:53:57 -0700 Subject: 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. --- bin/spack | 7 ++ lib/spack/spack/__init__.py | 2 - lib/spack/spack/cmd/dotkit.py | 99 ----------------- lib/spack/spack/cmd/load.py | 24 ++--- lib/spack/spack/cmd/module.py | 104 ++++++++++++++++++ lib/spack/spack/cmd/tclmodule.py | 99 ----------------- lib/spack/spack/cmd/unload.py | 8 +- lib/spack/spack/cmd/unuse.py | 8 +- lib/spack/spack/cmd/use.py | 22 +--- lib/spack/spack/hooks/dotkit.py | 58 +--------- lib/spack/spack/hooks/tclmodule.py | 61 +---------- lib/spack/spack/modules.py | 216 +++++++++++++++++++++++++++++++++++++ share/spack/setup-env.bash | 149 ------------------------- share/spack/setup-env.sh | 150 ++++++++++++++++++++++++++ share/spack/setup-env.zsh | 122 --------------------- 15 files changed, 508 insertions(+), 621 deletions(-) delete mode 100644 lib/spack/spack/cmd/dotkit.py create mode 100644 lib/spack/spack/cmd/module.py delete mode 100644 lib/spack/spack/cmd/tclmodule.py create mode 100644 lib/spack/spack/modules.py delete mode 100755 share/spack/setup-env.bash create mode 100755 share/spack/setup-env.sh delete mode 100755 share/spack/setup-env.zsh diff --git a/bin/spack b/bin/spack index c63178b191..f2b5d1d583 100755 --- a/bin/spack +++ b/bin/spack @@ -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. diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index 0b69ccde38..be38971c30 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -58,8 +58,6 @@ var_path = join_path(prefix, "var", "spack") 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. diff --git a/lib/spack/spack/cmd/dotkit.py b/lib/spack/spack/cmd/dotkit.py deleted file mode 100644 index 7a691ae5c0..0000000000 --- a/lib/spack/spack/cmd/dotkit.py +++ /dev/null @@ -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 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 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.dotkit -from spack.spec import Spec - - -description ="Find dotkits for packages if they exist." - -def setup_parser(subparser): - subparser.add_argument( - '--refresh', action='store_true', help='Regenerate all dotkits') - - subparser.add_argument( - 'spec', nargs=argparse.REMAINDER, help='spec to find a dotkit 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: - 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.dotkit.dotkit_file(match.package)): - tty.die("No dotkit is installed for package %s." % spec) - - print match.format('$_$@$+$%@$=$#') - - -def dotkit_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.dotkit_path, ignore_errors=False) - mkdirp(spack.dotkit_path) - - for spec in specs: - spack.hooks.dotkit.post_install(spec.package) - - - -def dotkit(parser, args): - if args.refresh: - dotkit_refresh(parser, args) - else: - dotkit_find(parser, args) diff --git a/lib/spack/spack/cmd/load.py b/lib/spack/spack/cmd/load.py index 1389740df1..5bc6b15784 100644 --- a/lib/spack/spack/cmd/load.py +++ b/lib/spack/spack/cmd/load.py @@ -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() diff --git a/lib/spack/spack/cmd/module.py b/lib/spack/spack/cmd/module.py new file mode 100644 index 0000000000..ead3b9abac --- /dev/null +++ b/lib/spack/spack/cmd/module.py @@ -0,0 +1,104 @@ +############################################################################## +# 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 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.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 +} + + +def setup_parser(subparser): + sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='module_command') + + 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 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 = specs[0] + + if not spack.db.exists(spec.name): + tty.die("No such package: %s" % spec.name) + + 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) + + 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) + + 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 mod.file_name + + +def module_refresh(): + shutil.rmtree(spack.dotkit_path, ignore_errors=False) + mkdirp(spack.dotkit_path) + + specs = spack.db.installed_package_specs() + for spec in specs: + for mt in module_types: + mt(spec.package).write() + + +def module(parser, args): + if args.module_command == 'refresh': + module_refresh() + + elif args.module_command == 'find': + module_find(args.module_type, args.spec) diff --git a/lib/spack/spack/cmd/tclmodule.py b/lib/spack/spack/cmd/tclmodule.py deleted file mode 100644 index 270ee65b7b..0000000000 --- a/lib/spack/spack/cmd/tclmodule.py +++ /dev/null @@ -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) diff --git a/lib/spack/spack/cmd/unload.py b/lib/spack/spack/cmd/unload.py index df009c840b..24e49b3f24 100644 --- a/lib/spack/spack/cmd/unload.py +++ b/lib/spack/spack/cmd/unload.py @@ -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() diff --git a/lib/spack/spack/cmd/unuse.py b/lib/spack/spack/cmd/unuse.py index a31e16d11a..7f0b384ea0 100644 --- a/lib/spack/spack/cmd/unuse.py +++ b/lib/spack/spack/cmd/unuse.py @@ -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() diff --git a/lib/spack/spack/cmd/use.py b/lib/spack/spack/cmd/use.py index 10a0644df8..4990fea2f8 100644 --- a/lib/spack/spack/cmd/use.py +++ b/lib/spack/spack/cmd/use.py @@ -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() diff --git a/lib/spack/spack/hooks/dotkit.py b/lib/spack/spack/hooks/dotkit.py index 10b7732353..0f46f6a2fc 100644 --- a/lib/spack/spack/hooks/dotkit.py +++ b/lib/spack/spack/hooks/dotkit.py @@ -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() diff --git a/lib/spack/spack/hooks/tclmodule.py b/lib/spack/spack/hooks/tclmodule.py index d9b4a43831..d93da3177e 100644 --- a/lib/spack/spack/hooks/tclmodule.py +++ b/lib/spack/spack/hooks/tclmodule.py @@ -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() diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py new file mode 100644 index 0000000000..8ac7e470cb --- /dev/null +++ b/lib/spack/spack/modules.py @@ -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) diff --git a/share/spack/setup-env.bash b/share/spack/setup-env.bash deleted file mode 100755 index c23a5acab4..0000000000 --- a/share/spack/setup-env.bash +++ /dev/null @@ -1,149 +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 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 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: -# -# . /path/to/spack/share/spack/setup-env.bash -# -# - - -######################################################################## -# 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 - $_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 - -} - -######################################################################## -# Prepends directories to path, if they exist. -# pathadd /path/to/dir # add to PATH -# or pathadd OTHERPATH /path/to/dir # add to OTHERPATH -######################################################################## -function _spack_pathadd { - # If no variable name is supplied, just append to PATH - # otherwise append to that variable. - varname=PATH - path="$1" - if [ -n "$2" ]; then - varname="$1" - 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\"" - else - export $varname="$path" - fi - fi -} - - -# -# Set up dotkit and path in the user environment -# -_spack_share_dir="$(dirname ${BASH_SOURCE[0]})" -_spack_prefix="$(dirname $(dirname $_spack_share_dir))" - -_spack_pathadd DK_NODE "$_spack_share_dir/dotkit" -_spack_pathadd MODULEPATH "$_spack_share_dir/modules" -_spack_pathadd PATH "$_spack_prefix/bin" diff --git a/share/spack/setup-env.sh b/share/spack/setup-env.sh new file mode 100755 index 0000000000..7cadc6f202 --- /dev/null +++ b/share/spack/setup-env.sh @@ -0,0 +1,150 @@ +############################################################################## +# 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 file is part of Spack and sets up the spack environment for +# 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.sh +# + +######################################################################## +# 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 { + _sp_subcommand=$1; shift + _sp_spec="$@" + + # Filter out use and unuse. For any other commands, just run the + # command. + case $_sp_subcommand in + "use"|"unuse"|"load"|"unload") + # Shift any other args for use off before parsing spec. + _sp_module_args="" + if [[ "$1" =~ ^- ]]; then + _sp_module_args="$1"; shift + _sp_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 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 $_sp_subcommand $_sp_spec + esac +} + +######################################################################## +# Prepends directories to path, if they exist. +# pathadd /path/to/dir # add to PATH +# or pathadd OTHERPATH /path/to/dir # add to OTHERPATH +######################################################################## +function _spack_pathadd { + # If no variable name is supplied, just append to PATH + # otherwise append to that variable. + _pa_varname=PATH + _pa_new_path="$1" + if [ -n "$2" ]; then + _pa_varname="$1" + _pa_new_path="$2" + fi + + # Do the actual prepending here. + 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 $_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 modules and dotkit search paths in the user environment +# +_sp_share_dir="$(dirname $_sp_source_file)" +_sp_prefix="$(dirname $(dirname $_sp_share_dir))" + +_spack_pathadd DK_NODE "$_sp_share_dir/dotkit" +_spack_pathadd MODULEPATH "$_sp_share_dir/modules" +_spack_pathadd PATH "$_sp_prefix/bin" diff --git a/share/spack/setup-env.zsh b/share/spack/setup-env.zsh deleted file mode 100755 index 9aba92818d..0000000000 --- a/share/spack/setup-env.zsh +++ /dev/null @@ -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" -- cgit v1.2.3-70-g09d2 From 776560f8ce9f464548cc116117c6a58b686448ff Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 16 Aug 2014 14:58:15 -0700 Subject: Add csh/tcsh support for modules - csh scripting is a GIANT pain in the ass - hopefully the thin script layer doesn't get much more complex. --- lib/spack/spack/modules.py | 1 + share/spack/csh/spack.csh | 71 +++++++++++++++++++++++++++++++++++++++ share/spack/csh/spack_pathadd.csh | 23 +++++++++++++ share/spack/setup-env.csh | 46 +++++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 share/spack/csh/spack.csh create mode 100644 share/spack/csh/spack_pathadd.csh create mode 100755 share/spack/setup-env.csh diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 8ac7e470cb..0f8c417793 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -71,6 +71,7 @@ def print_help(): " . %s/setup-env.sh" % spack.share_path, "", "For csh and tcsh:", + " setenv SPACK_ROOT %s" % spack.prefix, " source %s/setup-env.csh" % spack.share_path, "") diff --git a/share/spack/csh/spack.csh b/share/spack/csh/spack.csh new file mode 100644 index 0000000000..2f6b96f4eb --- /dev/null +++ b/share/spack/csh/spack.csh @@ -0,0 +1,71 @@ +######################################################################## +# 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. +######################################################################## +# Set up args -- we want a subcommand and a spec. +set _sp_subcommand=""; +set _sp_spec=""; +[ $#_sp_args -gt 0 ] && set _sp_subcommand = ($_sp_args[1]); +[ $#_sp_args -gt 1 ] && set _sp_spec = ($_sp_args[2-]); + +# Figure out what type of module we're running here. +set _sp_modtype = ""; +switch ($_sp_subcommand) +case use: +case unuse: +case load: +case unload: + set _sp_module_args="""" + if ( "$_sp_spec" =~ "-*" ) then + set _sp_module_args = $_sp_spec[1] + shift _sp_spec + set _sp_spec = ($_sp_spec) + endif + # 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. + switch ($_sp_subcommand) + case use: + case unuse: + set _sp_modtype = dotkit + set _sp_sh_cmd = $_sp_subcommand + breaksw + case load: + case unload: + set _sp_modtype = tcl + set _sp_sh_cmd = ( module $_sp_subcommand ) + breaksw + endsw + + # Here the user has run use or unuse with a spec. Find a matching + # 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 { set _sp_full_spec = `command spack module find $_sp_modtype $_sp_spec` } then + echo $_sp_sh_cmd $_sp_module_args $_sp_full_spec + endif +default: + command spack $_sp_args +endsw + +unset _sp_args _sp_full_spec _sp_modtype _sp_module_args _sp_sh_cmd _sp_spec _sp_subcommand diff --git a/share/spack/csh/spack_pathadd.csh b/share/spack/csh/spack_pathadd.csh new file mode 100644 index 0000000000..1e0800c5f3 --- /dev/null +++ b/share/spack/csh/spack_pathadd.csh @@ -0,0 +1,23 @@ +######################################################################## +# Prepends directories to path, if they exist. +# pathadd /path/to/dir # add to PATH +# or pathadd OTHERPATH /path/to/dir # add to OTHERPATH +######################################################################## +# If no variable name is supplied, just append to PATH +# otherwise append to that variable. +set _pa_varname = PATH; +set _pa_new_path = $_pa_args[1]; +[ $#_pa_args -gt 1 ] && set _pa_varname = $_pa_args[1] && set _pa_new_path = $_pa_args[2]; + +# Check whether the variable is set yet. +set _pa_old_value = "" +eval set _pa_set = '$?'$_pa_varname +[ $_pa_set -eq 1 ] && eval set _pa_old_value='$'$_pa_varname; + +# Do the actual prepending here, if it is a dir and not already in the path +if ( -d $_pa_new_path && \:$_pa_old_value\: !~ *\:$_pa_new_path\:* ) then + [ -n "$_pa_old_value" ] && setenv $_pa_varname $_pa_new_path\:$_pa_old_value + [ -z "$_pa_old_value" ] && setenv $_pa_varname $_pa_new_path +endif + +unset _pa_args _pa_new_path _pa_old_value _pa_set _pa_varname diff --git a/share/spack/setup-env.csh b/share/spack/setup-env.csh new file mode 100755 index 0000000000..e3243e40b2 --- /dev/null +++ b/share/spack/setup-env.csh @@ -0,0 +1,46 @@ +############################################################################## +# 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 file is part of Spack and sets up the spack environment for +# csh and tcsh. This includes dotkit support, module support, and +# it also puts spack in your path. Source it like this: +# +# setenv SPACK_ROOT /path/to/spack +# source $SPACK_ROOT/share/spack/setup-env.csh +# +if ($?SPACK_ROOT) then + set _spack_source_file = $SPACK_ROOT/share/spack/setup-env.csh + set _spack_share_dir = $SPACK_ROOT/share/spack + + # Command aliases point at separate source files + alias spack 'set _sp_args = (\!*); source $_spack_share_dir/csh/spack.csh' + alias _spack_pathadd 'set _pa_args = (\!*) && source $_spack_share_dir/csh/spack_pathadd.csh' + + # Set up modules and dotkit search paths in the user environment + _spack_pathadd DK_NODE "$_spack_share_dir/dotkit" + _spack_pathadd MODULEPATH "$_spack_share_dir/modules" + _spack_pathadd PATH "$SPACK_ROOT/bin" +endif -- cgit v1.2.3-70-g09d2 From 22bec329c1824ecd3271fffcef9ff793363ba93d Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 16 Aug 2014 22:22:34 -0700 Subject: Bugfixes, more consolidation of modules code. - specific module classes use __metaclass__ to register themselves. - bugfixes in module writing. --- .gitignore | 1 + lib/spack/spack/cmd/module.py | 25 +++++++++++++------------ lib/spack/spack/modules.py | 35 ++++++++++++++++++++++++++--------- lib/spack/spack/packages.py | 10 ++++++++++ 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index d6e0d3e60c..828fb04e7d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ .idea /etc/spackconfig /share/spack/dotkit +/share/spack/modules diff --git a/lib/spack/spack/cmd/module.py b/lib/spack/spack/cmd/module.py index ead3b9abac..af5a68923b 100644 --- a/lib/spack/spack/cmd/module.py +++ b/lib/spack/spack/cmd/module.py @@ -32,18 +32,13 @@ from llnl.util.lang import partition_list from llnl.util.filesystem import mkdirp import spack.cmd -import spack.modules +from spack.modules import module_types 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 -} - def setup_parser(subparser): sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='module_command') @@ -87,13 +82,19 @@ def module_find(mtype, spec_array): def module_refresh(): - shutil.rmtree(spack.dotkit_path, ignore_errors=False) - mkdirp(spack.dotkit_path) + """Regenerate all module files for installed packages known to + spack (some packages may no longer exist).""" + specs = [s for s in spack.db.installed_known_package_specs()] + + for name, cls in module_types.items(): + tty.msg("Regenerating %s module files." % name) + if os.path.isdir(cls.path): + shutil.rmtree(cls.path, ignore_errors=False) + mkdirp(cls.path) + for spec in specs: + tty.debug(" Writing file for %s." % spec) + cls(spec.package).write() - specs = spack.db.installed_package_specs() - for spec in specs: - for mt in module_types: - mt(spec.package).write() def module(parser, args): diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 0f8c417793..596308f801 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -56,8 +56,10 @@ 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") +"""Registry of all types of modules. Entries created by EnvModule's + metaclass.""" +module_types = {} + def print_help(): """For use by commands to tell user how to activate shell support.""" @@ -77,6 +79,15 @@ def print_help(): class EnvModule(object): + name = 'env_module' + + class __metaclass__(type): + def __init__(cls, name, bases, dict): + type.__init__(cls, name, bases, dict) + if cls.name != 'env_module': + module_types[cls.name] = cls + + def __init__(self, pkg=None): # category in the modules system # TODO: come up with smarter category names. @@ -97,7 +108,7 @@ class EnvModule(object): if self._paths is None: self._paths = {} - def add_path(self, path_name, directory): + def add_path(path_name, directory): path = self._paths.setdefault(path_name, []) path.append(directory) @@ -126,14 +137,14 @@ class EnvModule(object): def write(self): """Write out a module file for this object.""" module_dir = os.path.dirname(self.file_name) - if not os.path.exists(): + if not os.path.exists(module_dir): 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: + with closing(open(self.file_name, 'w')) as f: self._write(f) @@ -156,10 +167,13 @@ class EnvModule(object): class Dotkit(EnvModule): + name = 'dotkit' + path = join_path(spack.share_path, "dotkit") + @property def file_name(self): spec = self.pkg.spec - return join_path(dotkit_path, spec.architecture, + return join_path(Dotkit.path, spec.architecture, spec.format('$_$@$%@$+$#.dk')) @@ -183,14 +197,17 @@ class Dotkit(EnvModule): 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) + dk_file.write("dk_alter CMAKE_PREFIX_PATH %s\n" % self.pkg.prefix) class TclModule(EnvModule): + name = 'tcl' + path = join_path(spack.share_path, "modules") + @property def file_name(self): spec = self.pkg.spec - return join_path(tcl_mod_path, spec.architecture, + return join_path(TclModule.path, spec.architecture, spec.format('$_$@$%@$+$#')) @@ -214,4 +231,4 @@ class TclModule(EnvModule): 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) + m_file.write("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % self.pkg.prefix) diff --git a/lib/spack/spack/packages.py b/lib/spack/spack/packages.py index 00834c95d5..f9840a5c05 100644 --- a/lib/spack/spack/packages.py +++ b/lib/spack/spack/packages.py @@ -118,6 +118,16 @@ class PackageDB(object): return spack.install_layout.all_specs() + def installed_known_package_specs(self): + """Read installed package names straight from the install + directory layout, but return only specs for which the + package is known to this version of spack. + """ + for spec in spack.install_layout.all_specs(): + if self.exists(spec.name): + yield spec + + @memoized def all_package_names(self): """Generator function for all packages. This looks for -- cgit v1.2.3-70-g09d2 From b601fd08caf21b5fc11e6998a5ebd20a04ac57ad Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 17 Aug 2014 01:41:32 -0700 Subject: Bugfixes for csh environment modules. --- lib/spack/spack/cmd/module.py | 15 +++++++++------ lib/spack/spack/modules.py | 27 ++++++++++++++++++++------- share/spack/csh/spack.csh | 42 +++++++++++++++++++++++++++++++----------- share/spack/setup-env.csh | 5 +++-- share/spack/setup-env.sh | 22 ++++++++++++++++++---- 5 files changed, 81 insertions(+), 30 deletions(-) diff --git a/lib/spack/spack/cmd/module.py b/lib/spack/spack/cmd/module.py index af5a68923b..4f6de18532 100644 --- a/lib/spack/spack/cmd/module.py +++ b/lib/spack/spack/cmd/module.py @@ -52,14 +52,16 @@ def setup_parser(subparser): def module_find(mtype, spec_array): + """Look at all installed packages and see if the spec provided + matches any. If it does, check whether there is a module file + of type there, and print out the name that the user + should type to use that package's module. + """ specs = spack.cmd.parse_specs(spec_array) if len(specs) > 1: tty.die("You can only pass one spec.") spec = specs[0] - if not spack.db.exists(spec.name): - tty.die("No such package: %s" % spec.name) - if mtype not in module_types: tty.die("Invalid module type: '%s'. Options are " + comma_and(module_types)) @@ -74,11 +76,12 @@ def module_find(mtype, spec_array): sys.exit(1) mt = module_types[mtype] - mod = mt(spec.package) + mod = mt(specs[0].package) if not os.path.isfile(mod.file_name): - tty.die("No dotkit is installed for package %s." % spec) + tty.error( mod.file_name) + tty.die("No %s module is installed for package %s." % (mtype, spec)) - print mod.file_name + print mod.use_name def module_refresh(): diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py index 596308f801..3f56208f5b 100644 --- a/lib/spack/spack/modules.py +++ b/lib/spack/spack/modules.py @@ -157,7 +157,14 @@ class EnvModule(object): def file_name(self): """Subclasses should implement this to return the name of the file where this module lives.""" - return self.pkg.spec.format('$_$@$%@$+$=$#') + raise NotImplementedError() + + + @property + def use_name(self): + """Subclasses should implement this to return the name the + module command uses to refer to the package.""" + raise NotImplementedError() def remove(self): @@ -172,9 +179,12 @@ class Dotkit(EnvModule): @property def file_name(self): - spec = self.pkg.spec - return join_path(Dotkit.path, spec.architecture, - spec.format('$_$@$%@$+$#.dk')) + return join_path(Dotkit.path, self.pkg.spec.architecture, + self.pkg.spec.format('$_$@$%@$+$#.dk')) + + @property + def use_name(self): + return self.pkg.spec.format('$_$@$%@$+$#') def _write(self, dk_file): @@ -206,9 +216,12 @@ class TclModule(EnvModule): @property def file_name(self): - spec = self.pkg.spec - return join_path(TclModule.path, spec.architecture, - spec.format('$_$@$%@$+$#')) + return join_path(TclModule.path, self.pkg.spec.architecture, self.use_name) + + + @property + def use_name(self): + return self.pkg.spec.format('$_$@$%@$+$#') def _write(self, m_file): diff --git a/share/spack/csh/spack.csh b/share/spack/csh/spack.csh index 2f6b96f4eb..169e9878bf 100644 --- a/share/spack/csh/spack.csh +++ b/share/spack/csh/spack.csh @@ -22,14 +22,28 @@ # avoids the need to come up with a user-friendly naming scheme for # spack dotfiles. ######################################################################## +# accumulate initial flags for main spack command +set _sp_flags = "" +while ( $#_sp_args > 0 ) + if ( "$_sp_args[1]" !~ "-*" ) break + set _sp_flags = "$_sp_flags $_sp_args[1]" + shift _sp_args +end + +# h and V flags don't require further output parsing. +if ( "$_sp_flags" =~ *h* || "$_sp_flags" =~ *V* ) then + \spack $_sp_flags $_sp_args + goto _sp_end +endif + # Set up args -- we want a subcommand and a spec. -set _sp_subcommand=""; -set _sp_spec=""; -[ $#_sp_args -gt 0 ] && set _sp_subcommand = ($_sp_args[1]); -[ $#_sp_args -gt 1 ] && set _sp_spec = ($_sp_args[2-]); +set _sp_subcommand="" +set _sp_spec="" +[ $#_sp_args -gt 0 ] && set _sp_subcommand = ($_sp_args[1]) +[ $#_sp_args -gt 1 ] && set _sp_spec = ($_sp_args[2-]) # Figure out what type of module we're running here. -set _sp_modtype = ""; +set _sp_modtype = "" switch ($_sp_subcommand) case use: case unuse: @@ -48,12 +62,12 @@ case unload: case use: case unuse: set _sp_modtype = dotkit - set _sp_sh_cmd = $_sp_subcommand + set _sp_sh_cmd = ( "`alias $_sp_subcommand'" ) breaksw case load: case unload: set _sp_modtype = tcl - set _sp_sh_cmd = ( module $_sp_subcommand ) + set _sp_sh_cmd = ( "`alias module`" $_sp_subcommand ) breaksw endsw @@ -61,11 +75,17 @@ case unload: # 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 { set _sp_full_spec = `command spack module find $_sp_modtype $_sp_spec` } then - echo $_sp_sh_cmd $_sp_module_args $_sp_full_spec + set _sp_full_spec = "" + if { set _sp_full_spec = `\spack module find $_sp_modtype $_sp_spec` } then + $_sp_sh_cmd $_sp_module_args $_sp_full_spec endif + breaksw + default: - command spack $_sp_args + \spack $_sp_args + breaksw endsw -unset _sp_args _sp_full_spec _sp_modtype _sp_module_args _sp_sh_cmd _sp_spec _sp_subcommand +_sp_end: +unset _sp_args _sp_full_spec _sp_modtype _sp_module_args +unset _sp_sh_cmd _sp_spec _sp_subcommand _sp_flags diff --git a/share/spack/setup-env.csh b/share/spack/setup-env.csh index e3243e40b2..cc12eae82f 100755 --- a/share/spack/setup-env.csh +++ b/share/spack/setup-env.csh @@ -40,7 +40,8 @@ if ($?SPACK_ROOT) then alias _spack_pathadd 'set _pa_args = (\!*) && source $_spack_share_dir/csh/spack_pathadd.csh' # Set up modules and dotkit search paths in the user environment - _spack_pathadd DK_NODE "$_spack_share_dir/dotkit" - _spack_pathadd MODULEPATH "$_spack_share_dir/modules" + # TODO: fix SYS_TYPE to something non-LLNL-specific + _spack_pathadd DK_NODE "$_spack_share_dir/dotkit/$SYS_TYPE" + _spack_pathadd MODULEPATH "$_spack_share_dir/modules/$SYS_TYPE" _spack_pathadd PATH "$SPACK_ROOT/bin" endif diff --git a/share/spack/setup-env.sh b/share/spack/setup-env.sh index 7cadc6f202..0142e04817 100755 --- a/share/spack/setup-env.sh +++ b/share/spack/setup-env.sh @@ -56,6 +56,19 @@ # spack dotfiles. ######################################################################## function spack { + # accumulate initial flags for main spack command + _sp_flags="" + while [[ "$1" =~ ^- ]]; do + _sp_flags="$_sp_flags $1" + shift + done + + # h and V flags don't require further output parsing. + if [[ "$_sp_flags" =~ *h* || "$_sp_flags" =~ *V* ]]; then + command spack $_sp_flags "$@" + return + fi + _sp_subcommand=$1; shift _sp_spec="$@" @@ -88,13 +101,13 @@ function spack { # 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 + if _sp_full_spec=$(command spack $_sp_flags module find $_sp_modtype $_sp_spec); then $_sp_sh_cmd $_sp_module_args $_sp_full_spec fi return ;; *) - command spack $_sp_subcommand $_sp_spec + command spack $_sp_flags $_sp_subcommand $_sp_spec esac } @@ -145,6 +158,7 @@ fi _sp_share_dir="$(dirname $_sp_source_file)" _sp_prefix="$(dirname $(dirname $_sp_share_dir))" -_spack_pathadd DK_NODE "$_sp_share_dir/dotkit" -_spack_pathadd MODULEPATH "$_sp_share_dir/modules" +# TODO: fix SYS_TYPE to something non-LLNL-specific +_spack_pathadd DK_NODE "$_sp_share_dir/dotkit/$SYS_TYPE" +_spack_pathadd MODULEPATH "$_sp_share_dir/modules/$SYS_TYPE" _spack_pathadd PATH "$_sp_prefix/bin" -- cgit v1.2.3-70-g09d2