From 7714d08e2e4b1c7accd6113618651b42bdc942c1 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 10 Aug 2014 11:48:07 -0700 Subject: Remvoe dependence on v2.7 argparse by including argparse. --- bin/spack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bin') diff --git a/bin/spack b/bin/spack index c63178b191..0af8d62b5e 100755 --- a/bin/spack +++ b/bin/spack @@ -28,7 +28,6 @@ if not sys.version_info[:2] >= (2,7): sys.exit("Spack requires Python 2.7. Version was %s." % sys.version_info) import os -import argparse # Find spack's location and its prefix. SPACK_FILE = os.path.realpath(os.path.expanduser(__file__)) @@ -51,6 +50,7 @@ del SPACK_FILE, SPACK_PREFIX, SPACK_LIB_PATH import llnl.util.tty as tty import spack from spack.error import SpackError +from external import argparse # Command parsing parser = argparse.ArgumentParser( -- cgit v1.2.3-70-g09d2 From 48d5281e3a9142ded1e67983a22dce3f5777e1b4 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 10 Aug 2014 18:00:20 -0700 Subject: Test cases pass; Spack supports Python 2.6! --- bin/spack | 4 +- lib/spack/spack/stage.py | 3 +- lib/spack/spack/test/__init__.py | 4 +- lib/spack/spack/test/concretize.py | 24 +++--- lib/spack/spack/test/mock_packages_test.py | 3 +- lib/spack/spack/test/spec_dag.py | 46 +++++------ lib/spack/spack/test/stage.py | 122 +++++++++++++++-------------- 7 files changed, 104 insertions(+), 102 deletions(-) (limited to 'bin') diff --git a/bin/spack b/bin/spack index 0af8d62b5e..679ca9f1be 100755 --- a/bin/spack +++ b/bin/spack @@ -24,8 +24,8 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## import sys -if not sys.version_info[:2] >= (2,7): - sys.exit("Spack requires Python 2.7. Version was %s." % sys.version_info) +if not sys.version_info[:2] >= (2,6): + sys.exit("Spack requires Python 2.6. Version was %s." % sys.version_info) import os diff --git a/lib/spack/spack/stage.py b/lib/spack/spack/stage.py index 839555d630..3dac798396 100644 --- a/lib/spack/spack/stage.py +++ b/lib/spack/spack/stage.py @@ -120,8 +120,7 @@ class Stage(object): if spack.use_tmp_stage: # If we're using a tmp dir, it's a link, and it points at the right spot, # then keep it. - if (os.path.commonprefix((real_path, real_tmp)) == real_tmp - and os.path.exists(real_path)): + if (real_path.startswith(real_tmp) and os.path.exists(real_path)): return False else: # otherwise, just unlink it and start over. diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py index 4479c45d77..8ddc7f227d 100644 --- a/lib/spack/spack/test/__init__.py +++ b/lib/spack/spack/test/__init__.py @@ -72,7 +72,7 @@ def run(names, verbose=False): runner = unittest.TextTestRunner(verbosity=verbosity) - testsRun = errors = failures = skipped = 0 + testsRun = errors = failures = 0 for test in names: module = 'spack.test.' + test print module @@ -83,12 +83,10 @@ def run(names, verbose=False): testsRun += result.testsRun errors += len(result.errors) failures += len(result.failures) - skipped += len(result.skipped) succeeded = not errors and not failures tty.msg("Tests Complete.", "%5d tests run" % testsRun, - "%5d skipped" % skipped, "%5d failures" % failures, "%5d errors" % errors) diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 6ad2ef29d8..a7f4812c8c 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -134,29 +134,29 @@ class ConcretizeTest(MockPackagesTest): def test_virtual_is_fully_expanded_for_callpath(self): # force dependence on fake "zmpi" by asking for MPI 10.0 spec = Spec('callpath ^mpi@10.0') - self.assertIn('mpi', spec.dependencies) - self.assertNotIn('fake', spec) + self.assertTrue('mpi' in spec.dependencies) + self.assertFalse('fake' in spec) spec.concretize() - self.assertIn('zmpi', spec.dependencies) - self.assertNotIn('mpi', spec) - self.assertIn('fake', spec.dependencies['zmpi']) + self.assertTrue('zmpi' in spec.dependencies) + self.assertFalse('mpi' in spec) + self.assertTrue('fake' in spec.dependencies['zmpi']) def test_virtual_is_fully_expanded_for_mpileaks(self): spec = Spec('mpileaks ^mpi@10.0') - self.assertIn('mpi', spec.dependencies) - self.assertNotIn('fake', spec) + self.assertTrue('mpi' in spec.dependencies) + self.assertFalse('fake' in spec) spec.concretize() - self.assertIn('zmpi', spec.dependencies) - self.assertIn('callpath', spec.dependencies) - self.assertIn('zmpi', spec.dependencies['callpath'].dependencies) - self.assertIn('fake', spec.dependencies['callpath'].dependencies['zmpi'].dependencies) + self.assertTrue('zmpi' in spec.dependencies) + self.assertTrue('callpath' in spec.dependencies) + self.assertTrue('zmpi' in spec.dependencies['callpath'].dependencies) + self.assertTrue('fake' in spec.dependencies['callpath'].dependencies['zmpi'].dependencies) - self.assertNotIn('mpi', spec) + self.assertFalse('mpi' in spec) def test_my_dep_depends_on_provider_of_my_virtual_dep(self): diff --git a/lib/spack/spack/test/mock_packages_test.py b/lib/spack/spack/test/mock_packages_test.py index adde70ff6c..e948376039 100644 --- a/lib/spack/spack/test/mock_packages_test.py +++ b/lib/spack/spack/test/mock_packages_test.py @@ -39,7 +39,6 @@ def set_pkg_dep(pkg, spec): class MockPackagesTest(unittest.TestCase): - @classmethod def setUp(self): # Use the mock packages database for these tests. This allows # us to set up contrived packages that don't interfere with @@ -52,7 +51,7 @@ class MockPackagesTest(unittest.TestCase): 'site' : spack.mock_site_config, 'user' : spack.mock_user_config } - @classmethod + def tearDown(self): """Restore the real packages path after any test.""" spack.db = self.real_db diff --git a/lib/spack/spack/test/spec_dag.py b/lib/spack/spack/test/spec_dag.py index 322f34cf02..fb67aa8a8d 100644 --- a/lib/spack/spack/test/spec_dag.py +++ b/lib/spack/spack/test/spec_dag.py @@ -57,10 +57,10 @@ class SpecDagTest(MockPackagesTest): pairs = zip([0,1,2,3,4,2,3], names) traversal = dag.traverse() - self.assertListEqual([x.name for x in traversal], names) + self.assertEqual([x.name for x in traversal], names) traversal = dag.traverse(depth=True) - self.assertListEqual([(x, y.name) for x,y in traversal], pairs) + self.assertEqual([(x, y.name) for x,y in traversal], pairs) def test_preorder_edge_traversal(self): @@ -72,10 +72,10 @@ class SpecDagTest(MockPackagesTest): pairs = zip([0,1,2,3,4,3,2,3,1], names) traversal = dag.traverse(cover='edges') - self.assertListEqual([x.name for x in traversal], names) + self.assertEqual([x.name for x in traversal], names) traversal = dag.traverse(cover='edges', depth=True) - self.assertListEqual([(x, y.name) for x,y in traversal], pairs) + self.assertEqual([(x, y.name) for x,y in traversal], pairs) def test_preorder_path_traversal(self): @@ -87,10 +87,10 @@ class SpecDagTest(MockPackagesTest): pairs = zip([0,1,2,3,4,3,2,3,1,2], names) traversal = dag.traverse(cover='paths') - self.assertListEqual([x.name for x in traversal], names) + self.assertEqual([x.name for x in traversal], names) traversal = dag.traverse(cover='paths', depth=True) - self.assertListEqual([(x, y.name) for x,y in traversal], pairs) + self.assertEqual([(x, y.name) for x,y in traversal], pairs) def test_postorder_node_traversal(self): @@ -102,10 +102,10 @@ class SpecDagTest(MockPackagesTest): pairs = zip([4,3,2,3,2,1,0], names) traversal = dag.traverse(order='post') - self.assertListEqual([x.name for x in traversal], names) + self.assertEqual([x.name for x in traversal], names) traversal = dag.traverse(depth=True, order='post') - self.assertListEqual([(x, y.name) for x,y in traversal], pairs) + self.assertEqual([(x, y.name) for x,y in traversal], pairs) def test_postorder_edge_traversal(self): @@ -117,10 +117,10 @@ class SpecDagTest(MockPackagesTest): pairs = zip([4,3,3,2,3,2,1,1,0], names) traversal = dag.traverse(cover='edges', order='post') - self.assertListEqual([x.name for x in traversal], names) + self.assertEqual([x.name for x in traversal], names) traversal = dag.traverse(cover='edges', depth=True, order='post') - self.assertListEqual([(x, y.name) for x,y in traversal], pairs) + self.assertEqual([(x, y.name) for x,y in traversal], pairs) def test_postorder_path_traversal(self): @@ -132,10 +132,10 @@ class SpecDagTest(MockPackagesTest): pairs = zip([4,3,3,2,3,2,1,2,1,0], names) traversal = dag.traverse(cover='paths', order='post') - self.assertListEqual([x.name for x in traversal], names) + self.assertEqual([x.name for x in traversal], names) traversal = dag.traverse(cover='paths', depth=True, order='post') - self.assertListEqual([(x, y.name) for x,y in traversal], pairs) + self.assertEqual([(x, y.name) for x,y in traversal], pairs) def test_conflicting_spec_constraints(self): @@ -199,13 +199,13 @@ class SpecDagTest(MockPackagesTest): def check_links(self, spec_to_check): for spec in spec_to_check.traverse(): for dependent in spec.dependents.values(): - self.assertIn( - spec.name, dependent.dependencies, + self.assertTrue( + spec.name in dependent.dependencies, "%s not in dependencies of %s" % (spec.name, dependent.name)) for dependency in spec.dependencies.values(): - self.assertIn( - spec.name, dependency.dependents, + self.assertTrue( + spec.name in dependency.dependents, "%s not in dependents of %s" % (spec.name, dependency.name)) @@ -385,13 +385,13 @@ class SpecDagTest(MockPackagesTest): def test_contains(self): spec = Spec('mpileaks ^mpi ^libelf@1.8.11 ^libdwarf') - self.assertIn(Spec('mpi'), spec) - self.assertIn(Spec('libelf'), spec) - self.assertIn(Spec('libelf@1.8.11'), spec) - self.assertNotIn(Spec('libelf@1.8.12'), spec) - self.assertIn(Spec('libdwarf'), spec) - self.assertNotIn(Spec('libgoblin'), spec) - self.assertIn(Spec('mpileaks'), spec) + self.assertTrue(Spec('mpi') in spec) + self.assertTrue(Spec('libelf') in spec) + self.assertTrue(Spec('libelf@1.8.11') in spec) + self.assertFalse(Spec('libelf@1.8.12') in spec) + self.assertTrue(Spec('libdwarf') in spec) + self.assertFalse(Spec('libgoblin') in spec) + self.assertTrue(Spec('mpileaks') in spec) def test_copy_simple(self): diff --git a/lib/spack/spack/test/stage.py b/lib/spack/spack/test/stage.py index 08899f9810..a412549dc7 100644 --- a/lib/spack/spack/test/stage.py +++ b/lib/spack/spack/test/stage.py @@ -51,28 +51,20 @@ readme_text = "hello world!\n" stage_name = 'spack-test-stage' -class with_tmp(object): - """Decorator that executes a function with or without spack set to use - a temp dir. Spack allows builds to happen directly in the - stage directory or in a tmp dir and symlinked into the stage - directory, so this lets us use the same test in both cases. +@contextmanager +def use_tmp(use_tmp): + """Allow some test code to be executed with spack.use_tmp_stage + set to a certain value. Context manager makes sure it's reset + on failure. """ - def __init__(self, use_tmp): - self.use_tmp = use_tmp - - def __call__(self, fun): - use_tmp = self.use_tmp - def new_test_function(self): - old_tmp = spack.use_tmp_stage - spack.use_tmp_stage = use_tmp - fun(self) - spack.use_tmp_stage = old_tmp - return new_test_function + old_tmp = spack.use_tmp_stage + spack.use_tmp_stage = use_tmp + yield + spack.use_tmp_stage = old_tmp class StageTest(unittest.TestCase): - @classmethod - def setUpClass(cls): + def setUp(self): """This sets up a mock archive to fetch, and a mock temp space for use by the Stage class. It doesn't actually create the Stage -- that is done by individual tests. @@ -92,52 +84,58 @@ class StageTest(unittest.TestCase): tar('czf', archive_name, archive_dir) # Make spack use the test environment for tmp stuff. - cls.old_tmp_dirs = spack.tmp_dirs + self.old_tmp_dirs = spack.tmp_dirs spack.tmp_dirs = [test_tmp_path] + # record this since this test changes to directories that will + # be removed. + self.working_dir = os.getcwd() + - @classmethod - def tearDownClass(cls): + def tearDown(self): """Blows away the test environment directory.""" shutil.rmtree(test_files_dir) + # chdir back to original working dir + os.chdir(self.working_dir) + # restore spack's original tmp environment - spack.tmp_dirs = cls.old_tmp_dirs + spack.tmp_dirs = self.old_tmp_dirs def get_stage_path(self, stage, stage_name): - """Figure out based on a stage and an intended name where it should - be living. This depends on whether it's named or not. + """Figure out where a stage should be living. This depends on + whether it's named. """ - if stage_name: + if stage_name is not None: # If it is a named stage, we know where the stage should be - stage_path = join_path(spack.stage_path, stage_name) + return join_path(spack.stage_path, stage_name) else: # If it's unnamed, ensure that we ran mkdtemp in the right spot. - stage_path = stage.path - self.assertIsNotNone(stage_path) - self.assertEqual( - os.path.commonprefix((stage_path, spack.stage_path)), - spack.stage_path) - return stage_path + self.assertTrue(stage.path is not None) + self.assertTrue(stage.path.startswith(spack.stage_path)) + return stage.path def check_setup(self, stage, stage_name): """Figure out whether a stage was set up correctly.""" stage_path = self.get_stage_path(stage, stage_name) + + # Ensure stage was created in the spack stage directory self.assertTrue(os.path.isdir(stage_path)) if spack.use_tmp_stage: - # Make sure everything was created and linked correctly for - # a tmp stage. + # Check that the stage dir is really a symlink. self.assertTrue(os.path.islink(stage_path)) + # Make sure it points to a valid directory target = os.path.realpath(stage_path) self.assertTrue(os.path.isdir(target)) self.assertFalse(os.path.islink(target)) - self.assertEqual( - os.path.commonprefix((target, test_tmp_path)), - test_tmp_path) + + # Make sure the directory is in the place we asked it to + # be (see setUp and tearDown) + self.assertTrue(target.startswith(test_tmp_path)) else: # Make sure the stage path is NOT a link for a non-tmp stage @@ -146,15 +144,15 @@ class StageTest(unittest.TestCase): def check_fetch(self, stage, stage_name): stage_path = self.get_stage_path(stage, stage_name) - self.assertIn(archive_name, os.listdir(stage_path)) + self.assertTrue(archive_name in os.listdir(stage_path)) self.assertEqual(join_path(stage_path, archive_name), stage.archive_file) def check_expand_archive(self, stage, stage_name): stage_path = self.get_stage_path(stage, stage_name) - self.assertIn(archive_name, os.listdir(stage_path)) - self.assertIn(archive_dir, os.listdir(stage_path)) + self.assertTrue(archive_name in os.listdir(stage_path)) + self.assertTrue(archive_dir in os.listdir(stage_path)) self.assertEqual( join_path(stage_path, archive_dir), @@ -192,32 +190,40 @@ class StageTest(unittest.TestCase): self.assertFalse(os.path.exists(target)) - def checkSetupAndDestroy(self, stage_name=None): - stage = Stage(archive_url, name=stage_name) - self.check_setup(stage, stage_name) - - stage.destroy() - self.check_destroy(stage, stage_name) - - - @with_tmp(True) def test_setup_and_destroy_name_with_tmp(self): - self.checkSetupAndDestroy(stage_name) + with use_tmp(True): + stage = Stage(archive_url, name=stage_name) + self.check_setup(stage, stage_name) + + stage.destroy() + self.check_destroy(stage, stage_name) - @with_tmp(False) def test_setup_and_destroy_name_without_tmp(self): - self.checkSetupAndDestroy(stage_name) + with use_tmp(False): + stage = Stage(archive_url, name=stage_name) + self.check_setup(stage, stage_name) + + stage.destroy() + self.check_destroy(stage, stage_name) - @with_tmp(True) def test_setup_and_destroy_no_name_with_tmp(self): - self.checkSetupAndDestroy(None) + with use_tmp(True): + stage = Stage(archive_url) + self.check_setup(stage, None) + + stage.destroy() + self.check_destroy(stage, None) - @with_tmp(False) def test_setup_and_destroy_no_name_without_tmp(self): - self.checkSetupAndDestroy(None) + with use_tmp(False): + stage = Stage(archive_url) + self.check_setup(stage, None) + + stage.destroy() + self.check_destroy(stage, None) def test_chdir(self): @@ -286,7 +292,7 @@ class StageTest(unittest.TestCase): with closing(open('foobar', 'w')) as file: file.write("this file is to be destroyed.") - self.assertIn('foobar', os.listdir(stage.expanded_archive_path)) + self.assertTrue('foobar' in os.listdir(stage.expanded_archive_path)) # Make sure the file is not there after restage. stage.restage() @@ -295,7 +301,7 @@ class StageTest(unittest.TestCase): stage.chdir_to_archive() self.check_chdir_to_archive(stage, stage_name) - self.assertNotIn('foobar', os.listdir(stage.expanded_archive_path)) + self.assertFalse('foobar' in os.listdir(stage.expanded_archive_path)) stage.destroy() self.check_destroy(stage, stage_name) -- 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 (limited to 'bin') 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