Commands take specs as input instead of names.
modified clean, create, fetch, install, and uninstall
This commit is contained in:
		| @@ -1,7 +1,9 @@ | ||||
| import os | ||||
| import re | ||||
| import sys | ||||
|  | ||||
| import spack | ||||
| import spack.spec | ||||
| import spack.tty as tty | ||||
| import spack.attr as attr | ||||
|  | ||||
| @@ -21,10 +23,6 @@ | ||||
| commands.sort() | ||||
|  | ||||
|  | ||||
| def null_op(*args): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| def get_cmd_function_name(name): | ||||
|     return name.replace("-", "_") | ||||
|  | ||||
| @@ -36,7 +34,7 @@ def get_module(name): | ||||
|         module_name, fromlist=[name, SETUP_PARSER, DESCRIPTION], | ||||
|         level=0) | ||||
|  | ||||
|     attr.setdefault(module, SETUP_PARSER, null_op) | ||||
|     attr.setdefault(module, SETUP_PARSER, lambda *args: None) # null-op | ||||
|     attr.setdefault(module, DESCRIPTION, "") | ||||
|  | ||||
|     fn_name = get_cmd_function_name(name) | ||||
| @@ -50,3 +48,22 @@ def get_module(name): | ||||
| def get_command(name): | ||||
|     """Imports the command's function from a module and returns it.""" | ||||
|     return getattr(get_module(name), get_cmd_function_name(name)) | ||||
|  | ||||
|  | ||||
| def parse_specs(args): | ||||
|     """Convenience function for parsing arguments from specs.  Handles common | ||||
|        exceptions and dies if there are errors. | ||||
|     """ | ||||
|     if type(args) == list: | ||||
|         args = " ".join(args) | ||||
|  | ||||
|     try: | ||||
|         return spack.spec.parse(" ".join(args)) | ||||
|  | ||||
|     except spack.parse.ParseError, e: | ||||
|         e.print_error(sys.stdout) | ||||
|         sys.exit(1) | ||||
|  | ||||
|     except spack.spec.SpecError, e: | ||||
|         tty.error(e.message) | ||||
|         sys.exit(1) | ||||
|   | ||||
| @@ -1,3 +1,6 @@ | ||||
| import argparse | ||||
|  | ||||
| import spack.cmd | ||||
| import spack.packages as packages | ||||
| import spack.tty as tty | ||||
| import spack.stage as stage | ||||
| @@ -5,21 +8,22 @@ | ||||
| description = "Remove staged files for packages" | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     subparser.add_argument('names', nargs='+', help="name(s) of package(s) to clean") | ||||
|     subparser.add_argument('-c', "--clean", action="store_true", dest='clean', | ||||
|                            help="run make clean in the stage directory (default)") | ||||
|     subparser.add_argument('-w', "--work", action="store_true", dest='work', | ||||
|                            help="delete and re-expand the entire stage directory") | ||||
|     subparser.add_argument('-d', "--dist", action="store_true", dest='dist', | ||||
|                            help="delete the downloaded archive.") | ||||
|     subparser.add_argument('packages', nargs=argparse.REMAINDER, help="specs of packages to clean") | ||||
|  | ||||
|  | ||||
| def clean(parser, args): | ||||
|     if not args.names: | ||||
|         tty.die("spack clean requires at least one package name.") | ||||
|     if not args.packages: | ||||
|         tty.die("spack clean requires at least one package argument") | ||||
|  | ||||
|     for name in args.names: | ||||
|         package = packages.get(name) | ||||
|     specs = spack.cmd.parse_specs(args.packages) | ||||
|     for spec in specs: | ||||
|         package = packages.get(spec.name) | ||||
|         if args.dist: | ||||
|             package.do_clean_dist() | ||||
|         elif args.work: | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
| import spack | ||||
| import spack.packages as packages | ||||
| import spack.tty as tty | ||||
| import spack.version | ||||
| import spack.url | ||||
|  | ||||
| from spack.stage import Stage | ||||
| from contextlib import closing | ||||
| @@ -38,7 +38,7 @@ def create(parser, args): | ||||
|     url = args.url | ||||
|  | ||||
|     # Try to deduce name and version of the new package from the URL | ||||
|     name, version = spack.version.parse(url) | ||||
|     name, version = spack.url.parse_name_and_version(url) | ||||
|     if not name: | ||||
|         print "Couldn't guess a name for this package." | ||||
|         while not name: | ||||
|   | ||||
| @@ -1,12 +1,18 @@ | ||||
| import argparse | ||||
| import spack.cmd | ||||
| import spack.packages as packages | ||||
|  | ||||
| description = "Fetch archives for packages" | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     subparser.add_argument('names', nargs='+', help="names of packages to fetch") | ||||
|     subparser.add_argument('packages', nargs=argparse.REMAINDER, help="specs of packages to fetch") | ||||
|  | ||||
|  | ||||
| def fetch(parser, args): | ||||
|     for name in args.names: | ||||
|         package = packages.get(name) | ||||
|     if not args.packages: | ||||
|         tty.die("fetch requires at least one package argument") | ||||
|  | ||||
|     specs = spack.cmd.parse_specs(args.packages) | ||||
|     for spec in specs: | ||||
|         package = packages.get(spec.name) | ||||
|         package.do_fetch() | ||||
|   | ||||
| @@ -1,19 +1,28 @@ | ||||
| import sys | ||||
| import argparse | ||||
|  | ||||
| import spack | ||||
| import spack.packages as packages | ||||
| import spack.cmd | ||||
|  | ||||
| description = "Build and install packages" | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     subparser.add_argument('names', nargs='+', help="names of packages to install") | ||||
|     subparser.add_argument('-i', '--ignore-dependencies', | ||||
|                            action='store_true', dest='ignore_dependencies', | ||||
|                            help="Do not try to install dependencies of requested packages.") | ||||
|     subparser.add_argument('-d', '--dirty', action='store_true', dest='dirty', | ||||
|                            help="Don't clean up partially completed build/installation on error.") | ||||
|     subparser.add_argument('packages', nargs=argparse.REMAINDER, help="specs of packages to install") | ||||
|  | ||||
|  | ||||
| def install(parser, args): | ||||
|     if not args.packages: | ||||
|         tty.die("install requires at least one package argument") | ||||
|  | ||||
|     spack.ignore_dependencies = args.ignore_dependencies | ||||
|     for name in args.names: | ||||
|         package = packages.get(name) | ||||
|     specs = spack.cmd.parse_specs(args.packages) | ||||
|     for spec in specs: | ||||
|         package = packages.get(spec.name) | ||||
|         package.dirty = args.dirty | ||||
|         package.do_install() | ||||
|   | ||||
| @@ -1,15 +1,22 @@ | ||||
| import spack.cmd | ||||
| import spack.packages as packages | ||||
| import argparse | ||||
|  | ||||
| description="Remove an installed package" | ||||
|  | ||||
| def setup_parser(subparser): | ||||
|     subparser.add_argument('names', nargs='+', help="name(s) of package(s) to uninstall") | ||||
|     subparser.add_argument('-f', '--force', action='store_true', dest='force', | ||||
|                            help="Ignore installed packages that depend on this one and remove it anyway.") | ||||
|     subparser.add_argument('packages', nargs=argparse.REMAINDER, help="specs of packages to uninstall") | ||||
|  | ||||
| def uninstall(parser, args): | ||||
|     if not args.packages: | ||||
|         tty.die("uninstall requires at least one package argument.") | ||||
|  | ||||
|     specs = spack.cmd.parse_specs(args.packages) | ||||
|  | ||||
|     # get packages to uninstall as a list. | ||||
|     pkgs = [packages.get(name) for name in args.names] | ||||
|     pkgs = [packages.get(spec.name) for spec in specs] | ||||
|  | ||||
|     # Sort packages to be uninstalled by the number of installed dependents | ||||
|     # This ensures we do things in the right order | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
| class Dependency(object): | ||||
|     """Represents a dependency from one package to another. | ||||
|     """ | ||||
|     def __init__(self, name, version): | ||||
|     def __init__(self, name): | ||||
|         self.name = name | ||||
|  | ||||
|     @property | ||||
|   | ||||
| @@ -22,7 +22,7 @@ | ||||
| import tty | ||||
| import attr | ||||
| import validate | ||||
| import version | ||||
| import url | ||||
| import arch | ||||
|  | ||||
| from multi_function import platform | ||||
| @@ -261,7 +261,7 @@ def __init__(self, sys_type = arch.sys_type()): | ||||
|         validate.url(self.url) | ||||
|  | ||||
|         # Set up version | ||||
|         attr.setdefault(self, 'version', version.parse_version(self.url)) | ||||
|         attr.setdefault(self, 'version', url.parse_version(self.url)) | ||||
|         if not self.version: | ||||
|             tty.die("Couldn't extract version from %s. " + | ||||
|                     "You must specify it explicitly for this URL." % self.url) | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import re | ||||
| import spack.error as err | ||||
| import spack.tty as tty | ||||
| import itertools | ||||
|  | ||||
|  | ||||
| @@ -11,9 +12,7 @@ def __init__(self, message, string, pos): | ||||
|         self.pos = pos | ||||
|  | ||||
|     def print_error(self, out): | ||||
|         out.write(self.message + ":\n\n") | ||||
|         out.write("    " + self.string + "\n") | ||||
|         out.write("    " + self.pos * " " + "^\n\n") | ||||
|         tty.error(self.message, self.string, self.pos * " " + "^") | ||||
|  | ||||
|  | ||||
| class LexError(ParseError): | ||||
| @@ -107,7 +106,7 @@ def expect(self, id): | ||||
|             if self.next: | ||||
|                 self.unexpected_token() | ||||
|             else: | ||||
|                 self.next_token_error("Unexpected end of file") | ||||
|                 self.next_token_error("Unexpected end of input") | ||||
|             sys.exit(1) | ||||
|  | ||||
|     def parse(self, text): | ||||
|   | ||||
| @@ -44,6 +44,7 @@ class Mpileaks(Package): | ||||
|         spack install mpileaks ^mvapich | ||||
|         spack install mpileaks ^mpich | ||||
| """ | ||||
| import sys | ||||
| from dependency import Dependency | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -126,6 +126,9 @@ def expanded_archive_path(self): | ||||
|         """Returns the path to the expanded archive directory if it's expanded; | ||||
|            None if the archive hasn't been expanded. | ||||
|         """ | ||||
|         if not self.archive_file: | ||||
|             return None | ||||
|  | ||||
|         for file in os.listdir(self.path): | ||||
|             archive_path = spack.new_path(self.path, file) | ||||
|             if os.path.isdir(archive_path): | ||||
|   | ||||
| @@ -3,18 +3,19 @@ | ||||
| detection in Homebrew. | ||||
| """ | ||||
| import unittest | ||||
| import spack.version as ver | ||||
| import spack.url as url | ||||
| from pprint import pprint | ||||
|  | ||||
|  | ||||
| class UrlParseTest(unittest.TestCase): | ||||
|     def assert_not_detected(self, string): | ||||
|         self.assertRaises(ver.UndetectableVersionError, ver.parse, string) | ||||
|         self.assertRaises( | ||||
|             url.UndetectableVersionError, url.parse_name_and_version, string) | ||||
|  | ||||
|     def assert_detected(self, name, v, string): | ||||
|         parsed_name, parsed_v = ver.parse(string) | ||||
|         parsed_name, parsed_v = url.parse_name_and_version(string) | ||||
|         self.assertEqual(parsed_name, name) | ||||
|         self.assertEqual(parsed_v, ver.Version(v)) | ||||
|         self.assertEqual(parsed_v, url.Version(v)) | ||||
|  | ||||
|     def test_wwwoffle_version(self): | ||||
|         self.assert_detected( | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
| from spack.version import * | ||||
| 
 | ||||
| 
 | ||||
| class CompareVersionsTest(unittest.TestCase): | ||||
| class VersionsTest(unittest.TestCase): | ||||
| 
 | ||||
|     def assert_ver_lt(self, a, b): | ||||
|         a, b = ver(a), ver(b) | ||||
| @@ -129,7 +129,8 @@ def test_rpm_oddities(self): | ||||
|         self.assert_ver_lt('1.fc17',  '1g.fc17') | ||||
| 
 | ||||
| 
 | ||||
|     # Stuff below here is not taken from RPM's tests. | ||||
|     # Stuff below here is not taken from RPM's tests and is | ||||
|     # unique to spack | ||||
|     def test_version_ranges(self): | ||||
|         self.assert_ver_lt('1.2:1.4', '1.6') | ||||
|         self.assert_ver_gt('1.6', '1.2:1.4') | ||||
							
								
								
									
										166
									
								
								lib/spack/spack/url.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								lib/spack/spack/url.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,166 @@ | ||||
| """ | ||||
| This module has methods for parsing names and versions of packages from URLs. | ||||
| The idea is to allow package creators to supply nothing more than the | ||||
| download location of the package, and figure out version and name information | ||||
| from there. | ||||
|  | ||||
| Example: when spack is given the following URL: | ||||
|  | ||||
|     ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz | ||||
|  | ||||
| It can figure out that the package name is ruby, and that it is at version | ||||
| 1.9.1-p243.  This is useful for making the creation of packages simple: a user | ||||
| just supplies a URL and skeleton code is generated automatically. | ||||
|  | ||||
| Spack can also figure out that it can most likely download 1.8.1 at this URL: | ||||
|  | ||||
|     ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.8.1.tar.gz | ||||
|  | ||||
| This is useful if a user asks for a package at a particular version number; | ||||
| spack doesn't need anyone to tell it where to get the tarball even though | ||||
| it's never been told about that version before. | ||||
| """ | ||||
| import os | ||||
| import re | ||||
|  | ||||
| import spack.error | ||||
| import spack.utils | ||||
| from spack.version import Version | ||||
|  | ||||
|  | ||||
| class UrlParseError(spack.error.SpackError): | ||||
|     """Raised when the URL module can't parse something correctly.""" | ||||
|     def __init__(self, msg, spec): | ||||
|         super(UrlParseError, self).__init__(msg) | ||||
|         self.spec = spec | ||||
|  | ||||
|  | ||||
| class UndetectableVersionError(UrlParseError): | ||||
|     """Raised when we can't parse a version from a string.""" | ||||
|     def __init__(self, spec): | ||||
|         super(UndetectableVersionError, self).__init__( | ||||
|             "Couldn't detect version in: " + spec, spec) | ||||
|  | ||||
|  | ||||
| class UndetectableNameError(UrlParseError): | ||||
|     """Raised when we can't parse a package name from a string.""" | ||||
|     def __init__(self, spec): | ||||
|         super(UndetectableNameError, self).__init__( | ||||
|             "Couldn't parse package name in: " + spec) | ||||
|  | ||||
|  | ||||
| def parse_version_string_with_indices(spec): | ||||
|     """Try to extract a version string from a filename or URL.  This is taken | ||||
|        largely from Homebrew's Version class.""" | ||||
|  | ||||
|     if os.path.isdir(spec): | ||||
|         stem = os.path.basename(spec) | ||||
|     elif re.search(r'((?:sourceforge.net|sf.net)/.*)/download$', spec): | ||||
|         stem = spack.utils.stem(os.path.dirname(spec)) | ||||
|     else: | ||||
|         stem = spack.utils.stem(spec) | ||||
|  | ||||
|     version_types = [ | ||||
|         # GitHub tarballs, e.g. v1.2.3 | ||||
|         (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+)$', spec), | ||||
|  | ||||
|         # e.g. https://github.com/sam-github/libnet/tarball/libnet-1.1.4 | ||||
|         (r'github.com/.+/(?:zip|tar)ball/.*-((\d+\.)+\d+)$', spec), | ||||
|  | ||||
|         # e.g. https://github.com/isaacs/npm/tarball/v0.2.5-1 | ||||
|         (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+-(\d+))$', spec), | ||||
|  | ||||
|         # e.g. https://github.com/petdance/ack/tarball/1.93_02 | ||||
|         (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+_(\d+))$', spec), | ||||
|  | ||||
|         # e.g. https://github.com/erlang/otp/tarball/OTP_R15B01 (erlang style) | ||||
|         (r'[-_](R\d+[AB]\d*(-\d+)?)', spec), | ||||
|  | ||||
|         # e.g. boost_1_39_0 | ||||
|         (r'((\d+_)+\d+)$', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.1-1 | ||||
|         # e.g. ruby-1.9.1-p243 | ||||
|         (r'-((\d+\.)*\d\.\d+-(p|rc|RC)?\d+)(?:[-._](?:bin|dist|stable|src|sources))?$', stem), | ||||
|  | ||||
|         # e.g. lame-398-1 | ||||
|         (r'-((\d)+-\d)', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.1 | ||||
|         (r'-((\d+\.)*\d+)$', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.1b | ||||
|         (r'-((\d+\.)*\d+([a-z]|rc|RC)\d*)$', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.0-beta1, or foobar-4.50-beta | ||||
|         (r'-((\d+\.)*\d+-beta(\d+)?)$', stem), | ||||
|  | ||||
|         # e.g. foobar4.5.1 | ||||
|         (r'((\d+\.)*\d+)$', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.0-bin | ||||
|         (r'-((\d+\.)+\d+[a-z]?)[-._](bin|dist|stable|src|sources?)$', stem), | ||||
|  | ||||
|         # e.g. dash_0.5.5.1.orig.tar.gz (Debian style) | ||||
|         (r'_((\d+\.)+\d+[a-z]?)[.]orig$', stem), | ||||
|  | ||||
|         # e.g. http://www.openssl.org/source/openssl-0.9.8s.tar.gz | ||||
|         (r'-([^-]+)', stem), | ||||
|  | ||||
|         # e.g. astyle_1.23_macosx.tar.gz | ||||
|         (r'_([^_]+)', stem), | ||||
|  | ||||
|         # e.g. http://mirrors.jenkins-ci.org/war/1.486/jenkins.war | ||||
|         (r'\/(\d\.\d+)\/', spec), | ||||
|  | ||||
|         # e.g. http://www.ijg.org/files/jpegsrc.v8d.tar.gz | ||||
|         (r'\.v(\d+[a-z]?)', stem)] | ||||
|  | ||||
|     for vtype in version_types: | ||||
|         regex, match_string = vtype[:2] | ||||
|         match = re.search(regex, match_string) | ||||
|         if match and match.group(1) is not None: | ||||
|             return match.group(1), match.start(1), match.end(1) | ||||
|  | ||||
|     raise UndetectableVersionError(spec) | ||||
|  | ||||
|  | ||||
| def parse_version(spec): | ||||
|     """Given a URL or archive name, extract a version from it and return | ||||
|        a version object. | ||||
|     """ | ||||
|     ver, start, end = parse_version_string_with_indices(spec) | ||||
|     return Version(ver) | ||||
|  | ||||
|  | ||||
| def parse_name(spec, ver=None): | ||||
|     if ver is None: | ||||
|         ver = parse_version(spec) | ||||
|  | ||||
|     ntypes = (r'/sourceforge/([^/]+)/', | ||||
|               r'/([^/]+)/(tarball|zipball)/', | ||||
|               r'/([^/]+)[_.-](bin|dist|stable|src|sources)[_.-]%s' % ver, | ||||
|               r'/([^/]+)[_.-]v?%s' % ver, | ||||
|               r'/([^/]+)%s' % ver, | ||||
|               r'^([^/]+)[_.-]v?%s' % ver, | ||||
|               r'^([^/]+)%s' % ver) | ||||
|  | ||||
|     for nt in ntypes: | ||||
|         match = re.search(nt, spec) | ||||
|         if match: | ||||
|             return match.group(1) | ||||
|     raise UndetectableNameError(spec) | ||||
|  | ||||
|  | ||||
| def parse_name_and_version(spec): | ||||
|     ver = parse_version(spec) | ||||
|     name = parse_name(spec, ver) | ||||
|     return (name, ver) | ||||
|  | ||||
|  | ||||
| def create_version_format(spec): | ||||
|     """Given a URL or archive name, find the version and create a format string | ||||
|        that will allow another version to be substituted. | ||||
|     """ | ||||
|     ver, start, end = parse_version_string_with_indices(spec) | ||||
|     return spec[:start] + '%s' + spec[end:] | ||||
| @@ -3,7 +3,10 @@ | ||||
| from functools import total_ordering | ||||
|  | ||||
| import utils | ||||
| import spack.error as serr | ||||
| import spack.error | ||||
|  | ||||
| # Valid version characters | ||||
| VALID_VERSION = r'[A-Za-z0-9_.-]' | ||||
|  | ||||
|  | ||||
| def int_if_int(string): | ||||
| @@ -26,28 +29,37 @@ def ver(string): | ||||
| @total_ordering | ||||
| class Version(object): | ||||
|     """Class to represent versions""" | ||||
|     def __init__(self, version_string): | ||||
|     def __init__(self, string): | ||||
|         if not re.match(VALID_VERSION, string): | ||||
|             raise ValueError("Bad characters in version string: %s" % string) | ||||
|  | ||||
|         # preserve the original string | ||||
|         self.version_string = version_string | ||||
|         self.string = string | ||||
|  | ||||
|         # Split version into alphabetical and numeric segments | ||||
|         segments = re.findall(r'[a-zA-Z]+|[0-9]+', version_string) | ||||
|         segment_regex = r'[a-zA-Z]+|[0-9]+' | ||||
|         segments = re.findall(segment_regex, string) | ||||
|         self.version = tuple(int_if_int(seg) for seg in segments) | ||||
|  | ||||
|  | ||||
|     def up_to(self, index): | ||||
|         """Return a version string up to the specified component, exclusive. | ||||
|            e.g., if this is 10.8.2, self.up_to(2) will return '10.8'. | ||||
|         """ | ||||
|         return '.'.join(str(x) for x in self[:index]) | ||||
|  | ||||
|     def __iter__(self): | ||||
|         for v in self.version: | ||||
|             yield v | ||||
|  | ||||
|     def __getitem__(self, idx): | ||||
|         return tuple(self.version[idx]) | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return self.version_string | ||||
|         return self.string | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.version_string | ||||
|         return self.string | ||||
|  | ||||
|     def __lt__(self, other): | ||||
|         """Version comparison is designed for consistency with the way RPM | ||||
| @@ -145,144 +157,3 @@ def __str__(self): | ||||
|         if self.end: | ||||
|             out += str(self.end) | ||||
|         return out | ||||
|  | ||||
|  | ||||
| class VersionParseError(serr.SpackError): | ||||
|     """Raised when the version module can't parse something.""" | ||||
|     def __init__(self, msg, spec): | ||||
|         super(VersionParseError, self).__init__(msg) | ||||
|         self.spec = spec | ||||
|  | ||||
|  | ||||
| class UndetectableVersionError(VersionParseError): | ||||
|     """Raised when we can't parse a version from a string.""" | ||||
|     def __init__(self, spec): | ||||
|         super(UndetectableVersionError, self).__init__( | ||||
|             "Couldn't detect version in: " + spec, spec) | ||||
|  | ||||
|  | ||||
| class UndetectableNameError(VersionParseError): | ||||
|     """Raised when we can't parse a package name from a string.""" | ||||
|     def __init__(self, spec): | ||||
|         super(UndetectableNameError, self).__init__( | ||||
|             "Couldn't parse package name in: " + spec) | ||||
|  | ||||
|  | ||||
| def parse_version_string_with_indices(spec): | ||||
|     """Try to extract a version string from a filename or URL.  This is taken | ||||
|        largely from Homebrew's Version class.""" | ||||
|  | ||||
|     if os.path.isdir(spec): | ||||
|         stem = os.path.basename(spec) | ||||
|     elif re.search(r'((?:sourceforge.net|sf.net)/.*)/download$', spec): | ||||
|         stem = utils.stem(os.path.dirname(spec)) | ||||
|     else: | ||||
|         stem = utils.stem(spec) | ||||
|  | ||||
|     version_types = [ | ||||
|         # GitHub tarballs, e.g. v1.2.3 | ||||
|         (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+)$', spec), | ||||
|  | ||||
|         # e.g. https://github.com/sam-github/libnet/tarball/libnet-1.1.4 | ||||
|         (r'github.com/.+/(?:zip|tar)ball/.*-((\d+\.)+\d+)$', spec), | ||||
|  | ||||
|         # e.g. https://github.com/isaacs/npm/tarball/v0.2.5-1 | ||||
|         (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+-(\d+))$', spec), | ||||
|  | ||||
|         # e.g. https://github.com/petdance/ack/tarball/1.93_02 | ||||
|         (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+_(\d+))$', spec), | ||||
|  | ||||
|         # e.g. https://github.com/erlang/otp/tarball/OTP_R15B01 (erlang style) | ||||
|         (r'[-_](R\d+[AB]\d*(-\d+)?)', spec), | ||||
|  | ||||
|         # e.g. boost_1_39_0 | ||||
|         (r'((\d+_)+\d+)$', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.1-1 | ||||
|         # e.g. ruby-1.9.1-p243 | ||||
|         (r'-((\d+\.)*\d\.\d+-(p|rc|RC)?\d+)(?:[-._](?:bin|dist|stable|src|sources))?$', stem), | ||||
|  | ||||
|         # e.g. lame-398-1 | ||||
|         (r'-((\d)+-\d)', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.1 | ||||
|         (r'-((\d+\.)*\d+)$', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.1b | ||||
|         (r'-((\d+\.)*\d+([a-z]|rc|RC)\d*)$', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.0-beta1, or foobar-4.50-beta | ||||
|         (r'-((\d+\.)*\d+-beta(\d+)?)$', stem), | ||||
|  | ||||
|         # e.g. foobar4.5.1 | ||||
|         (r'((\d+\.)*\d+)$', stem), | ||||
|  | ||||
|         # e.g. foobar-4.5.0-bin | ||||
|         (r'-((\d+\.)+\d+[a-z]?)[-._](bin|dist|stable|src|sources?)$', stem), | ||||
|  | ||||
|         # e.g. dash_0.5.5.1.orig.tar.gz (Debian style) | ||||
|         (r'_((\d+\.)+\d+[a-z]?)[.]orig$', stem), | ||||
|  | ||||
|         # e.g. http://www.openssl.org/source/openssl-0.9.8s.tar.gz | ||||
|         (r'-([^-]+)', stem), | ||||
|  | ||||
|         # e.g. astyle_1.23_macosx.tar.gz | ||||
|         (r'_([^_]+)', stem), | ||||
|  | ||||
|         # e.g. http://mirrors.jenkins-ci.org/war/1.486/jenkins.war | ||||
|         (r'\/(\d\.\d+)\/', spec), | ||||
|  | ||||
|         # e.g. http://www.ijg.org/files/jpegsrc.v8d.tar.gz | ||||
|         (r'\.v(\d+[a-z]?)', stem)] | ||||
|  | ||||
|     for vtype in version_types: | ||||
|         regex, match_string = vtype[:2] | ||||
|         match = re.search(regex, match_string) | ||||
|         if match and match.group(1) is not None: | ||||
|             return match.group(1), match.start(1), match.end(1) | ||||
|  | ||||
|     raise UndetectableVersionError(spec) | ||||
|  | ||||
|  | ||||
| def parse_version(spec): | ||||
|     """Given a URL or archive name, extract a version from it and return | ||||
|        a version object. | ||||
|     """ | ||||
|     ver, start, end = parse_version_string_with_indices(spec) | ||||
|     return Version(ver) | ||||
|  | ||||
|  | ||||
| def create_version_format(spec): | ||||
|     """Given a URL or archive name, find the version and create a format string | ||||
|        that will allow another version to be substituted. | ||||
|     """ | ||||
|     ver, start, end = parse_version_string_with_indices(spec) | ||||
|     return spec[:start] + '%s' + spec[end:] | ||||
|  | ||||
|  | ||||
| def replace_version(spec, new_version): | ||||
|     version = create_version_format(spec) | ||||
|     # TODO: finish this function. | ||||
|  | ||||
| def parse_name(spec, ver=None): | ||||
|     if ver is None: | ||||
|         ver = parse_version(spec) | ||||
|  | ||||
|     ntypes = (r'/sourceforge/([^/]+)/', | ||||
|               r'/([^/]+)/(tarball|zipball)/', | ||||
|               r'/([^/]+)[_.-](bin|dist|stable|src|sources)[_.-]%s' % ver, | ||||
|               r'/([^/]+)[_.-]v?%s' % ver, | ||||
|               r'/([^/]+)%s' % ver, | ||||
|               r'^([^/]+)[_.-]v?%s' % ver, | ||||
|               r'^([^/]+)%s' % ver) | ||||
|  | ||||
|     for nt in ntypes: | ||||
|         match = re.search(nt, spec) | ||||
|         if match: | ||||
|             return match.group(1) | ||||
|     raise UndetectableNameError(spec) | ||||
|  | ||||
| def parse(spec): | ||||
|     ver = parse_version(spec) | ||||
|     name = parse_name(spec, ver) | ||||
|     return (name, ver) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Todd Gamblin
					Todd Gamblin