summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/package.py51
-rw-r--r--lib/spack/spack/repository.py39
2 files changed, 90 insertions, 0 deletions
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 5b1927fe8f..9f1825ca21 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -58,6 +58,7 @@ import spack.compilers
import spack.mirror
import spack.hooks
import spack.directives
+import spack.repository
import spack.build_environment
import spack.url
import spack.util.web
@@ -502,6 +503,7 @@ class Package(object):
self._fetcher = self._make_fetcher()
return self._fetcher
+
@fetcher.setter
def fetcher(self, f):
self._fetcher = f
@@ -905,6 +907,9 @@ class Package(object):
install(log_path, log_install_path)
install(env_path, env_install_path)
+ packages_dir = spack.install_layout.build_packages_path(self.spec)
+ dump_packages(self.spec, packages_dir)
+
# On successful install, remove the stage.
if not keep_stage:
self.stage.destroy()
@@ -1219,6 +1224,52 @@ def validate_package_url(url_string):
tty.die("Invalid file type in URL: '%s'" % url_string)
+def dump_packages(spec, path):
+ """Dump all package information for a spec and its dependencies.
+
+ This creates a package repository within path for every
+ namespace in the spec DAG, and fills the repos wtih package
+ files and patch files for every node in the DAG.
+ """
+ mkdirp(path)
+
+ # Copy in package.py files from any dependencies.
+ # Note that we copy them in as they are in the *install* directory
+ # NOT as they are in the repository, because we want a snapshot of
+ # how *this* particular build was done.
+ for node in spec.traverse():
+ if node is not spec:
+ # Locate the dependency package in the install tree and find
+ # its provenance information.
+ source = spack.install_layout.build_packages_path(node)
+ source_repo_root = join_path(source, node.namespace)
+
+ # There's no provenance installed for the source package. Skip it.
+ # User can always get something current from the builtin repo.
+ if not os.path.isdir(source_repo_root):
+ continue
+
+ # Create a source repo and get the pkg directory out of it.
+ try:
+ source_repo = spack.repository.Repo(source_repo_root)
+ source_pkg_dir = source_repo.dirname_for_package_name(node.name)
+ except RepoError as e:
+ tty.warn("Warning: Couldn't copy in provenance for %s" % node.name)
+
+ # Create a destination repository
+ dest_repo_root = join_path(path, node.namespace)
+ if not os.path.exists(dest_repo_root):
+ spack.repository.create_repo(dest_repo_root)
+ repo = spack.repository.Repo(dest_repo_root)
+
+ # Get the location of the package in the dest repo.
+ dest_pkg_dir = repo.dirname_for_package_name(node.name)
+ if node is not spec:
+ install_tree(source_pkg_dir, dest_pkg_dir)
+ else:
+ spack.repo.dump_provenance(node, dest_pkg_dir)
+
+
def print_pkg(message):
"""Outputs a message with a package icon."""
from llnl.util.tty.color import cwrite
diff --git a/lib/spack/spack/repository.py b/lib/spack/spack/repository.py
index 6aa75cb43e..8d06fefe7f 100644
--- a/lib/spack/spack/repository.py
+++ b/lib/spack/spack/repository.py
@@ -316,6 +316,16 @@ class RepoPath(object):
return self.repo_for_pkg(spec).get(spec)
+ @_autospec
+ def dump_provenance(self, spec, path):
+ """Dump provenance information for a spec to a particular path.
+
+ This dumps the package file and any associated patch files.
+ Raises UnknownPackageError if not found.
+ """
+ return self.repo_for_pkg(spec).dump_provenance(spec, path)
+
+
def dirname_for_package_name(self, pkg_name):
return self.repo_for_pkg(pkg_name).dirname_for_package_name(pkg_name)
@@ -552,6 +562,35 @@ class Repo(object):
return self._instances[key]
+ @_autospec
+ def dump_provenance(self, spec, path):
+ """Dump provenance information for a spec to a particular path.
+
+ This dumps the package file and any associated patch files.
+ Raises UnknownPackageError if not found.
+ """
+ # Some preliminary checks.
+ if spec.virtual:
+ raise UnknownPackageError(spec.name)
+
+ if spec.namespace and spec.namespace != self.namespace:
+ raise UnknownPackageError("Repository %s does not contain package %s."
+ % (self.namespace, spec.fullname))
+
+ # Install any patch files needed by packages.
+ mkdirp(path)
+ for spec, patches in spec.package.patches.items():
+ for patch in patches:
+ if patch.path:
+ if os.path.exists(patch.path):
+ install(patch.path, path)
+ else:
+ tty.warn("Patch file did not exist: %s" % patch.path)
+
+ # Install the package.py file itself.
+ install(self.filename_for_package_name(spec), path)
+
+
def purge(self):
"""Clear entire package instance cache."""
self._instances.clear()