Initial version of spack with one package: cmake
This commit is contained in:
		
							
								
								
									
										168
									
								
								lib/spack/spack/Package.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								lib/spack/spack/Package.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
import inspect
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
from spack import *
 | 
			
		||||
import tty
 | 
			
		||||
import attr
 | 
			
		||||
import validate
 | 
			
		||||
import version
 | 
			
		||||
import shutil
 | 
			
		||||
import platform
 | 
			
		||||
from stage import Stage
 | 
			
		||||
 | 
			
		||||
def depends_on(*args, **kwargs):
 | 
			
		||||
    """Adds a depends_on local variable in the locals of
 | 
			
		||||
       the calling class, based on args.
 | 
			
		||||
    """
 | 
			
		||||
    stack = inspect.stack()
 | 
			
		||||
    try:
 | 
			
		||||
        locals = stack[1][0].f_locals
 | 
			
		||||
    finally:
 | 
			
		||||
        del stack
 | 
			
		||||
    print locals
 | 
			
		||||
 | 
			
		||||
    locals["depends_on"] = kwargs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Package(object):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        attr.required(self, 'homepage')
 | 
			
		||||
        attr.required(self, 'url')
 | 
			
		||||
        attr.required(self, 'md5')
 | 
			
		||||
 | 
			
		||||
        # Name of package is just the classname lowercased
 | 
			
		||||
        self.name = self.__class__.__name__.lower()
 | 
			
		||||
 | 
			
		||||
        # Make sure URL is an allowed type
 | 
			
		||||
        validate.url(self.url)
 | 
			
		||||
 | 
			
		||||
        v = version.parse(self.url)
 | 
			
		||||
        if not v:
 | 
			
		||||
            tty.die("Couldn't extract version from '%s'. " +
 | 
			
		||||
                    "You must specify it explicitly for this URL." % self.url)
 | 
			
		||||
        self.version = v
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def stage(self):
 | 
			
		||||
        return Stage(self.stage_name)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def stage_name(self):
 | 
			
		||||
        return "%s-%s" % (self.name, self.version)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def prefix(self):
 | 
			
		||||
        return new_path(install_path, self.stage_name)
 | 
			
		||||
 | 
			
		||||
    def do_fetch(self):
 | 
			
		||||
        """Creates a stage directory and downloads the taball for this package.
 | 
			
		||||
           Working directory will be set to the stage directory.
 | 
			
		||||
        """
 | 
			
		||||
        stage = self.stage
 | 
			
		||||
        stage.setup()
 | 
			
		||||
        stage.chdir()
 | 
			
		||||
 | 
			
		||||
        archive_file = os.path.basename(self.url)
 | 
			
		||||
        if not os.path.exists(archive_file):
 | 
			
		||||
            tty.msg("Fetching %s" % self.url)
 | 
			
		||||
 | 
			
		||||
            # Run curl but grab the mime type from the http headers
 | 
			
		||||
            headers = curl('-#', '-O', '-D', '-', self.url, return_output=True)
 | 
			
		||||
 | 
			
		||||
            # output this if we somehow got an HTML file rather than the archive we
 | 
			
		||||
            # asked for.
 | 
			
		||||
            if re.search(r'Content-Type: text/html', headers):
 | 
			
		||||
                tty.warn("The contents of '%s' look like HTML.  The checksum will "+
 | 
			
		||||
                         "likely fail.  Use 'spack clean %s' to delete this file. "
 | 
			
		||||
                         "The fix the gateway issue and install again." % (archive_file, self.name))
 | 
			
		||||
 | 
			
		||||
            if not os.path.exists(archive_file):
 | 
			
		||||
                tty.die("Failed to download '%s'!" % self.url)
 | 
			
		||||
        else:
 | 
			
		||||
            tty.msg("Already downloaded %s." % self.name)
 | 
			
		||||
 | 
			
		||||
        archive_md5 = md5(archive_file)
 | 
			
		||||
        if archive_md5 != self.md5:
 | 
			
		||||
            tty.die("MD5 Checksum failed for %s.  Expected %s but got %s."
 | 
			
		||||
                    % (self.name, self.md5, archive_md5))
 | 
			
		||||
 | 
			
		||||
        return archive_file
 | 
			
		||||
 | 
			
		||||
    def do_stage(self):
 | 
			
		||||
        """Unpacks the fetched tarball, then changes into the expanded tarball directory."""
 | 
			
		||||
        archive_file = self.do_fetch()
 | 
			
		||||
        stage = self.stage
 | 
			
		||||
 | 
			
		||||
        archive_dir = stage.archive_path
 | 
			
		||||
        if not archive_dir:
 | 
			
		||||
            tty.msg("Staging archive: '%s'" % archive_file)
 | 
			
		||||
            decompress = decompressor_for(archive_file)
 | 
			
		||||
            decompress(archive_file)
 | 
			
		||||
        else:
 | 
			
		||||
            tty.msg("Alredy staged %s" % self.name)
 | 
			
		||||
 | 
			
		||||
        stage.chdir_to_archive()
 | 
			
		||||
 | 
			
		||||
    def do_install(self):
 | 
			
		||||
        """This class should call this version of the install method.
 | 
			
		||||
           Package implementations should override install().
 | 
			
		||||
        """
 | 
			
		||||
        if os.path.exists(self.prefix):
 | 
			
		||||
            tty.msg("%s is already installed." % self.name)
 | 
			
		||||
            tty.pkg(self.prefix)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        self.do_stage()
 | 
			
		||||
 | 
			
		||||
        # Populate the module scope of install() with some useful functions.
 | 
			
		||||
        # This makes things easier for package writers.
 | 
			
		||||
        self.module.configure = which("configure", [self.stage.archive_path])
 | 
			
		||||
        self.module.cmake = which("cmake")
 | 
			
		||||
 | 
			
		||||
        self.install(self.prefix)
 | 
			
		||||
        tty.msg("Successfully installed %s" % self.name)
 | 
			
		||||
        tty.pkg(self.prefix)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def module(self):
 | 
			
		||||
        """Use this to add variables to the class's module's scope.
 | 
			
		||||
           This lets us use custom syntax in the install method.
 | 
			
		||||
        """
 | 
			
		||||
        return __import__(self.__class__.__module__,
 | 
			
		||||
                          fromlist=[self.__class__.__name__])
 | 
			
		||||
 | 
			
		||||
    def install(self, prefix):
 | 
			
		||||
        """Package implementations override this with their own build configuration."""
 | 
			
		||||
        tty.die("Packages must provide an install method!")
 | 
			
		||||
 | 
			
		||||
    def do_uninstall(self):
 | 
			
		||||
        self.uninstall(self.prefix)
 | 
			
		||||
        tty.msg("Successfully uninstalled %s." % self.name)
 | 
			
		||||
 | 
			
		||||
    def uninstall(self, prefix):
 | 
			
		||||
        """By default just blows the install dir away."""
 | 
			
		||||
        shutil.rmtree(self.prefix, True)
 | 
			
		||||
 | 
			
		||||
    def do_clean(self):
 | 
			
		||||
        self.clean()
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        """By default just runs make clean.  Override if this isn't good."""
 | 
			
		||||
        stage = self.stage
 | 
			
		||||
        if stage.archive_path:
 | 
			
		||||
            stage.chdir_to_archive()
 | 
			
		||||
            try:
 | 
			
		||||
                make("clean")
 | 
			
		||||
                tty.msg("Successfully cleaned %s" % self.name)
 | 
			
		||||
            except subprocess.CalledProcessError:
 | 
			
		||||
                # Might not be configured.  Ignore.
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
    def do_clean_all(self):
 | 
			
		||||
        if os.path.exists(self.stage.path):
 | 
			
		||||
            self.stage.destroy()
 | 
			
		||||
        tty.msg("Successfully cleaned %s" % self.name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								lib/spack/spack/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/spack/spack/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
 | 
			
		||||
from globals import *
 | 
			
		||||
from fileutils import *
 | 
			
		||||
 | 
			
		||||
from Package import Package, depends_on
 | 
			
		||||
							
								
								
									
										8
									
								
								lib/spack/spack/attr.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/spack/spack/attr.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import spack.tty as tty
 | 
			
		||||
 | 
			
		||||
def required(obj, attr_name):
 | 
			
		||||
    """Ensure that a class has a required attribute."""
 | 
			
		||||
    if not hasattr(obj, attr_name):
 | 
			
		||||
        tty.die("No required attribute '%s' in class '%s'"
 | 
			
		||||
                % (attr_name, obj.__class__.__name__))
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								lib/spack/spack/cmd/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								lib/spack/spack/cmd/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
import spack
 | 
			
		||||
import spack.tty as tty
 | 
			
		||||
 | 
			
		||||
SETUP_PARSER = "setup_parser"
 | 
			
		||||
command_path = os.path.join(spack.lib_path, "spack", "cmd")
 | 
			
		||||
 | 
			
		||||
commands = []
 | 
			
		||||
for file in os.listdir(command_path):
 | 
			
		||||
    if file.endswith(".py") and not file == "__init__.py":
 | 
			
		||||
        cmd = re.sub(r'.py$', '', file)
 | 
			
		||||
        commands.append(cmd)
 | 
			
		||||
commands.sort()
 | 
			
		||||
 | 
			
		||||
def null_op(*args):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_module(name):
 | 
			
		||||
    """Imports the module for a particular command name and returns it."""
 | 
			
		||||
    module_name = "%s.%s" % (__name__, name)
 | 
			
		||||
    module = __import__(module_name, fromlist=[name, SETUP_PARSER], level=0)
 | 
			
		||||
    module.setup_parser = getattr(module, SETUP_PARSER, null_op)
 | 
			
		||||
 | 
			
		||||
    if not hasattr(module, name):
 | 
			
		||||
        tty.die("Command module %s (%s) must define function '%s'."
 | 
			
		||||
                % (module.__name__, module.__file__, name))
 | 
			
		||||
 | 
			
		||||
    return module
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_command(name):
 | 
			
		||||
    """Imports the command's function from a module and returns it."""
 | 
			
		||||
    return getattr(get_module(name), name)
 | 
			
		||||
							
								
								
									
										12
									
								
								lib/spack/spack/cmd/arch.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/spack/spack/cmd/arch.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
from spack import *
 | 
			
		||||
import spack.version as version
 | 
			
		||||
 | 
			
		||||
import multiprocessing
 | 
			
		||||
import platform
 | 
			
		||||
 | 
			
		||||
def arch(args):
 | 
			
		||||
    print multiprocessing.cpu_count()
 | 
			
		||||
    print platform.mac_ver()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    print version.canonical(platform.mac_ver()[0])
 | 
			
		||||
							
								
								
									
										16
									
								
								lib/spack/spack/cmd/clean.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								lib/spack/spack/cmd/clean.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
import spack.packages as packages
 | 
			
		||||
 | 
			
		||||
def setup_parser(subparser):
 | 
			
		||||
    subparser.add_argument('name', help="name of package to clean")
 | 
			
		||||
    subparser.add_argument('-a', "--all", action="store_true", dest="all",
 | 
			
		||||
                           help="delete the entire stage directory")
 | 
			
		||||
 | 
			
		||||
def clean(args):
 | 
			
		||||
    package_class = packages.get(args.name)
 | 
			
		||||
    package = package_class()
 | 
			
		||||
    if args.all:
 | 
			
		||||
        package.do_clean_all()
 | 
			
		||||
    else:
 | 
			
		||||
        package.do_clean()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								lib/spack/spack/cmd/create.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								lib/spack/spack/cmd/create.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
import string
 | 
			
		||||
 | 
			
		||||
import spack
 | 
			
		||||
import spack.packages as packages
 | 
			
		||||
import spack.tty as tty
 | 
			
		||||
import spack.version
 | 
			
		||||
 | 
			
		||||
pacakge_tempate = string.Template("""\
 | 
			
		||||
from spack import *
 | 
			
		||||
 | 
			
		||||
class $name(Package):
 | 
			
		||||
    homepage = "${homepage}"
 | 
			
		||||
    url      = "${url}"
 | 
			
		||||
    md5      = "${md5}"
 | 
			
		||||
 | 
			
		||||
    def install(self):
 | 
			
		||||
        # Insert your installation code here.
 | 
			
		||||
        pass
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
def create_template(name):
 | 
			
		||||
    class_name = name.capitalize()
 | 
			
		||||
    return new_pacakge_tempate % class_name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def setup_parser(subparser):
 | 
			
		||||
    subparser.add_argument('url', nargs='?', help="url of package archive")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create(args):
 | 
			
		||||
    url = args.url
 | 
			
		||||
 | 
			
		||||
    version = spack.version.parse(url)
 | 
			
		||||
    if not version:
 | 
			
		||||
        tty.die("Couldn't figure out a version string from '%s'." % url)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # By default open the directory where packages live.
 | 
			
		||||
    if not name:
 | 
			
		||||
        path = spack.packages_path
 | 
			
		||||
    else:
 | 
			
		||||
        path = packages.filename_for(name)
 | 
			
		||||
 | 
			
		||||
        if os.path.exists(path):
 | 
			
		||||
            if not os.path.isfile(path):
 | 
			
		||||
                tty.die("Something's wrong.  '%s' is not a file!" % path)
 | 
			
		||||
            if not os.access(path, os.R_OK|os.W_OK):
 | 
			
		||||
                tty.die("Insufficient permissions on '%s'!" % path)
 | 
			
		||||
        else:
 | 
			
		||||
            tty.msg("Editing new file: '%s'." % path)
 | 
			
		||||
            file = open(path, "w")
 | 
			
		||||
            file.write(create_template(name))
 | 
			
		||||
            file.close()
 | 
			
		||||
 | 
			
		||||
    # If everything checks out, go ahead and edit.
 | 
			
		||||
    spack.editor(path)
 | 
			
		||||
							
								
								
									
										50
									
								
								lib/spack/spack/cmd/edit.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								lib/spack/spack/cmd/edit.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
import os
 | 
			
		||||
import spack
 | 
			
		||||
import spack.packages as packages
 | 
			
		||||
import spack.tty as tty
 | 
			
		||||
 | 
			
		||||
new_pacakge_tempate = """\
 | 
			
		||||
from spack import *
 | 
			
		||||
 | 
			
		||||
class %s(Package):
 | 
			
		||||
    homepage = "https://www.example.com"
 | 
			
		||||
    url      = "https://www.example.com/download/example-1.0.tar.gz"
 | 
			
		||||
    md5      = "nomd5"
 | 
			
		||||
 | 
			
		||||
    def install(self):
 | 
			
		||||
        # Insert your installation code here.
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
def create_template(name):
 | 
			
		||||
    class_name = name.capitalize()
 | 
			
		||||
    return new_pacakge_tempate % class_name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def setup_parser(subparser):
 | 
			
		||||
    subparser.add_argument(
 | 
			
		||||
        'name', nargs='?', default=None, help="name of package to edit")
 | 
			
		||||
 | 
			
		||||
def edit(args):
 | 
			
		||||
    name = args.name
 | 
			
		||||
 | 
			
		||||
    # By default open the directory where packages live.
 | 
			
		||||
    if not name:
 | 
			
		||||
        path = spack.packages_path
 | 
			
		||||
    else:
 | 
			
		||||
        path = packages.filename_for(name)
 | 
			
		||||
 | 
			
		||||
        if os.path.exists(path):
 | 
			
		||||
            if not os.path.isfile(path):
 | 
			
		||||
                tty.die("Something's wrong.  '%s' is not a file!" % path)
 | 
			
		||||
            if not os.access(path, os.R_OK|os.W_OK):
 | 
			
		||||
                tty.die("Insufficient permissions on '%s'!" % path)
 | 
			
		||||
        else:
 | 
			
		||||
            tty.msg("Editing new file: '%s'." % path)
 | 
			
		||||
            file = open(path, "w")
 | 
			
		||||
            file.write(create_template(name))
 | 
			
		||||
            file.close()
 | 
			
		||||
 | 
			
		||||
    # If everything checks out, go ahead and edit.
 | 
			
		||||
    spack.editor(path)
 | 
			
		||||
							
								
								
									
										9
									
								
								lib/spack/spack/cmd/fetch.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/spack/spack/cmd/fetch.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
import spack.packages as packages
 | 
			
		||||
 | 
			
		||||
def setup_parser(subparser):
 | 
			
		||||
    subparser.add_argument('name', help="name of package to fetch")
 | 
			
		||||
 | 
			
		||||
def fetch(args):
 | 
			
		||||
    package_class = packages.get(args.name)
 | 
			
		||||
    package = package_class()
 | 
			
		||||
    package.do_fetch()
 | 
			
		||||
							
								
								
									
										11
									
								
								lib/spack/spack/cmd/install.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								lib/spack/spack/cmd/install.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
import spack.packages as packages
 | 
			
		||||
 | 
			
		||||
def setup_parser(subparser):
 | 
			
		||||
    subparser.add_argument('name', help="name of package to install")
 | 
			
		||||
 | 
			
		||||
def install(args):
 | 
			
		||||
    package_class = packages.get(args.name)
 | 
			
		||||
    package = package_class()
 | 
			
		||||
    package.do_install()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								lib/spack/spack/cmd/stage.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/spack/spack/cmd/stage.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
import spack.packages as packages
 | 
			
		||||
 | 
			
		||||
def setup_parser(subparser):
 | 
			
		||||
    subparser.add_argument('name', help="name of package to stage")
 | 
			
		||||
 | 
			
		||||
def stage(args):
 | 
			
		||||
    package_class = packages.get(args.name)
 | 
			
		||||
    package = package_class()
 | 
			
		||||
    package.do_stage()
 | 
			
		||||
							
								
								
									
										9
									
								
								lib/spack/spack/cmd/uninstall.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/spack/spack/cmd/uninstall.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
import spack.packages as packages
 | 
			
		||||
 | 
			
		||||
def setup_parser(subparser):
 | 
			
		||||
    subparser.add_argument('name', help="name of package to uninstall")
 | 
			
		||||
 | 
			
		||||
def uninstall(args):
 | 
			
		||||
    package_class = packages.get(args.name)
 | 
			
		||||
    package = package_class()
 | 
			
		||||
    package.do_uninstall()
 | 
			
		||||
							
								
								
									
										112
									
								
								lib/spack/spack/fileutils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								lib/spack/spack/fileutils.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
import os
 | 
			
		||||
import subprocess
 | 
			
		||||
import re
 | 
			
		||||
from itertools import product
 | 
			
		||||
from contextlib import closing
 | 
			
		||||
 | 
			
		||||
import tty
 | 
			
		||||
 | 
			
		||||
# Supported archvie extensions.
 | 
			
		||||
PRE_EXTS = ["tar"]
 | 
			
		||||
EXTS     = ["gz", "bz2", "xz", "Z", "zip", "tgz"]
 | 
			
		||||
 | 
			
		||||
# Add EXTS last so that .tar.gz is matched *before* tar.gz
 | 
			
		||||
ALLOWED_ARCHIVE_TYPES = [".".join(l) for l in product(PRE_EXTS, EXTS)] + EXTS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def has_whitespace(string):
 | 
			
		||||
    return re.search(r'\s', string)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def new_path(prefix, *args):
 | 
			
		||||
    path=prefix
 | 
			
		||||
    for elt in args:
 | 
			
		||||
        path = os.path.join(path, elt)
 | 
			
		||||
 | 
			
		||||
    if has_whitespace(path):
 | 
			
		||||
        tty.die("Invalid path: '%s'.  Use a path without whitespace.")
 | 
			
		||||
 | 
			
		||||
    return path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def ancestor(dir, n=1):
 | 
			
		||||
    """Get the nth ancestor of a directory."""
 | 
			
		||||
    parent = os.path.abspath(dir)
 | 
			
		||||
    for i in range(n):
 | 
			
		||||
        parent = os.path.dirname(parent)
 | 
			
		||||
    return parent
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Executable(object):
 | 
			
		||||
    """Class representing a program that can be run on the command line."""
 | 
			
		||||
    def __init__(self, name):
 | 
			
		||||
        self.exe = name.split(' ')
 | 
			
		||||
 | 
			
		||||
    def add_default_arg(self, arg):
 | 
			
		||||
        self.exe.append(arg)
 | 
			
		||||
 | 
			
		||||
    def __call__(self, *args, **kwargs):
 | 
			
		||||
        """Run the executable with subprocess.check_output, return output."""
 | 
			
		||||
        return_output = kwargs.get("return_output", False)
 | 
			
		||||
 | 
			
		||||
        quoted_args = [arg for arg in args if re.search(r'^"|^\'|"$|\'$', arg)]
 | 
			
		||||
        if quoted_args:
 | 
			
		||||
            tty.warn("Quotes in package command arguments can confuse shell scripts like configure.",
 | 
			
		||||
                     "The following arguments may cause problems when executed:",
 | 
			
		||||
                     str("\n".join(["    "+arg for arg in quoted_args])),
 | 
			
		||||
                     "Quotes aren't needed because spack doesn't use a shell.  Consider removing them")
 | 
			
		||||
 | 
			
		||||
        cmd = self.exe + list(args)
 | 
			
		||||
        tty.verbose(cmd)
 | 
			
		||||
 | 
			
		||||
        if return_output:
 | 
			
		||||
            return subprocess.check_output(cmd)
 | 
			
		||||
        else:
 | 
			
		||||
            return subprocess.check_call(cmd)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return "<exe: %s>" % self.exe
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def which(name, path=None):
 | 
			
		||||
    """Finds an executable in the path like command-line which."""
 | 
			
		||||
    if not path:
 | 
			
		||||
        path = os.environ.get('PATH', '').split(os.pathsep)
 | 
			
		||||
    if not path:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    for dir in path:
 | 
			
		||||
        exe = os.path.join(dir, name)
 | 
			
		||||
        if os.access(exe, os.X_OK):
 | 
			
		||||
            return Executable(exe)
 | 
			
		||||
    return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def stem(path):
 | 
			
		||||
    """Get the part of a path that does not include its compressed
 | 
			
		||||
       type extension."""
 | 
			
		||||
    for type in ALLOWED_ARCHIVE_TYPES:
 | 
			
		||||
        suffix = r'\.%s$' % type
 | 
			
		||||
        if re.search(suffix, path):
 | 
			
		||||
            return re.sub(suffix, "", path)
 | 
			
		||||
    return path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def decompressor_for(path):
 | 
			
		||||
    """Get the appropriate decompressor for a path."""
 | 
			
		||||
    if which("tar"):
 | 
			
		||||
        return Executable("tar -xf")
 | 
			
		||||
    else:
 | 
			
		||||
        tty.die("spack requires tar.  Make sure it's on your path.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def md5(filename, block_size=2**20):
 | 
			
		||||
    import hashlib
 | 
			
		||||
    md5 = hashlib.md5()
 | 
			
		||||
    with closing(open(filename)) as file:
 | 
			
		||||
        while True:
 | 
			
		||||
            data = file.read(block_size)
 | 
			
		||||
            if not data:
 | 
			
		||||
                break
 | 
			
		||||
            md5.update(data)
 | 
			
		||||
        return md5.hexdigest()
 | 
			
		||||
							
								
								
									
										42
									
								
								lib/spack/spack/globals.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								lib/spack/spack/globals.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
import multiprocessing
 | 
			
		||||
from version import Version
 | 
			
		||||
 | 
			
		||||
import tty
 | 
			
		||||
from fileutils import *
 | 
			
		||||
 | 
			
		||||
# This lives in $prefix/lib/spac/spack/__file__
 | 
			
		||||
prefix = ancestor(__file__, 4)
 | 
			
		||||
 | 
			
		||||
# The spack script itself
 | 
			
		||||
spack_file = new_path(prefix, "bin", "spack")
 | 
			
		||||
 | 
			
		||||
# spack directory hierarchy
 | 
			
		||||
lib_path      = new_path(prefix, "lib", "spack")
 | 
			
		||||
module_path   = new_path(lib_path, "spack")
 | 
			
		||||
packages_path = new_path(module_path, "packages")
 | 
			
		||||
 | 
			
		||||
var_path      = new_path(prefix, "var", "spack")
 | 
			
		||||
stage_path    = new_path(var_path, "stage")
 | 
			
		||||
 | 
			
		||||
install_path  = new_path(prefix, "opt")
 | 
			
		||||
 | 
			
		||||
# Version information
 | 
			
		||||
version = Version("0.1")
 | 
			
		||||
 | 
			
		||||
# User's editor from the environment
 | 
			
		||||
editor = Executable(os.environ.get("EDITOR", ""))
 | 
			
		||||
 | 
			
		||||
# Curl tool for fetching files.
 | 
			
		||||
curl = which("curl")
 | 
			
		||||
if not curl:
 | 
			
		||||
    tty.die("spack requires curl.  Make sure it is in your path.")
 | 
			
		||||
 | 
			
		||||
make = which("make")
 | 
			
		||||
make.add_default_arg("-j%d" % multiprocessing.cpu_count())
 | 
			
		||||
if not make:
 | 
			
		||||
    tty.die("spack requires make.  Make sure it is in your path.")
 | 
			
		||||
 | 
			
		||||
verbose = False
 | 
			
		||||
debug = False
 | 
			
		||||
							
								
								
									
										35
									
								
								lib/spack/spack/packages/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								lib/spack/spack/packages/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
import spack
 | 
			
		||||
from spack.fileutils import *
 | 
			
		||||
 | 
			
		||||
import re
 | 
			
		||||
import inspect
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def filename_for(package):
 | 
			
		||||
    """Get the filename where a package name should be stored."""
 | 
			
		||||
    return new_path(spack.packages_path, "%s.py" % package.lower())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get(name):
 | 
			
		||||
    file = filename_for(name)
 | 
			
		||||
 | 
			
		||||
    if os.path.exists(file):
 | 
			
		||||
        if not os.path.isfile(file):
 | 
			
		||||
            tty.die("Something's wrong. '%s' is not a file!" % file)
 | 
			
		||||
        if not os.access(file, os.R_OK):
 | 
			
		||||
            tty.die("Cannot read '%s'!" % file)
 | 
			
		||||
 | 
			
		||||
    class_name = name.capitalize()
 | 
			
		||||
    try:
 | 
			
		||||
        module_name = "%s.%s" % (__name__, name)
 | 
			
		||||
        module = __import__(module_name, fromlist=[class_name])
 | 
			
		||||
    except ImportError, e:
 | 
			
		||||
        tty.die("Error while importing %s.%s:\n%s" % (name, class_name, e.message))
 | 
			
		||||
 | 
			
		||||
    klass = getattr(module, class_name)
 | 
			
		||||
    if not inspect.isclass(klass):
 | 
			
		||||
        tty.die("%s.%s is not a class" % (name, class_name))
 | 
			
		||||
 | 
			
		||||
    return klass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								lib/spack/spack/packages/cmake.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								lib/spack/spack/packages/cmake.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
from spack import *
 | 
			
		||||
 | 
			
		||||
class Cmake(Package):
 | 
			
		||||
    homepage  = 'https://www.cmake.org'
 | 
			
		||||
    url       = 'http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz'
 | 
			
		||||
    md5       = '097278785da7182ec0aea8769d06860c'
 | 
			
		||||
 | 
			
		||||
    def install(self, prefix):
 | 
			
		||||
        configure('--prefix=%s' % prefix)
 | 
			
		||||
        make()
 | 
			
		||||
        make('install')
 | 
			
		||||
							
								
								
									
										68
									
								
								lib/spack/spack/stage.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lib/spack/spack/stage.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
import os
 | 
			
		||||
import shutil
 | 
			
		||||
 | 
			
		||||
import spack
 | 
			
		||||
import tty
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def ensure_access(dir=spack.stage_path):
 | 
			
		||||
    if not os.access(dir, os.R_OK|os.W_OK):
 | 
			
		||||
        tty.die("Insufficient permissions on directory '%s'" % dir)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Stage(object):
 | 
			
		||||
    def __init__(self, stage_name):
 | 
			
		||||
        self.stage_name = stage_name
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def path(self):
 | 
			
		||||
        return spack.new_path(spack.stage_path, self.stage_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def setup(self):
 | 
			
		||||
        if os.path.exists(self.path):
 | 
			
		||||
            if not os.path.isdir(self.path):
 | 
			
		||||
                tty.die("Stage path '%s' is not a directory!" % self.path)
 | 
			
		||||
        else:
 | 
			
		||||
            os.makedirs(self.path)
 | 
			
		||||
 | 
			
		||||
        ensure_access(self.path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def archive_path(self):
 | 
			
		||||
        """"Returns the path to the expanded archive directory if it's expanded;
 | 
			
		||||
            None if the archive hasn't been expanded.
 | 
			
		||||
        """
 | 
			
		||||
        for file in os.listdir(self.path):
 | 
			
		||||
            archive_path = spack.new_path(self.path, file)
 | 
			
		||||
            if os.path.isdir(archive_path):
 | 
			
		||||
                return archive_path
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def chdir(self):
 | 
			
		||||
        """Changes directory to the stage path.  Or dies if it is not set up."""
 | 
			
		||||
        if os.path.isdir(self.path):
 | 
			
		||||
            os.chdir(self.path)
 | 
			
		||||
        else:
 | 
			
		||||
            tty.die("Attempt to chdir to stage before setup.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def chdir_to_archive(self):
 | 
			
		||||
        """Changes directory to the expanded archive directory if it exists.
 | 
			
		||||
           Dies with an error otherwise.
 | 
			
		||||
        """
 | 
			
		||||
        path = self.archive_path
 | 
			
		||||
        if not path:
 | 
			
		||||
            tty.die("Attempt to chdir before expanding archive.")
 | 
			
		||||
        else:
 | 
			
		||||
            os.chdir(path)
 | 
			
		||||
            if not os.listdir(path):
 | 
			
		||||
                tty.die("Archive was empty for '%s'" % self.name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def destroy(self):
 | 
			
		||||
        """Blows away the stage directory.  Can always call setup() again."""
 | 
			
		||||
        if os.path.exists(self.path):
 | 
			
		||||
            shutil.rmtree(self.path, True)
 | 
			
		||||
							
								
								
									
										189
									
								
								lib/spack/spack/test/test_versions.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										189
									
								
								lib/spack/spack/test/test_versions.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,189 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
"""\
 | 
			
		||||
This file has a bunch of versions tests taken from the excellent version
 | 
			
		||||
detection in Homebrew.
 | 
			
		||||
"""
 | 
			
		||||
import spack.version as version
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VersionTest(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def assert_not_detected(self, string):
 | 
			
		||||
        self.assertIsNone(version.parse(string))
 | 
			
		||||
 | 
			
		||||
    def assert_detected(self, v, string):
 | 
			
		||||
        self.assertEqual(v, version.parse(string))
 | 
			
		||||
 | 
			
		||||
    def test_wwwoffle_version(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '2.9h', 'http://www.gedanken.demon.co.uk/download-wwwoffle/wwwoffle-2.9h.tgz')
 | 
			
		||||
 | 
			
		||||
    def test_version_sourceforge_download(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.21', 'http://sourceforge.net/foo_bar-1.21.tar.gz/download')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.21', 'http://sf.net/foo_bar-1.21.tar.gz/download')
 | 
			
		||||
 | 
			
		||||
    def test_no_version(self):
 | 
			
		||||
        self.assert_not_detected('http://example.com/blah.tar')
 | 
			
		||||
        self.assert_not_detected('foo')
 | 
			
		||||
 | 
			
		||||
    def test_version_all_dots(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.14','http://example.com/foo.bar.la.1.14.zip')
 | 
			
		||||
 | 
			
		||||
    def test_version_underscore_separator(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.1', 'http://example.com/grc_1.1.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_boost_version_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.39.0', 'http://example.com/boost_1_39_0.tar.bz2')
 | 
			
		||||
 | 
			
		||||
    def test_erlang_version_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            'R13B', 'http://erlang.org/download/otp_src_R13B.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_another_erlang_version_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            'R15B01', 'https://github.com/erlang/otp/tarball/OTP_R15B01')
 | 
			
		||||
 | 
			
		||||
    def test_yet_another_erlang_version_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            'R15B03-1', 'https://github.com/erlang/otp/tarball/OTP_R15B03-1')
 | 
			
		||||
 | 
			
		||||
    def test_p7zip_version_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '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(
 | 
			
		||||
            '1.1.4', 'https://github.com/sam-github/libnet/tarball/libnet-1.1.4')
 | 
			
		||||
 | 
			
		||||
    def test_gloox_beta_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.0-beta7', 'http://camaya.net/download/gloox-1.0-beta7.tar.bz2')
 | 
			
		||||
 | 
			
		||||
    def test_sphinx_beta_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.10-beta', 'http://sphinxsearch.com/downloads/sphinx-1.10-beta.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_astyle_verson_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.23', 'http://kent.dl.sourceforge.net/sourceforge/astyle/astyle_1.23_macosx.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_version_dos2unix(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '3.1', 'http://www.sfr-fresh.com/linux/misc/dos2unix-3.1.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_version_internal_dash(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.1-2', 'http://example.com/foo-arse-1.1-2.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_version_single_digit(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '45', 'http://example.com/foo_bar.45.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_noseparator_single_digit(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '45', 'http://example.com/foo_bar45.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_version_developer_that_hates_us_format(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.2.3', 'http://example.com/foo-bar-la.1.2.3.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_version_regular(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.21', 'http://example.com/foo_bar-1.21.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_version_github(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.0.5', 'http://github.com/lloyd/yajl/tarball/1.0.5')
 | 
			
		||||
 | 
			
		||||
    def test_version_github_with_high_patch_number(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.2.34', 'http://github.com/lloyd/yajl/tarball/v1.2.34')
 | 
			
		||||
 | 
			
		||||
    def test_yet_another_version(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '0.15.1b', 'http://example.com/mad-0.15.1b.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_lame_version_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '398-2', 'http://kent.dl.sourceforge.net/sourceforge/lame/lame-398-2.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_ruby_version_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '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(
 | 
			
		||||
            '0.80.2', 'http://www.alcyone.com/binaries/omega/omega-0.80.2-src.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_rc_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.2.2rc1', 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.2.2rc1.tar.bz2')
 | 
			
		||||
 | 
			
		||||
    def test_dash_rc_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '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(
 | 
			
		||||
            '3.0.9b', 'http://rephial.org/downloads/3.0/angband-3.0.9b-src.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_stable_suffix(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.4.14b', 'http://www.monkey.org/~provos/libevent-1.4.14b-stable.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_debian_style_1(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '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(
 | 
			
		||||
            '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(
 | 
			
		||||
            '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(
 | 
			
		||||
            '3.4', 'http://www.antlr.org/download/antlr-3.4-complete.jar')
 | 
			
		||||
 | 
			
		||||
    def test_apache_version_style(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '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(
 | 
			
		||||
            '8d', 'http://www.ijg.org/files/jpegsrc.v8d.tar.gz')
 | 
			
		||||
 | 
			
		||||
    def test_more_versions(self):
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.4.1', 'http://pypy.org/download/pypy-1.4.1-osx.tar.bz2')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '0.9.8s', 'http://www.openssl.org/source/openssl-0.9.8s.tar.gz')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.5E', 'ftp://ftp.visi.com/users/hawkeyd/X/Xaw3d-1.5E.tar.gz')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '2.1.0beta', 'http://downloads.sourceforge.net/project/fann/fann/2.1.0beta/fann-2.1.0beta.zip')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '2.0.1', 'ftp://iges.org/grads/2.0/grads-2.0.1-bin-darwin9.8-intel.tar.gz')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '2.08', 'http://haxe.org/file/haxe-2.08-osx.tar.gz')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '2007f', 'ftp://ftp.cac.washington.edu/imap/imap-2007f.tar.gz')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '3.3.12ga7', 'http://sourceforge.net/projects/x3270/files/x3270/3.3.12ga7/suite3270-3.3.12ga7-src.tgz')
 | 
			
		||||
        self.assert_detected(
 | 
			
		||||
            '1.3.6p2', 'http://synergy.googlecode.com/files/synergy-1.3.6p2-MacOSX-Universal.zip')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    unittest.main()
 | 
			
		||||
							
								
								
									
										63
									
								
								lib/spack/spack/tty.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								lib/spack/spack/tty.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
import sys
 | 
			
		||||
import spack
 | 
			
		||||
 | 
			
		||||
indent = "  "
 | 
			
		||||
 | 
			
		||||
def escape(s):
 | 
			
		||||
    """Returns a TTY escape code if stdout is a tty, otherwise empty string"""
 | 
			
		||||
    if sys.stdout.isatty():
 | 
			
		||||
        return "\033[{}m".format(s)
 | 
			
		||||
    return ''
 | 
			
		||||
 | 
			
		||||
def color(n):
 | 
			
		||||
    return escape("0;{}".format(n))
 | 
			
		||||
 | 
			
		||||
def bold(n):
 | 
			
		||||
    return escape("1;{}".format(n))
 | 
			
		||||
 | 
			
		||||
def underline(n):
 | 
			
		||||
    return escape("4;{}".format(n))
 | 
			
		||||
 | 
			
		||||
blue   = bold(34)
 | 
			
		||||
white  = bold(39)
 | 
			
		||||
red    = bold(31)
 | 
			
		||||
yellow = underline(33)
 | 
			
		||||
green  = bold(92)
 | 
			
		||||
gray   = bold(30)
 | 
			
		||||
em     = underline(39)
 | 
			
		||||
reset  = escape(0)
 | 
			
		||||
 | 
			
		||||
def msg(msg, *args, **kwargs):
 | 
			
		||||
    color = kwargs.get("color", blue)
 | 
			
		||||
    print "{}==>{} {}{}".format(color, white, str(msg), reset)
 | 
			
		||||
    for arg in args: print indent + str(arg)
 | 
			
		||||
 | 
			
		||||
def verbose(*args):
 | 
			
		||||
    if spack.verbose: msg(*args, color=green)
 | 
			
		||||
 | 
			
		||||
def debug(*args):
 | 
			
		||||
    if spack.debug: msg(*args, color=red)
 | 
			
		||||
 | 
			
		||||
def error(msg, *args):
 | 
			
		||||
    print "{}Error{}: {}".format(red, reset, str(msg))
 | 
			
		||||
    for arg in args: print indent + str(arg)
 | 
			
		||||
 | 
			
		||||
def warn(msg, *args):
 | 
			
		||||
    print "{}Warning{}: {}".format(yellow, reset, str(msg))
 | 
			
		||||
    for arg in args: print indent + str(arg)
 | 
			
		||||
 | 
			
		||||
def die(msg):
 | 
			
		||||
    error(msg)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
def pkg(msg):
 | 
			
		||||
    """Outputs a message with a package icon."""
 | 
			
		||||
    import platform
 | 
			
		||||
    from version import Version
 | 
			
		||||
 | 
			
		||||
    mac_version = platform.mac_ver()[0]
 | 
			
		||||
    if Version(mac_version) >= Version("10.7"):
 | 
			
		||||
        print u"\U0001F4E6" + indent,
 | 
			
		||||
    else:
 | 
			
		||||
        print '[%] ',
 | 
			
		||||
    print msg
 | 
			
		||||
							
								
								
									
										13
									
								
								lib/spack/spack/validate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lib/spack/spack/validate.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
import tty
 | 
			
		||||
from fileutils import ALLOWED_ARCHIVE_TYPES
 | 
			
		||||
from urlparse import urlparse
 | 
			
		||||
 | 
			
		||||
ALLOWED_SCHEMES    = ["http", "https", "ftp"]
 | 
			
		||||
 | 
			
		||||
def url(url_string):
 | 
			
		||||
    url = urlparse(url_string)
 | 
			
		||||
    if url.scheme not in ALLOWED_SCHEMES:
 | 
			
		||||
        tty.die("Invalid protocol in URL: '%s'" % url_string)
 | 
			
		||||
 | 
			
		||||
    if not any(url_string.endswith(t) for t in ALLOWED_ARCHIVE_TYPES):
 | 
			
		||||
        tty.die("Invalid file type in URL: '%s'" % url_string)
 | 
			
		||||
							
								
								
									
										126
									
								
								lib/spack/spack/version.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								lib/spack/spack/version.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
import fileutils
 | 
			
		||||
 | 
			
		||||
class Version(object):
 | 
			
		||||
    """Class to represent versions"""
 | 
			
		||||
    def __init__(self, version_string):
 | 
			
		||||
        self.version_string = version_string
 | 
			
		||||
        self.version = canonical(version_string)
 | 
			
		||||
 | 
			
		||||
    def __cmp__(self, other):
 | 
			
		||||
        return cmp(self.version, other.version)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def major(self):
 | 
			
		||||
        return self.component(0)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def minor(self):
 | 
			
		||||
        return self.component(1)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def patch(self):
 | 
			
		||||
        return self.component(2)
 | 
			
		||||
 | 
			
		||||
    def component(self, i):
 | 
			
		||||
        """Returns the ith version component"""
 | 
			
		||||
        if len(self.version) > i:
 | 
			
		||||
            return self.version[i]
 | 
			
		||||
        else:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return self.version_string
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.version_string
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def canonical(v):
 | 
			
		||||
    """Get a "canonical" version of a version string, as a tuple."""
 | 
			
		||||
    def intify(part):
 | 
			
		||||
        try:
 | 
			
		||||
            return int(part)
 | 
			
		||||
        except:
 | 
			
		||||
            return part
 | 
			
		||||
    return tuple(intify(v) for v in re.split(r'[_.-]+', v))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse(spec):
 | 
			
		||||
    """Try to extract a version from a filename.  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 = fileutils.stem(os.path.dirname(spec))
 | 
			
		||||
    else:
 | 
			
		||||
        stem = fileutils.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, lambda s: s.replace('_', '.')),
 | 
			
		||||
 | 
			
		||||
        # 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 type in version_types:
 | 
			
		||||
        regex, match_string = type[:2]
 | 
			
		||||
        match = re.search(regex, match_string)
 | 
			
		||||
        if match and match.group(1) is not None:
 | 
			
		||||
            if type[2:]:
 | 
			
		||||
                return Version(type[2](match.group(1)))
 | 
			
		||||
            else:
 | 
			
		||||
                return Version(match.group(1))
 | 
			
		||||
    return None
 | 
			
		||||
		Reference in New Issue
	
	Block a user