summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorscheibelp <scheibel1@llnl.gov>2016-11-24 12:21:05 -0800
committerTodd Gamblin <tgamblin@llnl.gov>2016-11-24 12:21:05 -0800
commit261d36e8012b78f5a92a7b5f7c18ddcc34459bce (patch)
tree7a9338777f16e9921359328ebca8f553cd47cb22 /lib
parent9c267e9c73618d81e431a5655fe6e5d144fc492e (diff)
downloadspack-261d36e8012b78f5a92a7b5f7c18ddcc34459bce.tar.gz
spack-261d36e8012b78f5a92a7b5f7c18ddcc34459bce.tar.bz2
spack-261d36e8012b78f5a92a7b5f7c18ddcc34459bce.tar.xz
spack-261d36e8012b78f5a92a7b5f7c18ddcc34459bce.zip
Add dynamic search option for package sources (#2270)
Package provides a 'list_url' attribute which may be searched to find download links. #1822 created a slowdown for all tests by always searching this URL. This reenables dynamic search only in cases where all other fetchers fail. This also only enables dynamic search when 'mirror_only' is set to false.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/fetch_strategy.py5
-rw-r--r--lib/spack/spack/package.py8
-rw-r--r--lib/spack/spack/stage.py19
-rw-r--r--lib/spack/spack/test/stage.py46
4 files changed, 70 insertions, 8 deletions
diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py
index 5084a68e08..23f3b9a41e 100644
--- a/lib/spack/spack/fetch_strategy.py
+++ b/lib/spack/spack/fetch_strategy.py
@@ -911,7 +911,10 @@ def from_list_url(pkg):
versions = pkg.fetch_remote_versions()
try:
url_from_list = versions[pkg.version]
- return URLFetchStrategy(url=url_from_list, digest=None)
+ digest = None
+ if pkg.version in pkg.versions:
+ digest = pkg.versions[pkg.version].get('md5', None)
+ return URLFetchStrategy(url=url_from_list, digest=digest)
except KeyError:
tty.msg("Can not find version %s in url_list" %
self.version)
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 7462a73533..8bb19042cc 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -703,7 +703,13 @@ class PackageBase(object):
# Construct a path where the stage should build..
s = self.spec
stage_name = "%s-%s-%s" % (s.name, s.version, s.dag_hash())
- stage = Stage(fetcher, mirror_path=mp, name=stage_name, path=self.path)
+
+ def download_search():
+ dynamic_fetcher = fs.from_list_url(self)
+ return [dynamic_fetcher] if dynamic_fetcher else []
+
+ stage = Stage(fetcher, mirror_path=mp, name=stage_name, path=self.path,
+ search_fn=download_search)
return stage
def _make_stage(self):
diff --git a/lib/spack/spack/stage.py b/lib/spack/spack/stage.py
index 4157511ce0..91f77839d8 100644
--- a/lib/spack/spack/stage.py
+++ b/lib/spack/spack/stage.py
@@ -162,7 +162,7 @@ class Stage(object):
def __init__(
self, url_or_fetch_strategy,
name=None, mirror_path=None, keep=False, path=None, lock=True,
- alternate_fetchers=None):
+ search_fn=None):
"""Create a stage object.
Parameters:
url_or_fetch_strategy
@@ -198,7 +198,7 @@ class Stage(object):
self.fetcher.set_stage(self)
# self.fetcher can change with mirrors.
self.default_fetcher = self.fetcher
- self.alternate_fetchers = alternate_fetchers
+ self.search_fn = search_fn
# used for mirrored archives of repositories.
self.skip_checksum_for_mirror = True
@@ -416,10 +416,17 @@ class Stage(object):
self.mirror_path, digest, expand=expand,
extension=extension))
- if self.alternate_fetchers:
- fetchers.extend(self.alternate_fetchers)
-
- for fetcher in fetchers:
+ def generate_fetchers():
+ for fetcher in fetchers:
+ yield fetcher
+ # The search function may be expensive, so wait until now to
+ # call it so the user can stop if a prior fetcher succeeded
+ if self.search_fn and not mirror_only:
+ dynamic_fetchers = self.search_fn()
+ for fetcher in dynamic_fetchers:
+ yield fetcher
+
+ for fetcher in generate_fetchers():
try:
fetcher.set_stage(self)
self.fetcher = fetcher
diff --git a/lib/spack/spack/test/stage.py b/lib/spack/spack/test/stage.py
index 64cfa222db..cfeb80dd35 100644
--- a/lib/spack/spack/test/stage.py
+++ b/lib/spack/spack/test/stage.py
@@ -59,6 +59,26 @@ def use_tmp(use_tmp):
yield
+def fail_search_fn():
+ raise Exception("This should not have been called")
+
+
+class FailingFetchStrategy(spack.fetch_strategy.FetchStrategy):
+ def fetch(self):
+ raise spack.fetch_strategy.FailedDownloadError(
+ "<non-existent URL>",
+ "This implementation of FetchStrategy always fails")
+
+
+class MockSearchFunction(object):
+ def __init__(self):
+ self.performed_search = False
+
+ def __call__(self):
+ self.performed_search = True
+ return []
+
+
class StageTest(MockPackagesTest):
def setUp(self):
@@ -251,6 +271,32 @@ class StageTest(MockPackagesTest):
self.check_fetch(stage, self.stage_name)
self.check_destroy(stage, self.stage_name)
+ def test_no_search_if_default_succeeds(self):
+ with Stage(self.archive_url, name=self.stage_name,
+ search_fn=fail_search_fn) as stage:
+ stage.fetch()
+ self.check_destroy(stage, self.stage_name)
+
+ def test_no_search_mirror_only(self):
+ with Stage(FailingFetchStrategy(), name=self.stage_name,
+ search_fn=fail_search_fn) as stage:
+ try:
+ stage.fetch(mirror_only=True)
+ except spack.fetch_strategy.FetchError:
+ pass
+ self.check_destroy(stage, self.stage_name)
+
+ def test_search_if_default_fails(self):
+ test_search = MockSearchFunction()
+ with Stage(FailingFetchStrategy(), name=self.stage_name,
+ search_fn=test_search) as stage:
+ try:
+ stage.fetch(mirror_only=False)
+ except spack.fetch_strategy.FetchError:
+ pass
+ self.check_destroy(stage, self.stage_name)
+ self.assertTrue(test_search.performed_search)
+
def test_expand_archive(self):
with Stage(self.archive_url, name=self.stage_name) as stage:
stage.fetch()