summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@googlemail.com>2015-11-26 17:53:33 +0100
committerMassimiliano Culpo <massimiliano.culpo@googlemail.com>2015-11-26 17:53:33 +0100
commit1fe626ec7cd8b8a2bceb9e73dd9597d9f99813cf (patch)
tree7c10f88c31e1740d89cd28f42e23fbe4161b5ab6 /lib
parentf8ffb005c8780c786c7b0adc3ff5e314d410bbee (diff)
downloadspack-1fe626ec7cd8b8a2bceb9e73dd9597d9f99813cf.tar.gz
spack-1fe626ec7cd8b8a2bceb9e73dd9597d9f99813cf.tar.bz2
spack-1fe626ec7cd8b8a2bceb9e73dd9597d9f99813cf.tar.xz
spack-1fe626ec7cd8b8a2bceb9e73dd9597d9f99813cf.zip
resource directive : sketch of implementation + clang / llvm use case
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/llnl/util/lang.py2
-rw-r--r--lib/spack/spack/directives.py36
-rw-r--r--lib/spack/spack/package.py51
-rw-r--r--lib/spack/spack/resource.py37
4 files changed, 112 insertions, 14 deletions
diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py
index 156ee34c9e..e726368794 100644
--- a/lib/spack/llnl/util/lang.py
+++ b/lib/spack/llnl/util/lang.py
@@ -112,7 +112,7 @@ def partition_list(elements, predicate):
def caller_locals():
"""This will return the locals of the *parent* of the caller.
- This allows a fucntion to insert variables into its caller's
+ This allows a function to insert variables into its caller's
scope. Yes, this is some black magic, and yes it's useful
for implementing things like depends_on and provides.
"""
diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py
index 78039ac6f9..4d8333fd7d 100644
--- a/lib/spack/spack/directives.py
+++ b/lib/spack/spack/directives.py
@@ -44,11 +44,12 @@ The available directives are:
* ``variant``
"""
-__all__ = [ 'depends_on', 'extends', 'provides', 'patch', 'version',
- 'variant' ]
+__all__ = ['depends_on', 'extends', 'provides', 'patch', 'version',
+ 'variant', 'resource']
import re
import inspect
+import functools
from llnl.util.lang import *
@@ -60,7 +61,8 @@ from spack.version import Version
from spack.patch import Patch
from spack.variant import Variant
from spack.spec import Spec, parse_anonymous_spec
-
+from spack.resource import Resource
+from spack.fetch_strategy import URLFetchStrategy
#
# This is a list of all directives, built up as they are defined in
@@ -79,8 +81,8 @@ class directive(object):
"""Decorator for Spack directives.
Spack directives allow you to modify a package while it is being
- defined, e.g. to add version or depenency information. Directives
- are one of the key pieces of Spack's package "langauge", which is
+ defined, e.g. to add version or dependency information. Directives
+ are one of the key pieces of Spack's package "language", which is
embedded in python.
Here's an example directive:
@@ -141,6 +143,7 @@ class directive(object):
def __call__(self, directive_function):
directives[directive_function.__name__] = self
+ @functools.wraps(directive_function)
def wrapped(*args, **kwargs):
pkg = DictWrapper(caller_locals())
self.ensure_dicts(pkg)
@@ -259,6 +262,29 @@ def variant(pkg, name, default=False, description=""):
pkg.variants[name] = Variant(default, description)
+@directive('resources')
+def resource(pkg, **kwargs):
+ """
+ Define an external resource to be fetched and staged when building the package. Based on the keywords present in the
+ dictionary the appropriate FetchStrategy will be used for the resource.
+
+ List of recognized keywords:
+
+ * 'when' : represents the condition upon which the resource is needed (optional)
+ * 'destination' : path where to extract / checkout the resource (optional)
+
+ """
+ when = kwargs.get('when', pkg.name)
+ # FIXME : currently I assume destination to be a relative path (rooted at pkg.stage.source_path)
+ destination = kwargs.get('destination', "")
+ when_spec = parse_anonymous_spec(when, pkg.name)
+ resources = pkg.resources.setdefault(when_spec, [])
+ # FIXME : change URLFetchStrategy with a factory that selects based on kwargs
+ fetcher = URLFetchStrategy(**kwargs)
+ # FIXME : should we infer the name somehow if not passed ?
+ name = kwargs.get('name')
+ resources.append(Resource(name, fetcher, destination))
+
class DirectiveError(spack.error.SpackError):
"""This is raised when something is wrong with a package directive."""
def __init__(self, directive, message):
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index c631a35bf3..9fee962df3 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -639,26 +639,53 @@ class Package(object):
"Will not fetch %s." % self.spec.format('$_$@'), checksum_msg)
self.stage.fetch()
+
+ ##########
+ # Fetch resources
+ resources = self._get_resources()
+ # FIXME : choose the unique name appropriately. Is there a function somewhere for the base name ?
+ pieces = [self.name, str(self.version), self.spec.dag_hash()]
+ for resource in resources:
+ resource_stage_folder = '-'.join(pieces + [resource.name])
+ stage = Stage(resource.fetcher, name=resource_stage_folder)
+ resource.fetcher.set_stage(stage)
+ resource.fetcher.fetch()
+ ##########
+
self._fetch_time = time.time() - start_time
if spack.do_checksum and self.version in self.versions:
self.stage.check()
-
def do_stage(self):
"""Unpacks the fetched tarball, then changes into the expanded tarball
directory."""
if not self.spec.concrete:
raise ValueError("Can only stage concrete packages.")
- self.do_fetch()
+ def _expand_archive(stage, name=self.name):
+ archive_dir = stage.source_path
+ if not archive_dir:
+ stage.expand_archive()
+ tty.msg("Created stage in %s." % stage.path)
+ else:
+ tty.msg("Already staged %s in %s." % (name, stage.path))
- archive_dir = self.stage.source_path
- if not archive_dir:
- self.stage.expand_archive()
- tty.msg("Created stage in %s." % self.stage.path)
- else:
- tty.msg("Already staged %s in %s." % (self.name, self.stage.path))
+
+ self.do_fetch()
+ _expand_archive(self.stage)
+
+ ##########
+ # Stage resources in appropriate path
+ resources = self._get_resources()
+ for resource in resources:
+ stage = resource.fetcher.stage
+ _expand_archive(stage, resource.name)
+ link_path = join_path(self.stage.source_path, resource.destination, os.path.basename(stage.source_path))
+ if not os.path.exists(link_path):
+ # Create a symlink
+ os.symlink(stage.source_path, link_path)
+ ##########
self.stage.chdir_to_source()
@@ -730,6 +757,14 @@ class Package(object):
mkdirp(self.prefix.man1)
+ def _get_resources(self):
+ resources = []
+ # Select the resources that are needed for this build
+ for when_spec, resource_list in self.resources.items():
+ if when_spec in self.spec:
+ resources.extend(resource_list)
+ return resources
+
def _build_logger(self, log_path):
"""Create a context manager to log build output."""
diff --git a/lib/spack/spack/resource.py b/lib/spack/spack/resource.py
new file mode 100644
index 0000000000..00ee2d49e4
--- /dev/null
+++ b/lib/spack/spack/resource.py
@@ -0,0 +1,37 @@
+##############################################################################
+# 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
+##############################################################################
+"""
+Describes an optional resource needed for a build. Typically a bunch of sources that can be built in-tree within another
+package to enable optional features.
+"""
+
+class Resource(object):
+ """
+ Represents an optional resource. Aggregates a name, a fetcher and a destination.
+ """
+ def __init__(self, name, fetcher, destination):
+ self.name = name
+ self.fetcher = fetcher
+ self.destination = destination