package: Add fetch_options variable (#15317)
PR #15212 added a new connect_timeout option that can be overridden using fetch_options but had to specified per-version. This adds a new per-package variable that can be used to override fetch_options for all versions in the package. This includes connect_timeout as well as 'cookie' (e.g. for the jdk package). Packages can combine package-level fetch_options with per-version fetch_options, in which case the version fetch_options completely override the package-level fetch_options. This commit includes tests for the added behavior.
This commit is contained in:
		| @@ -256,7 +256,7 @@ def __init__(self, url=None, checksum=None, **kwargs): | ||||
|                 self.digest = kwargs[h] | ||||
| 
 | ||||
|         self.expand_archive = kwargs.get('expand', True) | ||||
|         self.extra_options = kwargs.get('fetch_options', []) | ||||
|         self.extra_options = kwargs.get('fetch_options', {}) | ||||
|         self._curl = None | ||||
| 
 | ||||
|         self.extension = kwargs.get('extension', None) | ||||
| @@ -1247,7 +1247,8 @@ def _check_version_attributes(fetcher, pkg, version): | ||||
| def _extrapolate(pkg, version): | ||||
|     """Create a fetcher from an extrapolated URL for this version.""" | ||||
|     try: | ||||
|         return URLFetchStrategy(pkg.url_for_version(version)) | ||||
|         return URLFetchStrategy(pkg.url_for_version(version), | ||||
|                                 fetch_options=pkg.fetch_options) | ||||
|     except spack.package.NoURLError: | ||||
|         msg = ("Can't extrapolate a URL for version %s " | ||||
|                "because package %s defines no URLs") | ||||
| @@ -1267,6 +1268,7 @@ def _from_merged_attrs(fetcher, pkg, version): | ||||
|         url = getattr(pkg, fetcher.url_attr) | ||||
|         attrs = {fetcher.url_attr: url} | ||||
| 
 | ||||
|     attrs['fetch_options'] = pkg.fetch_options | ||||
|     attrs.update(pkg.versions[version]) | ||||
|     return fetcher(**attrs) | ||||
| 
 | ||||
| @@ -1289,8 +1291,10 @@ def for_package_version(pkg, version): | ||||
|     if version not in pkg.versions: | ||||
|         return _extrapolate(pkg, version) | ||||
| 
 | ||||
|     # Set package args first so version args can override them | ||||
|     args = {'fetch_options': pkg.fetch_options} | ||||
|     # Grab a dict of args out of the package version dict | ||||
|     args = pkg.versions[version] | ||||
|     args.update(pkg.versions[version]) | ||||
| 
 | ||||
|     # If the version specifies a `url_attr` directly, use that. | ||||
|     for fetcher in all_strategies: | ||||
| @@ -1370,7 +1374,8 @@ def from_list_url(pkg): | ||||
|                         args.get('checksum')) | ||||
| 
 | ||||
|                 # construct a fetcher | ||||
|                 return URLFetchStrategy(url_from_list, checksum) | ||||
|                 return URLFetchStrategy(url_from_list, checksum, | ||||
|                                         fetch_options=pkg.fetch_options) | ||||
|             except KeyError as e: | ||||
|                 tty.debug(e) | ||||
|                 tty.msg("Cannot find version %s in url_list" % pkg.version) | ||||
|   | ||||
| @@ -477,6 +477,9 @@ class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)): | ||||
|     #: This is currently only used by package sanity tests. | ||||
|     manual_download = False | ||||
| 
 | ||||
|     #: Set of additional options used when fetching package versions. | ||||
|     fetch_options = {} | ||||
| 
 | ||||
|     # | ||||
|     # Set default licensing information | ||||
|     # | ||||
|   | ||||
| @@ -402,3 +402,24 @@ def test_bundle_patch_directive(mock_directive_bundle, | ||||
|                        match="Patches are not allowed"): | ||||
|         patch = spack.directives.patch('mock/patch.txt') | ||||
|         patch(mock_directive_bundle) | ||||
| 
 | ||||
| 
 | ||||
| def test_fetch_options(mock_packages, config): | ||||
|     """Test fetch options inference.""" | ||||
| 
 | ||||
|     pkg = spack.repo.get('fetch-options') | ||||
| 
 | ||||
|     fetcher = spack.fetch_strategy.for_package_version(pkg, '1.0') | ||||
|     assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy) | ||||
|     assert fetcher.digest == 'abc10' | ||||
|     assert fetcher.extra_options == {'timeout': 42, 'cookie': 'foobar'} | ||||
| 
 | ||||
|     fetcher = spack.fetch_strategy.for_package_version(pkg, '1.1') | ||||
|     assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy) | ||||
|     assert fetcher.digest == 'abc11' | ||||
|     assert fetcher.extra_options == {'timeout': 65} | ||||
| 
 | ||||
|     fetcher = spack.fetch_strategy.for_package_version(pkg, '1.2') | ||||
|     assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy) | ||||
|     assert fetcher.digest == 'abc12' | ||||
|     assert fetcher.extra_options == {'cookie': 'baz'} | ||||
|   | ||||
| @@ -26,10 +26,10 @@ def checksum_type(request): | ||||
| @pytest.fixture | ||||
| def pkg_factory(): | ||||
|     Pkg = collections.namedtuple( | ||||
|         'Pkg', ['url_for_version', 'urls', 'url', 'versions'] | ||||
|         'Pkg', ['url_for_version', 'urls', 'url', 'versions', 'fetch_options'] | ||||
|     ) | ||||
| 
 | ||||
|     def factory(url, urls): | ||||
|     def factory(url, urls, fetch_options={}): | ||||
| 
 | ||||
|         def fn(v): | ||||
|             main_url = url or urls[0] | ||||
| @@ -37,7 +37,8 @@ def fn(v): | ||||
| 
 | ||||
|         return Pkg( | ||||
|             url_for_version=fn, url=url, urls=urls, | ||||
|             versions=collections.defaultdict(dict) | ||||
|             versions=collections.defaultdict(dict), | ||||
|             fetch_options=fetch_options | ||||
|         ) | ||||
| 
 | ||||
|     return factory | ||||
| @@ -130,6 +131,10 @@ def test_from_list_url(mock_packages, config, spec, url, digest): | ||||
|     assert isinstance(fetch_strategy, fs.URLFetchStrategy) | ||||
|     assert os.path.basename(fetch_strategy.url) == url | ||||
|     assert fetch_strategy.digest == digest | ||||
|     assert fetch_strategy.extra_options == {} | ||||
|     pkg.fetch_options = {'timeout': 60} | ||||
|     fetch_strategy = fs.from_list_url(pkg) | ||||
|     assert fetch_strategy.extra_options == {'timeout': 60} | ||||
| 
 | ||||
| 
 | ||||
| def test_from_list_url_unspecified(mock_packages, config): | ||||
| @@ -142,6 +147,10 @@ def test_from_list_url_unspecified(mock_packages, config): | ||||
|     assert isinstance(fetch_strategy, fs.URLFetchStrategy) | ||||
|     assert os.path.basename(fetch_strategy.url) == 'foo-2.0.0.tar.gz' | ||||
|     assert fetch_strategy.digest is None | ||||
|     assert fetch_strategy.extra_options == {} | ||||
|     pkg.fetch_options = {'timeout': 60} | ||||
|     fetch_strategy = fs.from_list_url(pkg) | ||||
|     assert fetch_strategy.extra_options == {'timeout': 60} | ||||
| 
 | ||||
| 
 | ||||
| def test_nosource_from_list_url(mock_packages, config): | ||||
| @@ -191,3 +200,7 @@ def test_candidate_urls(pkg_factory, url, urls, version, expected): | ||||
|     pkg = pkg_factory(url, urls) | ||||
|     f = fs._from_merged_attrs(fs.URLFetchStrategy, pkg, version) | ||||
|     assert f.candidate_urls == expected | ||||
|     assert f.extra_options == {} | ||||
|     pkg = pkg_factory(url, urls, fetch_options={'timeout': 60}) | ||||
|     f = fs._from_merged_attrs(fs.URLFetchStrategy, pkg, version) | ||||
|     assert f.extra_options == {'timeout': 60} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Michael Kuhn
					Michael Kuhn