diff options
author | scheibelp <scheibel1@llnl.gov> | 2016-11-24 12:21:05 -0800 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2016-11-24 12:21:05 -0800 |
commit | 261d36e8012b78f5a92a7b5f7c18ddcc34459bce (patch) | |
tree | 7a9338777f16e9921359328ebca8f553cd47cb22 | |
parent | 9c267e9c73618d81e431a5655fe6e5d144fc492e (diff) | |
download | spack-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.
-rw-r--r-- | lib/spack/spack/fetch_strategy.py | 5 | ||||
-rw-r--r-- | lib/spack/spack/package.py | 8 | ||||
-rw-r--r-- | lib/spack/spack/stage.py | 19 | ||||
-rw-r--r-- | lib/spack/spack/test/stage.py | 46 |
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() |