From ae2a803496772db9ce6f9245d165b44f587e4389 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Tue, 30 Aug 2016 10:47:38 -0500 Subject: Make subcommands importable, '-' -> '_', fixes #1642 --- bin/spack | 11 +- lib/spack/spack/cmd/package-list.py | 104 ------------- lib/spack/spack/cmd/package_list.py | 104 +++++++++++++ lib/spack/spack/cmd/test-install.py | 245 ------------------------------- lib/spack/spack/cmd/test_install.py | 245 +++++++++++++++++++++++++++++++ lib/spack/spack/cmd/url-parse.py | 75 ---------- lib/spack/spack/cmd/url_parse.py | 75 ++++++++++ lib/spack/spack/test/cmd/test_install.py | 6 +- 8 files changed, 434 insertions(+), 431 deletions(-) delete mode 100644 lib/spack/spack/cmd/package-list.py create mode 100644 lib/spack/spack/cmd/package_list.py delete mode 100644 lib/spack/spack/cmd/test-install.py create mode 100644 lib/spack/spack/cmd/test_install.py delete mode 100644 lib/spack/spack/cmd/url-parse.py create mode 100644 lib/spack/spack/cmd/url_parse.py diff --git a/bin/spack b/bin/spack index 7efa88f1ee..323a06aa53 100755 --- a/bin/spack +++ b/bin/spack @@ -56,8 +56,15 @@ with warnings.catch_warnings(): # Spack, were removed, but shadow system modules that Spack still # imports. If we leave them, Spack will fail in mysterious ways. # TODO: more elegant solution for orphaned pyc files. -orphaned_pyc_files = [os.path.join(SPACK_EXTERNAL_LIBS, n) - for n in ('functools.pyc', 'ordereddict.pyc')] +orphaned_pyc_files = [ + os.path.join(SPACK_EXTERNAL_LIBS, 'functools.pyc'), + os.path.join(SPACK_EXTERNAL_LIBS, 'ordereddict.pyc'), + os.path.join(SPACK_LIB_PATH, 'spack', 'platforms', 'cray_xc.pyc'), + os.path.join(SPACK_LIB_PATH, 'spack', 'cmd', 'package-list.pyc'), + os.path.join(SPACK_LIB_PATH, 'spack', 'cmd', 'test-install.pyc'), + os.path.join(SPACK_LIB_PATH, 'spack', 'cmd', 'url-parse.pyc') +] + for pyc_file in orphaned_pyc_files: if not os.path.exists(pyc_file): continue diff --git a/lib/spack/spack/cmd/package-list.py b/lib/spack/spack/cmd/package-list.py deleted file mode 100644 index 42f408af96..0000000000 --- a/lib/spack/spack/cmd/package-list.py +++ /dev/null @@ -1,104 +0,0 @@ -############################################################################## -# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. -# Produced at the Lawrence Livermore National Laboratory. -# -# This file is part of Spack. -# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. -# LLNL-CODE-647188 -# -# For details, see https://github.com/llnl/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 Lesser General Public License (as -# published by the Free Software Foundation) version 2.1, 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 Lesser 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 cgi -from StringIO import StringIO -from llnl.util.tty.colify import * -import spack - -description = "Print a list of all packages in reStructuredText." - - -def github_url(pkg): - """Link to a package file on github.""" - url = "https://github.com/LLNL/spack/blob/develop/var/spack/repos/builtin/packages/{0}/package.py" - return url.format(pkg.name) - - -def rst_table(elts): - """Print out a RST-style table.""" - cols = StringIO() - ncol, widths = colify(elts, output=cols, tty=True) - header = " ".join("=" * (w - 1) for w in widths) - return "%s\n%s%s" % (header, cols.getvalue(), header) - - -def print_rst_package_list(): - """Print out information on all packages in restructured text.""" - pkgs = sorted(spack.repo.all_packages(), key=lambda s: s.name.lower()) - pkg_names = [p.name for p in pkgs] - - print ".. _package-list:" - print - print "============" - print "Package List" - print "============" - print - print "This is a list of things you can install using Spack. It is" - print "automatically generated based on the packages in the latest Spack" - print "release." - print - print "Spack currently has %d mainline packages:" % len(pkgs) - print - print rst_table("`%s`_" % p for p in pkg_names) - print - - # Output some text for each package. - for pkg in pkgs: - print "-----" - print - print ".. _%s:" % pkg.name - print - # Must be at least 2 long, breaks for single letter packages like R. - print "-" * max(len(pkg.name), 2) - print pkg.name - print "-" * max(len(pkg.name), 2) - print - print "Homepage:" - print " * `%s <%s>`__" % (cgi.escape(pkg.homepage), pkg.homepage) - print - print "Spack package:" - print " * `%s/package.py <%s>`__" % (pkg.name, github_url(pkg)) - print - if pkg.versions: - print "Versions:" - print " " + ", ".join(str(v) for v in - reversed(sorted(pkg.versions))) - print - - for deptype in spack.alldeps: - deps = pkg.dependencies_of_type(deptype) - if deps: - print "%s Dependencies" % deptype.capitalize() - print " " + ", ".join("%s_" % d if d in pkg_names - else d for d in deps) - print - - print "Description:" - print pkg.format_doc(indent=2) - print - - -def package_list(parser, args): - print_rst_package_list() diff --git a/lib/spack/spack/cmd/package_list.py b/lib/spack/spack/cmd/package_list.py new file mode 100644 index 0000000000..42f408af96 --- /dev/null +++ b/lib/spack/spack/cmd/package_list.py @@ -0,0 +1,104 @@ +############################################################################## +# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/llnl/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 Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, 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 Lesser 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 cgi +from StringIO import StringIO +from llnl.util.tty.colify import * +import spack + +description = "Print a list of all packages in reStructuredText." + + +def github_url(pkg): + """Link to a package file on github.""" + url = "https://github.com/LLNL/spack/blob/develop/var/spack/repos/builtin/packages/{0}/package.py" + return url.format(pkg.name) + + +def rst_table(elts): + """Print out a RST-style table.""" + cols = StringIO() + ncol, widths = colify(elts, output=cols, tty=True) + header = " ".join("=" * (w - 1) for w in widths) + return "%s\n%s%s" % (header, cols.getvalue(), header) + + +def print_rst_package_list(): + """Print out information on all packages in restructured text.""" + pkgs = sorted(spack.repo.all_packages(), key=lambda s: s.name.lower()) + pkg_names = [p.name for p in pkgs] + + print ".. _package-list:" + print + print "============" + print "Package List" + print "============" + print + print "This is a list of things you can install using Spack. It is" + print "automatically generated based on the packages in the latest Spack" + print "release." + print + print "Spack currently has %d mainline packages:" % len(pkgs) + print + print rst_table("`%s`_" % p for p in pkg_names) + print + + # Output some text for each package. + for pkg in pkgs: + print "-----" + print + print ".. _%s:" % pkg.name + print + # Must be at least 2 long, breaks for single letter packages like R. + print "-" * max(len(pkg.name), 2) + print pkg.name + print "-" * max(len(pkg.name), 2) + print + print "Homepage:" + print " * `%s <%s>`__" % (cgi.escape(pkg.homepage), pkg.homepage) + print + print "Spack package:" + print " * `%s/package.py <%s>`__" % (pkg.name, github_url(pkg)) + print + if pkg.versions: + print "Versions:" + print " " + ", ".join(str(v) for v in + reversed(sorted(pkg.versions))) + print + + for deptype in spack.alldeps: + deps = pkg.dependencies_of_type(deptype) + if deps: + print "%s Dependencies" % deptype.capitalize() + print " " + ", ".join("%s_" % d if d in pkg_names + else d for d in deps) + print + + print "Description:" + print pkg.format_doc(indent=2) + print + + +def package_list(parser, args): + print_rst_package_list() diff --git a/lib/spack/spack/cmd/test-install.py b/lib/spack/spack/cmd/test-install.py deleted file mode 100644 index 8e7173e9a2..0000000000 --- a/lib/spack/spack/cmd/test-install.py +++ /dev/null @@ -1,245 +0,0 @@ -############################################################################## -# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. -# Produced at the Lawrence Livermore National Laboratory. -# -# This file is part of Spack. -# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. -# LLNL-CODE-647188 -# -# For details, see https://github.com/llnl/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 Lesser General Public License (as -# published by the Free Software Foundation) version 2.1, 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 Lesser 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 codecs -import os -import time -import xml.dom.minidom -import xml.etree.ElementTree as ET - -import llnl.util.tty as tty -import spack -import spack.cmd -from llnl.util.filesystem import * -from spack.build_environment import InstallError -from spack.fetch_strategy import FetchError - -description = "Run package install as a unit test, output formatted results." - - -def setup_parser(subparser): - subparser.add_argument( - '-j', '--jobs', action='store', type=int, - help="Explicitly set number of make jobs. Default is #cpus.") - - subparser.add_argument( - '-n', '--no-checksum', action='store_true', dest='no_checksum', - help="Do not check packages against checksum") - - subparser.add_argument( - '-o', '--output', action='store', - help="test output goes in this file") - - subparser.add_argument( - 'package', nargs=argparse.REMAINDER, - help="spec of package to install") - - -class TestResult(object): - PASSED = 0 - FAILED = 1 - SKIPPED = 2 - ERRORED = 3 - - -class TestSuite(object): - - def __init__(self, filename): - self.filename = filename - self.root = ET.Element('testsuite') - self.tests = [] - - def __enter__(self): - return self - - def append(self, item): - if not isinstance(item, TestCase): - raise TypeError( - 'only TestCase instances may be appended to TestSuite') - self.tests.append(item) # Append the item to the list of tests - - def __exit__(self, exc_type, exc_val, exc_tb): - # Prepare the header for the entire test suite - number_of_errors = sum( - x.result_type == TestResult.ERRORED for x in self.tests) - self.root.set('errors', str(number_of_errors)) - number_of_failures = sum( - x.result_type == TestResult.FAILED for x in self.tests) - self.root.set('failures', str(number_of_failures)) - self.root.set('tests', str(len(self.tests))) - - for item in self.tests: - self.root.append(item.element) - - with open(self.filename, 'wb') as file: - xml_string = ET.tostring(self.root) - xml_string = xml.dom.minidom.parseString(xml_string).toprettyxml() - file.write(xml_string) - - -class TestCase(object): - - results = { - TestResult.PASSED: None, - TestResult.SKIPPED: 'skipped', - TestResult.FAILED: 'failure', - TestResult.ERRORED: 'error', - } - - def __init__(self, classname, name, time=None): - self.element = ET.Element('testcase') - self.element.set('classname', str(classname)) - self.element.set('name', str(name)) - if time is not None: - self.element.set('time', str(time)) - self.result_type = None - - def set_result(self, result_type, - message=None, error_type=None, text=None): - self.result_type = result_type - result = TestCase.results[self.result_type] - if result is not None and result is not TestResult.PASSED: - subelement = ET.SubElement(self.element, result) - if error_type is not None: - subelement.set('type', error_type) - if message is not None: - subelement.set('message', str(message)) - if text is not None: - subelement.text = text - - -def fetch_log(path): - if not os.path.exists(path): - return list() - with codecs.open(path, 'rb', 'utf-8') as F: - return list(line.strip() for line in F.readlines()) - - -def failed_dependencies(spec): - def get_deps(deptype): - return set(item for item in spec.dependencies(deptype) - if not spack.repo.get(item).installed) - link_deps = get_deps('link') - run_deps = get_deps('run') - return link_deps.union(run_deps) - - -def get_top_spec_or_die(args): - specs = spack.cmd.parse_specs(args.package, concretize=True) - if len(specs) > 1: - tty.die("Only 1 top-level package can be specified") - top_spec = iter(specs).next() - return top_spec - - -def install_single_spec(spec, number_of_jobs): - package = spack.repo.get(spec) - - # If it is already installed, skip the test - if spack.repo.get(spec).installed: - testcase = TestCase(package.name, package.spec.short_spec, time=0.0) - testcase.set_result( - TestResult.SKIPPED, - message='Skipped [already installed]', - error_type='already_installed') - return testcase - - # If it relies on dependencies that did not install, skip - if failed_dependencies(spec): - testcase = TestCase(package.name, package.spec.short_spec, time=0.0) - testcase.set_result( - TestResult.SKIPPED, - message='Skipped [failed dependencies]', - error_type='dep_failed') - return testcase - - # Otherwise try to install the spec - try: - start_time = time.time() - package.do_install(keep_prefix=False, - keep_stage=True, - ignore_deps=False, - make_jobs=number_of_jobs, - verbose=True, - fake=False) - duration = time.time() - start_time - testcase = TestCase(package.name, package.spec.short_spec, duration) - testcase.set_result(TestResult.PASSED) - except InstallError: - # An InstallError is considered a failure (the recipe didn't work - # correctly) - duration = time.time() - start_time - # Try to get the log - lines = fetch_log(package.build_log_path) - text = '\n'.join(lines) - testcase = TestCase(package.name, package.spec.short_spec, duration) - testcase.set_result(TestResult.FAILED, - message='Installation failure', text=text) - - except FetchError: - # A FetchError is considered an error (we didn't even start building) - duration = time.time() - start_time - testcase = TestCase(package.name, package.spec.short_spec, duration) - testcase.set_result(TestResult.ERRORED, - message='Unable to fetch package') - - return testcase - - -def get_filename(args, top_spec): - if not args.output: - fname = 'test-{x.name}-{x.version}-{hash}.xml'.format( - x=top_spec, hash=top_spec.dag_hash()) - output_directory = join_path(os.getcwd(), 'test-output') - if not os.path.exists(output_directory): - os.mkdir(output_directory) - output_filename = join_path(output_directory, fname) - else: - output_filename = args.output - return output_filename - - -def test_install(parser, args): - # Check the input - if not args.package: - tty.die("install requires a package argument") - - if args.jobs is not None: - if args.jobs <= 0: - tty.die("The -j option must be a positive integer!") - - if args.no_checksum: - spack.do_checksum = False # TODO: remove this global. - - # Get the one and only top spec - top_spec = get_top_spec_or_die(args) - # Get the filename of the test - output_filename = get_filename(args, top_spec) - # TEST SUITE - with TestSuite(output_filename) as test_suite: - # Traverse in post order : each spec is a test case - for spec in top_spec.traverse(order='post'): - test_case = install_single_spec(spec, args.jobs) - test_suite.append(test_case) diff --git a/lib/spack/spack/cmd/test_install.py b/lib/spack/spack/cmd/test_install.py new file mode 100644 index 0000000000..8e7173e9a2 --- /dev/null +++ b/lib/spack/spack/cmd/test_install.py @@ -0,0 +1,245 @@ +############################################################################## +# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/llnl/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 Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, 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 Lesser 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 codecs +import os +import time +import xml.dom.minidom +import xml.etree.ElementTree as ET + +import llnl.util.tty as tty +import spack +import spack.cmd +from llnl.util.filesystem import * +from spack.build_environment import InstallError +from spack.fetch_strategy import FetchError + +description = "Run package install as a unit test, output formatted results." + + +def setup_parser(subparser): + subparser.add_argument( + '-j', '--jobs', action='store', type=int, + help="Explicitly set number of make jobs. Default is #cpus.") + + subparser.add_argument( + '-n', '--no-checksum', action='store_true', dest='no_checksum', + help="Do not check packages against checksum") + + subparser.add_argument( + '-o', '--output', action='store', + help="test output goes in this file") + + subparser.add_argument( + 'package', nargs=argparse.REMAINDER, + help="spec of package to install") + + +class TestResult(object): + PASSED = 0 + FAILED = 1 + SKIPPED = 2 + ERRORED = 3 + + +class TestSuite(object): + + def __init__(self, filename): + self.filename = filename + self.root = ET.Element('testsuite') + self.tests = [] + + def __enter__(self): + return self + + def append(self, item): + if not isinstance(item, TestCase): + raise TypeError( + 'only TestCase instances may be appended to TestSuite') + self.tests.append(item) # Append the item to the list of tests + + def __exit__(self, exc_type, exc_val, exc_tb): + # Prepare the header for the entire test suite + number_of_errors = sum( + x.result_type == TestResult.ERRORED for x in self.tests) + self.root.set('errors', str(number_of_errors)) + number_of_failures = sum( + x.result_type == TestResult.FAILED for x in self.tests) + self.root.set('failures', str(number_of_failures)) + self.root.set('tests', str(len(self.tests))) + + for item in self.tests: + self.root.append(item.element) + + with open(self.filename, 'wb') as file: + xml_string = ET.tostring(self.root) + xml_string = xml.dom.minidom.parseString(xml_string).toprettyxml() + file.write(xml_string) + + +class TestCase(object): + + results = { + TestResult.PASSED: None, + TestResult.SKIPPED: 'skipped', + TestResult.FAILED: 'failure', + TestResult.ERRORED: 'error', + } + + def __init__(self, classname, name, time=None): + self.element = ET.Element('testcase') + self.element.set('classname', str(classname)) + self.element.set('name', str(name)) + if time is not None: + self.element.set('time', str(time)) + self.result_type = None + + def set_result(self, result_type, + message=None, error_type=None, text=None): + self.result_type = result_type + result = TestCase.results[self.result_type] + if result is not None and result is not TestResult.PASSED: + subelement = ET.SubElement(self.element, result) + if error_type is not None: + subelement.set('type', error_type) + if message is not None: + subelement.set('message', str(message)) + if text is not None: + subelement.text = text + + +def fetch_log(path): + if not os.path.exists(path): + return list() + with codecs.open(path, 'rb', 'utf-8') as F: + return list(line.strip() for line in F.readlines()) + + +def failed_dependencies(spec): + def get_deps(deptype): + return set(item for item in spec.dependencies(deptype) + if not spack.repo.get(item).installed) + link_deps = get_deps('link') + run_deps = get_deps('run') + return link_deps.union(run_deps) + + +def get_top_spec_or_die(args): + specs = spack.cmd.parse_specs(args.package, concretize=True) + if len(specs) > 1: + tty.die("Only 1 top-level package can be specified") + top_spec = iter(specs).next() + return top_spec + + +def install_single_spec(spec, number_of_jobs): + package = spack.repo.get(spec) + + # If it is already installed, skip the test + if spack.repo.get(spec).installed: + testcase = TestCase(package.name, package.spec.short_spec, time=0.0) + testcase.set_result( + TestResult.SKIPPED, + message='Skipped [already installed]', + error_type='already_installed') + return testcase + + # If it relies on dependencies that did not install, skip + if failed_dependencies(spec): + testcase = TestCase(package.name, package.spec.short_spec, time=0.0) + testcase.set_result( + TestResult.SKIPPED, + message='Skipped [failed dependencies]', + error_type='dep_failed') + return testcase + + # Otherwise try to install the spec + try: + start_time = time.time() + package.do_install(keep_prefix=False, + keep_stage=True, + ignore_deps=False, + make_jobs=number_of_jobs, + verbose=True, + fake=False) + duration = time.time() - start_time + testcase = TestCase(package.name, package.spec.short_spec, duration) + testcase.set_result(TestResult.PASSED) + except InstallError: + # An InstallError is considered a failure (the recipe didn't work + # correctly) + duration = time.time() - start_time + # Try to get the log + lines = fetch_log(package.build_log_path) + text = '\n'.join(lines) + testcase = TestCase(package.name, package.spec.short_spec, duration) + testcase.set_result(TestResult.FAILED, + message='Installation failure', text=text) + + except FetchError: + # A FetchError is considered an error (we didn't even start building) + duration = time.time() - start_time + testcase = TestCase(package.name, package.spec.short_spec, duration) + testcase.set_result(TestResult.ERRORED, + message='Unable to fetch package') + + return testcase + + +def get_filename(args, top_spec): + if not args.output: + fname = 'test-{x.name}-{x.version}-{hash}.xml'.format( + x=top_spec, hash=top_spec.dag_hash()) + output_directory = join_path(os.getcwd(), 'test-output') + if not os.path.exists(output_directory): + os.mkdir(output_directory) + output_filename = join_path(output_directory, fname) + else: + output_filename = args.output + return output_filename + + +def test_install(parser, args): + # Check the input + if not args.package: + tty.die("install requires a package argument") + + if args.jobs is not None: + if args.jobs <= 0: + tty.die("The -j option must be a positive integer!") + + if args.no_checksum: + spack.do_checksum = False # TODO: remove this global. + + # Get the one and only top spec + top_spec = get_top_spec_or_die(args) + # Get the filename of the test + output_filename = get_filename(args, top_spec) + # TEST SUITE + with TestSuite(output_filename) as test_suite: + # Traverse in post order : each spec is a test case + for spec in top_spec.traverse(order='post'): + test_case = install_single_spec(spec, args.jobs) + test_suite.append(test_case) diff --git a/lib/spack/spack/cmd/url-parse.py b/lib/spack/spack/cmd/url-parse.py deleted file mode 100644 index b8c7c95040..0000000000 --- a/lib/spack/spack/cmd/url-parse.py +++ /dev/null @@ -1,75 +0,0 @@ -############################################################################## -# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. -# Produced at the Lawrence Livermore National Laboratory. -# -# This file is part of Spack. -# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. -# LLNL-CODE-647188 -# -# For details, see https://github.com/llnl/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 Lesser General Public License (as -# published by the Free Software Foundation) version 2.1, 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 Lesser 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 llnl.util.tty as tty - -import spack -import spack.url -from spack.util.web import find_versions_of_archive - -description = "Show parsing of a URL, optionally spider web for versions." - - -def setup_parser(subparser): - subparser.add_argument('url', help="url of a package archive") - subparser.add_argument( - '-s', '--spider', action='store_true', - help="Spider the source page for versions.") - - -def print_name_and_version(url): - name, ns, nl, ntup, ver, vs, vl, vtup = spack.url.substitution_offsets(url) - underlines = [" "] * max(ns + nl, vs + vl) - for i in range(ns, ns + nl): - underlines[i] = '-' - for i in range(vs, vs + vl): - underlines[i] = '~' - - print " %s" % url - print " %s" % ''.join(underlines) - - -def url_parse(parser, args): - url = args.url - - ver, vs, vl = spack.url.parse_version_offset(url) - name, ns, nl = spack.url.parse_name_offset(url, ver) - - tty.msg("Parsing URL:") - try: - print_name_and_version(url) - except spack.url.UrlParseError as e: - tty.error(str(e)) - - print - tty.msg("Substituting version 9.9.9b:") - newurl = spack.url.substitute_version(url, '9.9.9b') - print_name_and_version(newurl) - - if args.spider: - print - tty.msg("Spidering for versions:") - versions = find_versions_of_archive(url) - for v in sorted(versions): - print "%-20s%s" % (v, versions[v]) diff --git a/lib/spack/spack/cmd/url_parse.py b/lib/spack/spack/cmd/url_parse.py new file mode 100644 index 0000000000..b8c7c95040 --- /dev/null +++ b/lib/spack/spack/cmd/url_parse.py @@ -0,0 +1,75 @@ +############################################################################## +# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/llnl/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 Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, 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 Lesser 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 llnl.util.tty as tty + +import spack +import spack.url +from spack.util.web import find_versions_of_archive + +description = "Show parsing of a URL, optionally spider web for versions." + + +def setup_parser(subparser): + subparser.add_argument('url', help="url of a package archive") + subparser.add_argument( + '-s', '--spider', action='store_true', + help="Spider the source page for versions.") + + +def print_name_and_version(url): + name, ns, nl, ntup, ver, vs, vl, vtup = spack.url.substitution_offsets(url) + underlines = [" "] * max(ns + nl, vs + vl) + for i in range(ns, ns + nl): + underlines[i] = '-' + for i in range(vs, vs + vl): + underlines[i] = '~' + + print " %s" % url + print " %s" % ''.join(underlines) + + +def url_parse(parser, args): + url = args.url + + ver, vs, vl = spack.url.parse_version_offset(url) + name, ns, nl = spack.url.parse_name_offset(url, ver) + + tty.msg("Parsing URL:") + try: + print_name_and_version(url) + except spack.url.UrlParseError as e: + tty.error(str(e)) + + print + tty.msg("Substituting version 9.9.9b:") + newurl = spack.url.substitute_version(url, '9.9.9b') + print_name_and_version(newurl) + + if args.spider: + print + tty.msg("Spidering for versions:") + versions = find_versions_of_archive(url) + for v in sorted(versions): + print "%-20s%s" % (v, versions[v]) diff --git a/lib/spack/spack/test/cmd/test_install.py b/lib/spack/spack/test/cmd/test_install.py index 39287d5d6d..4734fe1267 100644 --- a/lib/spack/spack/test/cmd/test_install.py +++ b/lib/spack/spack/test/cmd/test_install.py @@ -30,6 +30,7 @@ import contextlib import spack import spack.cmd +from spack.cmd import test_install FILE_REGISTRY = collections.defaultdict(StringIO.StringIO) @@ -51,11 +52,6 @@ def mock_open(filename, mode): handle.close() -# The use of __import__ is necessary to maintain a name with hyphen (which -# cannot be an identifier in python) -test_install = __import__("spack.cmd.test-install", fromlist=['test_install']) - - class MockSpec(object): def __init__(self, name, version, hashStr=None): -- cgit v1.2.3-60-g2f50