From 94c5c9667c786e05a635787e803d2cf7e22de73a Mon Sep 17 00:00:00 2001 From: David Beckingsale Date: Thu, 31 Jul 2014 13:42:34 -0700 Subject: [PATCH] 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 @@ 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" -