summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2016-03-06 16:51:09 -0800
committerTodd Gamblin <tgamblin@llnl.gov>2016-03-06 16:51:09 -0800
commit240ada5775c7857932279d86e4305ef001d33717 (patch)
treee33bd2a1d2ed1a602273c259e7db855c03f69614 /lib
parente515042a36e7aa21e52943dab1e8b5594f3f0e94 (diff)
downloadspack-240ada5775c7857932279d86e4305ef001d33717.tar.gz
spack-240ada5775c7857932279d86e4305ef001d33717.tar.bz2
spack-240ada5775c7857932279d86e4305ef001d33717.tar.xz
spack-240ada5775c7857932279d86e4305ef001d33717.zip
Add `expand=False` option for URL downloads.
- Allows skipping the expand step for downloads. - Fixed stage so that it knows expansion didn't fail when there is a no-expand URLFetchStrategy. - Updated docs to reflect new option, and provided an example.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/docs/packaging_guide.rst29
-rw-r--r--lib/spack/llnl/util/filesystem.py9
-rw-r--r--lib/spack/spack/fetch_strategy.py7
-rw-r--r--lib/spack/spack/mirror.py13
-rw-r--r--lib/spack/spack/stage.py48
5 files changed, 86 insertions, 20 deletions
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst
index 59ba63fa35..bae8c34d52 100644
--- a/lib/spack/docs/packaging_guide.rst
+++ b/lib/spack/docs/packaging_guide.rst
@@ -401,6 +401,35 @@ construct the new one for ``8.2.1``.
When you supply a custom URL for a version, Spack uses that URL
*verbatim* and does not perform extrapolation.
+Skipping the expand step
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Spack normally expands archives automatically after downloading
+them. If you want to skip this step (e.g., for self-extracting
+executables and other custom archive types), you can add
+``expand=False`` to a ``version`` directive.
+
+.. code-block:: python
+
+ version('8.2.1', '4136d7b4c04df68b686570afa26988ac',
+ url='http://example.com/foo-8.2.1-special-version.tar.gz', 'expand=False')
+
+When ``expand`` is set to ``False``, Spack sets the current working
+directory to the directory containing the downloaded archive before it
+calls your ``install`` method. Within ``install``, the path to the
+downloaded archive is available as ``self.stage.archive_file``.
+
+Here is an example snippet for packages distribuetd as self-extracting
+archives. The example sets permissions on the downloaded file to make
+it executable, then runs it with some arguments.
+
+.. code-block:: python
+
+ def install(self, spec, prefix):
+ set_executable(self.stage.archive_file)
+ installer = Executable(self.stage.archive_file)
+ installer('--prefix=%s' % prefix, 'arg1', 'arg2', 'etc.')
+
Checksums
~~~~~~~~~~~~~~~~~
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index a92cb0706d..f218b7c424 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -25,7 +25,8 @@
__all__ = ['set_install_permissions', 'install', 'install_tree', 'traverse_tree',
'expand_user', 'working_dir', 'touch', 'touchp', 'mkdirp',
'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file',
- 'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink', 'remove_dead_links', 'remove_linked_tree']
+ 'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink',
+ 'set_executable', 'remove_dead_links', 'remove_linked_tree']
import os
import sys
@@ -345,6 +346,12 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
if order == 'post':
yield (source_path, dest_path)
+
+def set_executable(path):
+ st = os.stat(path)
+ os.chmod(path, st.st_mode | stat.S_IEXEC)
+
+
def remove_dead_links(root):
"""
Removes any dead link that is present in root
diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py
index ec17cb97f1..0d0a7db8a9 100644
--- a/lib/spack/spack/fetch_strategy.py
+++ b/lib/spack/spack/fetch_strategy.py
@@ -82,7 +82,6 @@ class FetchStrategy(object):
class __metaclass__(type):
"""This metaclass registers all fetch strategies in a list."""
-
def __init__(cls, name, bases, dict):
type.__init__(cls, name, bases, dict)
if cls.enabled: all_strategies.append(cls)
@@ -145,6 +144,8 @@ class URLFetchStrategy(FetchStrategy):
self.digest = kwargs.get('md5', None)
if not self.digest: self.digest = digest
+ self.expand_archive = kwargs.get('expand', True)
+
if not self.url:
raise ValueError("URLFetchStrategy requires a url for fetching.")
@@ -218,6 +219,10 @@ class URLFetchStrategy(FetchStrategy):
@_needs_stage
def expand(self):
+ if not self.expand_archive:
+ tty.msg("Skipping expand step for %s" % self.archive_file)
+ return
+
tty.msg("Staging archive: %s" % self.archive_file)
self.stage.chdir()
diff --git a/lib/spack/spack/mirror.py b/lib/spack/spack/mirror.py
index fdc4e7967f..6981f69ac0 100644
--- a/lib/spack/spack/mirror.py
+++ b/lib/spack/spack/mirror.py
@@ -51,13 +51,20 @@ def mirror_archive_filename(spec, fetcher):
raise ValueError("mirror.path requires spec with concrete version.")
if isinstance(fetcher, fs.URLFetchStrategy):
- # If we fetch this version with a URLFetchStrategy, use URL's archive type
- ext = url.downloaded_file_extension(fetcher.url)
+ if fetcher.expand_archive:
+ # If we fetch this version with a URLFetchStrategy, use URL's archive type
+ ext = url.downloaded_file_extension(fetcher.url)
+ else:
+ # If the archive shouldn't be expanded, don't check for its extension.
+ ext = None
else:
# Otherwise we'll make a .tar.gz ourselves
ext = 'tar.gz'
- return "%s-%s.%s" % (spec.package.name, spec.version, ext)
+ filename = "%s-%s" % (spec.package.name, spec.version)
+ if ext:
+ filename += ".%s" % ext
+ return filename
def mirror_archive_path(spec, fetcher):
diff --git a/lib/spack/spack/stage.py b/lib/spack/spack/stage.py
index b117c76aa1..b405915a75 100644
--- a/lib/spack/spack/stage.py
+++ b/lib/spack/spack/stage.py
@@ -229,13 +229,22 @@ class Stage(object):
@property
def source_path(self):
- """Returns the path to the expanded/checked out source code
- within this fetch strategy's path.
+ """Returns the path to the expanded/checked out source code.
- This assumes nothing else is going ot be put in the
- FetchStrategy's path. It searches for the first
- subdirectory of the path it can find, then returns that.
+ To find the source code, this method searches for the first
+ subdirectory of the stage that it can find, and returns it.
+ This assumes nothing besides the archive file will be in the
+ stage path, but it has the advantage that we don't need to
+ know the name of the archive or its contents.
+
+ If the fetch strategy is not supposed to expand the downloaded
+ file, it will just return the stage path. If the archive needs
+ to be expanded, it will return None when no archive is found.
"""
+ if isinstance(self.fetcher, fs.URLFetchStrategy):
+ if not self.fetcher.expand_archive:
+ return self.path
+
for p in [os.path.join(self.path, f) for f in os.listdir(self.path)]:
if os.path.isdir(p):
return p
@@ -416,21 +425,15 @@ class ResourceStage(Stage):
shutil.move(source_path, destination_path)
-@pattern.composite(method_list=['fetch', 'create', 'check', 'expand_archive', 'restage', 'destroy'])
+@pattern.composite(method_list=['fetch', 'create', 'check', 'expand_archive', 'restage', 'destroy'])
class StageComposite:
"""
Composite for Stage type objects. The first item in this composite is considered to be the root package, and
operations that return a value are forwarded to it.
"""
-
- @property
- def source_path(self):
- return self[0].source_path
-
- @property
- def path(self):
- return self[0].path
-
+ #
+ # __enter__ and __exit__ delegate to all stages in the composite.
+ #
def __enter__(self):
for item in self:
item.__enter__()
@@ -440,9 +443,24 @@ class StageComposite:
for item in reversed(self):
item.__exit__(exc_type, exc_val, exc_tb)
+ #
+ # Below functions act only on the *first* stage in the composite.
+ #
+ @property
+ def source_path(self):
+ return self[0].source_path
+
+ @property
+ def path(self):
+ return self[0].path
+
def chdir_to_source(self):
return self[0].chdir_to_source()
+ @property
+ def archive_file(self):
+ return self[0].archive_file
+
class DIYStage(object):
"""Simple class that allows any directory to be a spack stage."""