diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/cmd/create.py | 21 | ||||
-rw-r--r-- | lib/spack/spack/packages.py | 4 | ||||
-rw-r--r-- | lib/spack/spack/test/__init__.py | 3 | ||||
-rw-r--r-- | lib/spack/spack/test/package_sanity.py | 40 | ||||
-rw-r--r-- | lib/spack/spack/test/url_parse.py | 114 | ||||
-rw-r--r-- | lib/spack/spack/url.py | 37 |
6 files changed, 156 insertions, 63 deletions
diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py index 8653fafa5f..cc2e0dd384 100644 --- a/lib/spack/spack/cmd/create.py +++ b/lib/spack/spack/cmd/create.py @@ -123,6 +123,18 @@ def make_version_dict(ver_hash_tuples): for v, h in ver_hash_tuples) + ' }' +def get_name(): + """Prompt user to input a package name.""" + name = "" + while not name: + new_name = raw_input("Name: ") + if spack.db.valid_name(name): + name = new_name + else: + print "Package name can only contain A-Z, a-z, 0-9, '_' and '-'" + return name + + def create(parser, args): url = args.url @@ -130,18 +142,15 @@ def create(parser, args): name, version = spack.url.parse_name_and_version(url) if not name: tty.msg("Couldn't guess a name for this package.") - while not name: - new_name = raw_input("Name: ") - if spack.db.valid_name(name): - name = new_name - else: - print "Package name can only contain A-Z, a-z, 0-9, '_' and '-'" + name = get_name() if not version: tty.die("Couldn't guess a version string from %s." % url) + tty.msg("This looks like a URL for %s version %s." % (name, version)) tty.msg("Creating template for package %s" % name) + # Create a directory for the new package. pkg_path = spack.db.filename_for_package_name(name) if os.path.exists(pkg_path) and not args.force: tty.die("%s already exists." % pkg_path) diff --git a/lib/spack/spack/packages.py b/lib/spack/spack/packages.py index 732ced9bf2..08ded5cdbb 100644 --- a/lib/spack/spack/packages.py +++ b/lib/spack/spack/packages.py @@ -171,7 +171,7 @@ class PackageDB(object): def all_packages(self): for name in self.all_package_names(): - yield get(name) + yield self.get(name) def exists(self, pkg_name): @@ -228,7 +228,7 @@ class PackageDB(object): pkg._dependents = [] for name, dep in pkg.dependencies.iteritems(): - dpkg = get(name) + dpkg = self.get(name) if dpkg._dependents is None: dpkg._dependents = [] dpkg._dependents.append(pkg.name) diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py index 271b915479..5aac710119 100644 --- a/lib/spack/spack/test/__init__.py +++ b/lib/spack/spack/test/__init__.py @@ -43,7 +43,8 @@ test_names = ['versions', 'spec_dag', 'concretize', 'multimethod', - 'install'] + 'install', + 'package_sanity'] def list_tests(): diff --git a/lib/spack/spack/test/package_sanity.py b/lib/spack/spack/test/package_sanity.py new file mode 100644 index 0000000000..a0bf4ceb4a --- /dev/null +++ b/lib/spack/spack/test/package_sanity.py @@ -0,0 +1,40 @@ +############################################################################## +# 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 test does sanity checks on Spack's builtin package database. +""" +import unittest + +import spack +import spack.url as url + +class PackageSanityTest(unittest.TestCase): + def test_url_versions(self): + """Ensure that url_for_version does the right thing for at least the + default version of each package. + """ + for pkg in spack.db.all_packages(): + v = url.parse_version(pkg.url) + self.assertEqual(pkg.url, pkg.url_for_version(v)) diff --git a/lib/spack/spack/test/url_parse.py b/lib/spack/spack/test/url_parse.py index 109402608b..a03d6098f1 100644 --- a/lib/spack/spack/test/url_parse.py +++ b/lib/spack/spack/test/url_parse.py @@ -36,21 +36,33 @@ class UrlParseTest(unittest.TestCase): self.assertRaises( url.UndetectableVersionError, url.parse_name_and_version, string) - def assert_detected(self, name, v, string): + + def check(self, name, v, string, **kwargs): + # Make sure correct name and version are extracted. parsed_name, parsed_v = url.parse_name_and_version(string) self.assertEqual(parsed_name, name) self.assertEqual(parsed_v, url.Version(v)) + # Some URLs (like boost) are special and need to override the + # built-in functionality. + if kwargs.get('no_check_url', False): + return + + # Make sure Spack formulates the right URL when we try to + # build one with a specific version. + self.assertEqual(string, url.substitute_version(string, v)) + + def test_wwwoffle_version(self): - self.assert_detected( + self.check( 'wwwoffle', '2.9h', 'http://www.gedanken.demon.co.uk/download-wwwoffle/wwwoffle-2.9h.tgz') def test_version_sourceforge_download(self): - self.assert_detected( + self.check( 'foo_bar', '1.21', 'http://sourceforge.net/foo_bar-1.21.tar.gz/download') - self.assert_detected( + self.check( 'foo_bar', '1.21', 'http://sf.net/foo_bar-1.21.tar.gz/download') @@ -59,216 +71,222 @@ class UrlParseTest(unittest.TestCase): self.assert_not_detected('foo') def test_version_all_dots(self): - self.assert_detected( + self.check( 'foo.bar.la', '1.14','http://example.com/foo.bar.la.1.14.zip') def test_version_underscore_separator(self): - self.assert_detected( + self.check( 'grc', '1.1', 'http://example.com/grc_1.1.tar.gz') def test_boost_version_style(self): - self.assert_detected( + self.check( 'boost', '1.39.0', - 'http://example.com/boost_1_39_0.tar.bz2') + 'http://example.com/boost_1_39_0.tar.bz2', + no_check_url=True) def test_erlang_version_style(self): - self.assert_detected( + self.check( 'otp', 'R13B', 'http://erlang.org/download/otp_src_R13B.tar.gz') def test_another_erlang_version_style(self): - self.assert_detected( + self.check( 'otp', 'R15B01', 'https://github.com/erlang/otp/tarball/OTP_R15B01') def test_yet_another_erlang_version_style(self): - self.assert_detected( + self.check( 'otp', 'R15B03-1', 'https://github.com/erlang/otp/tarball/OTP_R15B03-1') def test_p7zip_version_style(self): - self.assert_detected( + self.check( 'p7zip', '9.04', 'http://kent.dl.sourceforge.net/sourceforge/p7zip/p7zip_9.04_src_all.tar.bz2') def test_new_github_style(self): - self.assert_detected( + self.check( 'libnet', '1.1.4', 'https://github.com/sam-github/libnet/tarball/libnet-1.1.4') def test_gloox_beta_style(self): - self.assert_detected( + self.check( 'gloox', '1.0-beta7', 'http://camaya.net/download/gloox-1.0-beta7.tar.bz2') def test_sphinx_beta_style(self): - self.assert_detected( + self.check( 'sphinx', '1.10-beta', 'http://sphinxsearch.com/downloads/sphinx-1.10-beta.tar.gz') def test_astyle_verson_style(self): - self.assert_detected( + self.check( 'astyle', '1.23', 'http://kent.dl.sourceforge.net/sourceforge/astyle/astyle_1.23_macosx.tar.gz') def test_version_dos2unix(self): - self.assert_detected( + self.check( 'dos2unix', '3.1', 'http://www.sfr-fresh.com/linux/misc/dos2unix-3.1.tar.gz') def test_version_internal_dash(self): - self.assert_detected( + self.check( 'foo-arse', '1.1-2', 'http://example.com/foo-arse-1.1-2.tar.gz') def test_version_single_digit(self): - self.assert_detected( + self.check( 'foo_bar', '45', 'http://example.com/foo_bar.45.tar.gz') def test_noseparator_single_digit(self): - self.assert_detected( + self.check( 'foo_bar', '45', 'http://example.com/foo_bar45.tar.gz') def test_version_developer_that_hates_us_format(self): - self.assert_detected( + self.check( 'foo-bar-la', '1.2.3', 'http://example.com/foo-bar-la.1.2.3.tar.gz') def test_version_regular(self): - self.assert_detected( + self.check( 'foo_bar', '1.21', 'http://example.com/foo_bar-1.21.tar.gz') def test_version_github(self): - self.assert_detected( + self.check( 'yajl', '1.0.5', 'http://github.com/lloyd/yajl/tarball/1.0.5') def test_version_github_with_high_patch_number(self): - self.assert_detected( + self.check( 'yajl', '1.2.34', 'http://github.com/lloyd/yajl/tarball/v1.2.34') def test_yet_another_version(self): - self.assert_detected( + self.check( 'mad', '0.15.1b', 'http://example.com/mad-0.15.1b.tar.gz') def test_lame_version_style(self): - self.assert_detected( + self.check( 'lame', '398-2', 'http://kent.dl.sourceforge.net/sourceforge/lame/lame-398-2.tar.gz') def test_ruby_version_style(self): - self.assert_detected( + self.check( 'ruby', '1.9.1-p243', 'ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz') def test_omega_version_style(self): - self.assert_detected( + self.check( 'omega', '0.80.2', 'http://www.alcyone.com/binaries/omega/omega-0.80.2-src.tar.gz') def test_rc_style(self): - self.assert_detected( + self.check( 'libvorbis', '1.2.2rc1', 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.2.2rc1.tar.bz2') def test_dash_rc_style(self): - self.assert_detected( + self.check( 'js', '1.8.0-rc1', 'http://ftp.mozilla.org/pub/mozilla.org/js/js-1.8.0-rc1.tar.gz') def test_angband_version_style(self): - self.assert_detected( + self.check( 'angband', '3.0.9b', 'http://rephial.org/downloads/3.0/angband-3.0.9b-src.tar.gz') def test_stable_suffix(self): - self.assert_detected( + self.check( 'libevent', '1.4.14b', 'http://www.monkey.org/~provos/libevent-1.4.14b-stable.tar.gz') def test_debian_style_1(self): - self.assert_detected( + self.check( 'sl', '3.03', 'http://ftp.de.debian.org/debian/pool/main/s/sl/sl_3.03.orig.tar.gz') def test_debian_style_2(self): - self.assert_detected( + self.check( 'mmv', '1.01b', 'http://ftp.de.debian.org/debian/pool/main/m/mmv/mmv_1.01b.orig.tar.gz') def test_imagemagick_style(self): - self.assert_detected( + self.check( 'ImageMagick', '6.7.5-7', 'http://downloads.sf.net/project/machomebrew/mirror/ImageMagick-6.7.5-7.tar.bz2') def test_dash_version_dash_style(self): - self.assert_detected( + self.check( 'antlr', '3.4', 'http://www.antlr.org/download/antlr-3.4-complete.jar') def test_apache_version_style(self): - self.assert_detected( + self.check( 'apache-cassandra', '1.2.0-rc2', 'http://www.apache.org/dyn/closer.cgi?path=/cassandra/1.2.0/apache-cassandra-1.2.0-rc2-bin.tar.gz') def test_jpeg_style(self): - self.assert_detected( + self.check( 'jpegsrc', '8d', 'http://www.ijg.org/files/jpegsrc.v8d.tar.gz') def test_pypy_version(self): - self.assert_detected( + self.check( 'pypy', '1.4.1', 'http://pypy.org/download/pypy-1.4.1-osx.tar.bz2') def test_openssl_version(self): - self.assert_detected( + self.check( 'openssl', '0.9.8s', 'http://www.openssl.org/source/openssl-0.9.8s.tar.gz') def test_xaw3d_version(self): - self.assert_detected( + self.check( 'Xaw3d', '1.5E', 'ftp://ftp.visi.com/users/hawkeyd/X/Xaw3d-1.5E.tar.gz') def test_fann_version(self): - self.assert_detected( + self.check( 'fann', '2.1.0beta', 'http://downloads.sourceforge.net/project/fann/fann/2.1.0beta/fann-2.1.0beta.zip') def test_iges_version(self): - self.assert_detected( + self.check( 'grads', '2.0.1', 'ftp://iges.org/grads/2.0/grads-2.0.1-bin-darwin9.8-intel.tar.gz') def test_haxe_version(self): - self.assert_detected( + self.check( 'haxe', '2.08', 'http://haxe.org/file/haxe-2.08-osx.tar.gz') def test_imap_version(self): - self.assert_detected( + self.check( 'imap', '2007f', 'ftp://ftp.cac.washington.edu/imap/imap-2007f.tar.gz') def test_suite3270_version(self): - self.assert_detected( + self.check( 'suite3270', '3.3.12ga7', 'http://sourceforge.net/projects/x3270/files/x3270/3.3.12ga7/suite3270-3.3.12ga7-src.tgz') def test_synergy_version(self): - self.assert_detected( + self.check( 'synergy', '1.3.6p2', 'http://synergy.googlecode.com/files/synergy-1.3.6p2-MacOSX-Universal.zip') def test_mvapich2_version(self): - self.assert_detected( + self.check( 'mvapich2', '1.9', 'http://mvapich.cse.ohio-state.edu/download/mvapich2/mv2/mvapich2-1.9.tgz') + + def test_hdf5_version(self): + self.check( + 'hdf5', '1.8.13', + 'http://www.hdfgroup.org/ftp/HDF5/current/src/hdf5-1.8.13.tar.bz2') diff --git a/lib/spack/spack/url.py b/lib/spack/spack/url.py index deac156571..1b8120168f 100644 --- a/lib/spack/spack/url.py +++ b/lib/spack/spack/url.py @@ -191,6 +191,16 @@ def parse_name_and_version(path): return (name, ver) +def insensitize(string): + """Chagne upper and lowercase letters to be case insensitive in + the provided string. e.g., 'a' because '[Aa]', 'B' becomes + '[bB]', etc. Use for building regexes.""" + def to_ins(match): + char = match.group(1) + return '[%s%s]' % (char.lower(), char.upper()) + return re.sub(r'([a-zA-Z])', to_ins, string) + + def substitute_version(path, new_version): """Given a URL or archive name, find the version in the path and substitute the new version for it. @@ -203,11 +213,26 @@ def wildcard_version(path): """Find the version in the supplied path, and return a regular expression that will match this path with any version in its place. """ - ver, start, end = parse_version_string_with_indices(path) + # Get name and version, so we can treat them specially + name, v = parse_name_and_version(path) + + # Construct a case-insensitive regular expression for the package name. + name_re = '(%s)' % insensitize(name) + + # Split the string apart by things that match the name so that if the + # name contains numbers or things that look like versions, we don't + # catch them with the version wildcard. + name_parts = re.split(name_re, path) + + # Even elements in the array did *not* match the name + for i in xrange(0, len(name_parts), 2): + # Split each part by things that look like versions. + vparts = re.split(v.wildcard(), name_parts[i]) - v = Version(ver) - parts = [re.escape(p) for p in re.split(v.wildcard(), path)] + # Replace each version with a generic capture group to find versions. + # And escape everything else so it's not interpreted as a regex + vgroup = '(%s)' % v.wildcard() + name_parts[i] = vgroup.join(re.escape(vp) for vp in vparts) - # Make a group for the wildcard, so it will be captured by the regex. - version_group = '(%s)' % v.wildcard() - return version_group.join(parts) + # Put it all back together with original name matches intact. + return ''.join(name_parts) |