commands: add spack resource command to inspect downloadable files
				
					
				
			- currently just looks at patches - allows you to find out which package applied a patch to a spec - intended to work with tarballs and resources in the future. - add tab completion for `spack resource` and subcommands
This commit is contained in:
		@@ -1422,6 +1422,73 @@ with all packages in Spack, a patched dependency library can coexist with
 | 
				
			|||||||
other versions of that library.  See the `section on depends_on
 | 
					other versions of that library.  See the `section on depends_on
 | 
				
			||||||
<dependency_dependency_patching_>`_ for more details.
 | 
					<dependency_dependency_patching_>`_ for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. _patch_inspecting_patches:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					Inspecting patches
 | 
				
			||||||
 | 
					^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want to better understand the patches that Spack applies to your
 | 
				
			||||||
 | 
					packages, you can do that using ``spack spec``, ``spack find``, and other
 | 
				
			||||||
 | 
					query commands.  Let's look at ``m4``.  If you run ``spack spec m4``, you
 | 
				
			||||||
 | 
					can see the patches that would be applied to ``m4``::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $ spack spec m4
 | 
				
			||||||
 | 
					  Input spec
 | 
				
			||||||
 | 
					  --------------------------------
 | 
				
			||||||
 | 
					  m4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Concretized
 | 
				
			||||||
 | 
					  --------------------------------
 | 
				
			||||||
 | 
					  m4@1.4.18%clang@9.0.0-apple patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=darwin-highsierra-x86_64
 | 
				
			||||||
 | 
					      ^libsigsegv@2.11%clang@9.0.0-apple arch=darwin-highsierra-x86_64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can also see patches that have been applied to installed packages
 | 
				
			||||||
 | 
					with ``spack find -v``::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $ spack find -v m4
 | 
				
			||||||
 | 
					  ==> 1 installed package
 | 
				
			||||||
 | 
					  -- darwin-highsierra-x86_64 / clang@9.0.0-apple -----------------
 | 
				
			||||||
 | 
					  m4@1.4.18 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. _cmd-spack-resource:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In both cases above, you can see that the patches' sha256 hashes are
 | 
				
			||||||
 | 
					stored on the spec as a variant.  As mentioned above, this means that you
 | 
				
			||||||
 | 
					can have multiple, differently-patched versions of a package installed at
 | 
				
			||||||
 | 
					once.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can look up a patch by its sha256 hash (or a short version of it)
 | 
				
			||||||
 | 
					using the ``spack resource show`` command::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $ spack resource show 3877ab54
 | 
				
			||||||
 | 
					  3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00
 | 
				
			||||||
 | 
					      path:       /home/spackuser/src/spack/var/spack/repos/builtin/packages/m4/gnulib-pgi.patch
 | 
				
			||||||
 | 
					      applies to: builtin.m4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``spack resource show`` looks up downloadable resources from package
 | 
				
			||||||
 | 
					files by hash and prints out information about them.  Above, we see that
 | 
				
			||||||
 | 
					the ``3877ab54`` patch applies to the ``m4`` package.  The output also
 | 
				
			||||||
 | 
					tells us where to find the patch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Things get more interesting if you want to know about dependency
 | 
				
			||||||
 | 
					patches. For example, when ``dealii`` is built with ``boost@1.68.0``, it
 | 
				
			||||||
 | 
					has to patch boost to work correctly.  If you didn't know this, you might
 | 
				
			||||||
 | 
					wonder where the extra boost patches are coming from::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $ spack spec dealii ^boost@1.68.0 ^hdf5+fortran | grep '\^boost'
 | 
				
			||||||
 | 
					      ^boost@1.68.0
 | 
				
			||||||
 | 
					          ^boost@1.68.0%clang@9.0.0-apple+atomic+chrono~clanglibcpp cxxstd=default +date_time~debug+exception+filesystem+graph~icu+iostreams+locale+log+math~mpi+multithreaded~numpy patches=2ab6c72d03dec6a4ae20220a9dfd5c8c572c5294252155b85c6874d97c323199,b37164268f34f7133cbc9a4066ae98fda08adf51e1172223f6a969909216870f ~pic+program_options~python+random+regex+serialization+shared+signals~singlethreaded+system~taggedlayout+test+thread+timer~versionedlayout+wave arch=darwin-highsierra-x86_64
 | 
				
			||||||
 | 
					  $ spack resource show b37164268
 | 
				
			||||||
 | 
					  b37164268f34f7133cbc9a4066ae98fda08adf51e1172223f6a969909216870f
 | 
				
			||||||
 | 
					      path:       /home/spackuser/src/spack/var/spack/repos/builtin/packages/dealii/boost_1.68.0.patch
 | 
				
			||||||
 | 
					      applies to: builtin.boost
 | 
				
			||||||
 | 
					      patched by: builtin.dealii
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here you can see that the patch is applied to ``boost`` by ``dealii``,
 | 
				
			||||||
 | 
					and that it lives in ``dealii``'s directory in Spack's ``builtin``
 | 
				
			||||||
 | 
					package repository.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _handling_rpaths:
 | 
					.. _handling_rpaths:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------------
 | 
					---------------
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										84
									
								
								lib/spack/spack/cmd/resource.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								lib/spack/spack/cmd/resource.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					# Copyright 2013-2018 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from __future__ import print_function
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import llnl.util.tty as tty
 | 
				
			||||||
 | 
					import llnl.util.tty.color as color
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import spack.repo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					description = "list downloadable resources (tarballs, repos, patches, etc.)"
 | 
				
			||||||
 | 
					section = "basic"
 | 
				
			||||||
 | 
					level = "long"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def setup_parser(subparser):
 | 
				
			||||||
 | 
					    sp = subparser.add_subparsers(
 | 
				
			||||||
 | 
					        metavar='SUBCOMMAND', dest='resource_command')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    list_parser = sp.add_parser('list', help=resource_list.__doc__)
 | 
				
			||||||
 | 
					    list_parser.add_argument('--only-hashes', action='store_true',
 | 
				
			||||||
 | 
					                             help='only print sha256 hashes of resources')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    show_parser = sp.add_parser('show', help=resource_show.__doc__)
 | 
				
			||||||
 | 
					    show_parser.add_argument('hash', action='store')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _show_patch(sha256):
 | 
				
			||||||
 | 
					    """Show a record from the patch index."""
 | 
				
			||||||
 | 
					    patches = spack.repo.path.patch_index.index
 | 
				
			||||||
 | 
					    data = patches.get(sha256)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not data:
 | 
				
			||||||
 | 
					        candidates = [k for k in patches if k.startswith(sha256)]
 | 
				
			||||||
 | 
					        if not candidates:
 | 
				
			||||||
 | 
					            tty.die('no such resource: %s' % sha256)
 | 
				
			||||||
 | 
					        elif len(candidates) > 1:
 | 
				
			||||||
 | 
					            tty.die('%s: ambiguous hash prefix. Options are:',
 | 
				
			||||||
 | 
					                    *candidates)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sha256 = candidates[0]
 | 
				
			||||||
 | 
					        data = patches.get(sha256)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    color.cprint('@c{%s}' % sha256)
 | 
				
			||||||
 | 
					    for package, rec in data.items():
 | 
				
			||||||
 | 
					        owner = rec['owner']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if 'relative_path' in rec:
 | 
				
			||||||
 | 
					            pkg_dir = spack.repo.get(owner).package_dir
 | 
				
			||||||
 | 
					            path = os.path.join(pkg_dir, rec['relative_path'])
 | 
				
			||||||
 | 
					            print("    path:       %s" % path)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print("    url:        %s" % rec['url'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print("    applies to: %s" % package)
 | 
				
			||||||
 | 
					        if owner != package:
 | 
				
			||||||
 | 
					            print("    patched by: %s" % owner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def resource_list(args):
 | 
				
			||||||
 | 
					    """list all resources known to spack (currently just patches)"""
 | 
				
			||||||
 | 
					    patches = spack.repo.path.patch_index.index
 | 
				
			||||||
 | 
					    for sha256 in patches:
 | 
				
			||||||
 | 
					        if args.only_hashes:
 | 
				
			||||||
 | 
					            print(sha256)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            _show_patch(sha256)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def resource_show(args):
 | 
				
			||||||
 | 
					    """show a resource, identified by its checksum"""
 | 
				
			||||||
 | 
					    _show_patch(args.hash)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def resource(parser, args):
 | 
				
			||||||
 | 
					    action = {
 | 
				
			||||||
 | 
					        'list': resource_list,
 | 
				
			||||||
 | 
					        'show': resource_show
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    action[args.resource_command](args)
 | 
				
			||||||
							
								
								
									
										60
									
								
								lib/spack/spack/test/cmd/resource.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								lib/spack/spack/test/cmd/resource.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					# Copyright 2013-2018 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from spack.main import SpackCommand
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resource = SpackCommand('resource')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: these are hashes used in mock packages
 | 
				
			||||||
 | 
					mock_hashes = [
 | 
				
			||||||
 | 
					    'abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234',
 | 
				
			||||||
 | 
					    '1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd',
 | 
				
			||||||
 | 
					    'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c',
 | 
				
			||||||
 | 
					    'c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8',
 | 
				
			||||||
 | 
					    '24eceabef5fe8f575ff4b438313dc3e7b30f6a2d1c78841fbbe3b9293a589277',
 | 
				
			||||||
 | 
					    '689b8f9b32cb1d2f9271d29ea3fca2e1de5df665e121fca14e1364b711450deb',
 | 
				
			||||||
 | 
					    'ebe27f9930b99ebd8761ed2db3ea365142d0bafd78317efb4baadf62c7bf94d0',
 | 
				
			||||||
 | 
					    '208fcfb50e5a965d5757d151b675ca4af4ce2dfd56401721b6168fae60ab798f',
 | 
				
			||||||
 | 
					    'bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c',
 | 
				
			||||||
 | 
					    '7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730',
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_resource_list(mock_packages, capfd):
 | 
				
			||||||
 | 
					    with capfd.disabled():
 | 
				
			||||||
 | 
					        out = resource('list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for h in mock_hashes:
 | 
				
			||||||
 | 
					        assert h in out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert 'url:' in out
 | 
				
			||||||
 | 
					    assert 'applies to:' in out
 | 
				
			||||||
 | 
					    assert 'patched by:' in out
 | 
				
			||||||
 | 
					    assert 'path:' in out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert 'repos/builtin.mock/packages/patch-a-dependency/libelf.patch' in out
 | 
				
			||||||
 | 
					    assert 'applies to: builtin.mock.libelf' in out
 | 
				
			||||||
 | 
					    assert 'patched by: builtin.mock.patch-a-dependency' in out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_resource_list_only_hashes(mock_packages, capfd):
 | 
				
			||||||
 | 
					    with capfd.disabled():
 | 
				
			||||||
 | 
					        out = resource('list', '--only-hashes')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for h in mock_hashes:
 | 
				
			||||||
 | 
					        assert h in out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_resource_show(mock_packages, capfd):
 | 
				
			||||||
 | 
					    with capfd.disabled():
 | 
				
			||||||
 | 
					        out = resource('show', 'c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert out.startswith('c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8')
 | 
				
			||||||
 | 
					    assert 'repos/builtin.mock/packages/patch-a-dependency/libelf.patch' in out
 | 
				
			||||||
 | 
					    assert 'applies to: builtin.mock.libelf' in out
 | 
				
			||||||
 | 
					    assert 'patched by: builtin.mock.patch-a-dependency' in out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert len(out.strip().split('\n')) == 4
 | 
				
			||||||
@@ -1041,6 +1041,28 @@ function _spack_repo_rm {
 | 
				
			|||||||
    _spack_repo_remove
 | 
					    _spack_repo_remove
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _spack_resource {
 | 
				
			||||||
 | 
					    if $list_options
 | 
				
			||||||
 | 
					    then
 | 
				
			||||||
 | 
					        compgen -W "-h --help" -- "$cur"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        compgen -W "list show" -- "$cur"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _spack_resource_list {
 | 
				
			||||||
 | 
					    compgen -W "-h --help --only-hashes" -- "$cur"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _spack_resource_show {
 | 
				
			||||||
 | 
					    if $list_options
 | 
				
			||||||
 | 
					    then
 | 
				
			||||||
 | 
					        compgen -W "-h --help" -- "$cur"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        compgen -W "$(_all_resource_hashes)" -- "$cur"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function _spack_restage {
 | 
					function _spack_restage {
 | 
				
			||||||
    if $list_options
 | 
					    if $list_options
 | 
				
			||||||
    then
 | 
					    then
 | 
				
			||||||
@@ -1244,6 +1266,10 @@ function _all_packages {
 | 
				
			|||||||
    spack list
 | 
					    spack list
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function _all_resource_hashes {
 | 
				
			||||||
 | 
					    spack resource list --only-hashes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function _installed_packages {
 | 
					function _installed_packages {
 | 
				
			||||||
    spack --color=never find | grep -v "^--"
 | 
					    spack --color=never find | grep -v "^--"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user