Add --preferred and --latest tospack checksum (#25830)
				
					
				
			This commit is contained in:
		| @@ -14,6 +14,7 @@ | |||||||
| import spack.repo | import spack.repo | ||||||
| import spack.stage | import spack.stage | ||||||
| import spack.util.crypto | import spack.util.crypto | ||||||
|  | from spack.package import preferred_version | ||||||
| from spack.util.naming import valid_fully_qualified_module_name | from spack.util.naming import valid_fully_qualified_module_name | ||||||
| from spack.version import Version, ver | from spack.version import Version, ver | ||||||
| 
 | 
 | ||||||
| @@ -26,9 +27,16 @@ def setup_parser(subparser): | |||||||
|     subparser.add_argument( |     subparser.add_argument( | ||||||
|         '--keep-stage', action='store_true', |         '--keep-stage', action='store_true', | ||||||
|         help="don't clean up staging area when command completes") |         help="don't clean up staging area when command completes") | ||||||
|     subparser.add_argument( |     sp = subparser.add_mutually_exclusive_group() | ||||||
|  |     sp.add_argument( | ||||||
|         '-b', '--batch', action='store_true', |         '-b', '--batch', action='store_true', | ||||||
|         help="don't ask which versions to checksum") |         help="don't ask which versions to checksum") | ||||||
|  |     sp.add_argument( | ||||||
|  |         '-l', '--latest', action='store_true', | ||||||
|  |         help="checksum the latest available version only") | ||||||
|  |     sp.add_argument( | ||||||
|  |         '-p', '--preferred', action='store_true', | ||||||
|  |         help="checksum the preferred version only") | ||||||
|     arguments.add_common_arguments(subparser, ['package']) |     arguments.add_common_arguments(subparser, ['package']) | ||||||
|     subparser.add_argument( |     subparser.add_argument( | ||||||
|         'versions', nargs=argparse.REMAINDER, |         'versions', nargs=argparse.REMAINDER, | ||||||
| @@ -48,15 +56,18 @@ def checksum(parser, args): | |||||||
|     # Get the package we're going to generate checksums for |     # Get the package we're going to generate checksums for | ||||||
|     pkg = spack.repo.get(args.package) |     pkg = spack.repo.get(args.package) | ||||||
| 
 | 
 | ||||||
|  |     url_dict = {} | ||||||
|     if args.versions: |     if args.versions: | ||||||
|         # If the user asked for specific versions, use those |         # If the user asked for specific versions, use those | ||||||
|         url_dict = {} |  | ||||||
|         for version in args.versions: |         for version in args.versions: | ||||||
|             version = ver(version) |             version = ver(version) | ||||||
|             if not isinstance(version, Version): |             if not isinstance(version, Version): | ||||||
|                 tty.die("Cannot generate checksums for version lists or " |                 tty.die("Cannot generate checksums for version lists or " | ||||||
|                         "version ranges. Use unambiguous versions.") |                         "version ranges. Use unambiguous versions.") | ||||||
|             url_dict[version] = pkg.url_for_version(version) |             url_dict[version] = pkg.url_for_version(version) | ||||||
|  |     elif args.preferred: | ||||||
|  |         version = preferred_version(pkg) | ||||||
|  |         url_dict = dict([(version, pkg.url_for_version(version))]) | ||||||
|     else: |     else: | ||||||
|         # Otherwise, see what versions we can find online |         # Otherwise, see what versions we can find online | ||||||
|         url_dict = pkg.fetch_remote_versions() |         url_dict = pkg.fetch_remote_versions() | ||||||
| @@ -76,7 +87,7 @@ def checksum(parser, args): | |||||||
|     version_lines = spack.stage.get_checksums_for_versions( |     version_lines = spack.stage.get_checksums_for_versions( | ||||||
|         url_dict, pkg.name, keep_stage=args.keep_stage, |         url_dict, pkg.name, keep_stage=args.keep_stage, | ||||||
|         batch=(args.batch or len(args.versions) > 0 or len(url_dict) == 1), |         batch=(args.batch or len(args.versions) > 0 or len(url_dict) == 1), | ||||||
|         fetch_options=pkg.fetch_options) |         latest=args.latest, fetch_options=pkg.fetch_options) | ||||||
| 
 | 
 | ||||||
|     print() |     print() | ||||||
|     print(version_lines) |     print(version_lines) | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ | |||||||
| import spack.fetch_strategy as fs | import spack.fetch_strategy as fs | ||||||
| import spack.repo | import spack.repo | ||||||
| import spack.spec | import spack.spec | ||||||
|  | from spack.package import preferred_version | ||||||
| 
 | 
 | ||||||
| description = 'get detailed information on a particular package' | description = 'get detailed information on a particular package' | ||||||
| section = 'basic' | section = 'basic' | ||||||
| @@ -197,13 +198,7 @@ def print_text_info(pkg): | |||||||
|     else: |     else: | ||||||
|         pad = padder(pkg.versions, 4) |         pad = padder(pkg.versions, 4) | ||||||
| 
 | 
 | ||||||
|         # Here we sort first on the fact that a version is marked |         preferred = preferred_version(pkg) | ||||||
|         # as preferred in the package, then on the fact that the |  | ||||||
|         # version is not develop, then lexicographically |  | ||||||
|         key_fn = lambda v: (pkg.versions[v].get('preferred', False), |  | ||||||
|                             not v.isdevelop(), |  | ||||||
|                             v) |  | ||||||
|         preferred = sorted(pkg.versions, key=key_fn).pop() |  | ||||||
|         url = '' |         url = '' | ||||||
|         if pkg.has_code: |         if pkg.has_code: | ||||||
|             url = fs.for_package_version(pkg, preferred) |             url = fs.for_package_version(pkg, preferred) | ||||||
|   | |||||||
| @@ -83,6 +83,22 @@ | |||||||
| _spack_configure_argsfile = 'spack-configure-args.txt' | _spack_configure_argsfile = 'spack-configure-args.txt' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def preferred_version(pkg): | ||||||
|  |     """ | ||||||
|  |     Returns a sorted list of the preferred versions of the package. | ||||||
|  | 
 | ||||||
|  |     Arguments: | ||||||
|  |         pkg (Package): The package whose versions are to be assessed. | ||||||
|  |     """ | ||||||
|  |     # Here we sort first on the fact that a version is marked | ||||||
|  |     # as preferred in the package, then on the fact that the | ||||||
|  |     # version is not develop, then lexicographically | ||||||
|  |     key_fn = lambda v: (pkg.versions[v].get('preferred', False), | ||||||
|  |                         not v.isdevelop(), | ||||||
|  |                         v) | ||||||
|  |     return sorted(pkg.versions, key=key_fn).pop() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class InstallPhase(object): | class InstallPhase(object): | ||||||
|     """Manages a single phase of the installation. |     """Manages a single phase of the installation. | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -824,9 +824,7 @@ def purge(): | |||||||
|                 remove_linked_tree(stage_path) |                 remove_linked_tree(stage_path) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_checksums_for_versions( | def get_checksums_for_versions(url_dict, name, **kwargs): | ||||||
|         url_dict, name, first_stage_function=None, keep_stage=False, |  | ||||||
|         fetch_options=None, batch=False): |  | ||||||
|     """Fetches and checksums archives from URLs. |     """Fetches and checksums archives from URLs. | ||||||
| 
 | 
 | ||||||
|     This function is called by both ``spack checksum`` and ``spack |     This function is called by both ``spack checksum`` and ``spack | ||||||
| @@ -842,6 +840,7 @@ def get_checksums_for_versions( | |||||||
|         keep_stage (bool): whether to keep staging area when command completes |         keep_stage (bool): whether to keep staging area when command completes | ||||||
|         batch (bool): whether to ask user how many versions to fetch (false) |         batch (bool): whether to ask user how many versions to fetch (false) | ||||||
|             or fetch all versions (true) |             or fetch all versions (true) | ||||||
|  |         latest (bool): whether to take the latest version (true) or all (false) | ||||||
|         fetch_options (dict): Options used for the fetcher (such as timeout |         fetch_options (dict): Options used for the fetcher (such as timeout | ||||||
|             or cookies) |             or cookies) | ||||||
| 
 | 
 | ||||||
| @@ -849,7 +848,15 @@ def get_checksums_for_versions( | |||||||
|         (str): A multi-line string containing versions and corresponding hashes |         (str): A multi-line string containing versions and corresponding hashes | ||||||
| 
 | 
 | ||||||
|     """ |     """ | ||||||
|  |     batch = kwargs.get('batch', False) | ||||||
|  |     fetch_options = kwargs.get('fetch_options', None) | ||||||
|  |     first_stage_function = kwargs.get('first_stage_function', None) | ||||||
|  |     keep_stage = kwargs.get('keep_stage', False) | ||||||
|  |     latest = kwargs.get('latest', False) | ||||||
|  | 
 | ||||||
|     sorted_versions = sorted(url_dict.keys(), reverse=True) |     sorted_versions = sorted(url_dict.keys(), reverse=True) | ||||||
|  |     if latest: | ||||||
|  |         sorted_versions = sorted_versions[:1] | ||||||
| 
 | 
 | ||||||
|     # Find length of longest string in the list for padding |     # Find length of longest string in the list for padding | ||||||
|     max_len = max(len(str(v)) for v in sorted_versions) |     max_len = max(len(str(v)) for v in sorted_versions) | ||||||
| @@ -863,7 +870,7 @@ def get_checksums_for_versions( | |||||||
|                  for v in sorted_versions])) |                  for v in sorted_versions])) | ||||||
|     print() |     print() | ||||||
| 
 | 
 | ||||||
|     if batch: |     if batch or latest: | ||||||
|         archives_to_fetch = len(sorted_versions) |         archives_to_fetch = len(sorted_versions) | ||||||
|     else: |     else: | ||||||
|         archives_to_fetch = tty.get_number( |         archives_to_fetch = tty.get_number( | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								lib/spack/spack/test/cmd/checksum.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								lib/spack/spack/test/cmd/checksum.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | # Copyright 2013-2021 Lawrence Livermore National Security, LLC and other | ||||||
|  | # Spack Project Developers. See the top-level COPYRIGHT file for details. | ||||||
|  | # | ||||||
|  | # SPDX-License-Identifier: (Apache-2.0 OR MIT) | ||||||
|  | 
 | ||||||
|  | import argparse | ||||||
|  | 
 | ||||||
|  | import pytest | ||||||
|  | 
 | ||||||
|  | import llnl.util.tty as tty | ||||||
|  | 
 | ||||||
|  | import spack.cmd.checksum | ||||||
|  | import spack.repo | ||||||
|  | from spack.main import SpackCommand | ||||||
|  | 
 | ||||||
|  | spack_checksum = SpackCommand('checksum') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.parametrize('arguments,expected', [ | ||||||
|  |     (['--batch', 'patch'], (True, False, False)), | ||||||
|  |     (['--latest', 'patch'], (False, True, False)), | ||||||
|  |     (['--preferred', 'patch'], (False, False, True)), | ||||||
|  | ]) | ||||||
|  | def test_checksum_args(arguments, expected): | ||||||
|  |     parser = argparse.ArgumentParser() | ||||||
|  |     spack.cmd.checksum.setup_parser(parser) | ||||||
|  |     args = parser.parse_args(arguments) | ||||||
|  |     check = args.batch, args.latest, args.preferred | ||||||
|  |     assert check == expected | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.parametrize('arguments,expected', [ | ||||||
|  |     (['--batch', 'preferred-test'], 'versions of preferred-test'), | ||||||
|  |     (['--latest', 'preferred-test'], 'Found 1 version'), | ||||||
|  |     (['--preferred', 'preferred-test'], 'Found 1 version'), | ||||||
|  | ]) | ||||||
|  | def test_checksum(arguments, expected, mock_packages, mock_stage): | ||||||
|  |     output = spack_checksum(*arguments) | ||||||
|  |     assert expected in output | ||||||
|  |     assert 'version(' in output | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_checksum_interactive( | ||||||
|  |         mock_packages, mock_fetch, mock_stage, monkeypatch): | ||||||
|  |     def _get_number(*args, **kwargs): | ||||||
|  |         return 1 | ||||||
|  |     monkeypatch.setattr(tty, 'get_number', _get_number) | ||||||
|  | 
 | ||||||
|  |     output = spack_checksum('preferred-test') | ||||||
|  |     assert 'versions of preferred-test' in output | ||||||
|  |     assert 'version(' in output | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_checksum_versions(mock_packages, mock_fetch, mock_stage): | ||||||
|  |     pkg = spack.repo.get('preferred-test') | ||||||
|  | 
 | ||||||
|  |     versions = [str(v) for v in pkg.versions if not v.isdevelop()] | ||||||
|  |     output = spack_checksum('preferred-test', versions[0]) | ||||||
|  |     assert 'Found 1 version' in output | ||||||
|  |     assert 'version(' in output | ||||||
| @@ -575,7 +575,7 @@ _spack_cd() { | |||||||
| _spack_checksum() { | _spack_checksum() { | ||||||
|     if $list_options |     if $list_options | ||||||
|     then |     then | ||||||
|         SPACK_COMPREPLY="-h --help --keep-stage -b --batch" |         SPACK_COMPREPLY="-h --help --keep-stage -b --batch -l --latest -p --preferred" | ||||||
|     else |     else | ||||||
|         _all_packages |         _all_packages | ||||||
|     fi |     fi | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Tamara Dahlgren
					Tamara Dahlgren