Bootstrap GnuPG (#24003)
* GnuPG: allow bootstrapping from buildcache and sources * Add a test to bootstrap GnuPG from binaries * Disable bootstrapping in tests * Add e2e test to bootstrap GnuPG from sources on Ubuntu * Add e2e test to bootstrap GnuPG on macOS
This commit is contained in:
parent
1a3747b2b3
commit
78c08fccd5
8 changed files with 549 additions and 79 deletions
100
.github/workflows/bootstrap.yml
vendored
100
.github/workflows/bootstrap.yml
vendored
|
@ -19,7 +19,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
fedora-sources:
|
fedora-clingo-sources:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: "fedora:latest"
|
container: "fedora:latest"
|
||||||
steps:
|
steps:
|
||||||
|
@ -46,7 +46,7 @@ jobs:
|
||||||
spack -d solve zlib
|
spack -d solve zlib
|
||||||
tree ~/.spack/bootstrap/store/
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
||||||
ubuntu-sources:
|
ubuntu-clingo-sources:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: "ubuntu:latest"
|
container: "ubuntu:latest"
|
||||||
steps:
|
steps:
|
||||||
|
@ -76,7 +76,7 @@ jobs:
|
||||||
spack -d solve zlib
|
spack -d solve zlib
|
||||||
tree ~/.spack/bootstrap/store/
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
||||||
opensuse-sources:
|
opensuse-clingo-sources:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: "opensuse/leap:latest"
|
container: "opensuse/leap:latest"
|
||||||
steps:
|
steps:
|
||||||
|
@ -101,7 +101,7 @@ jobs:
|
||||||
spack -d solve zlib
|
spack -d solve zlib
|
||||||
tree ~/.spack/bootstrap/store/
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
||||||
macos-sources:
|
macos-clingo-sources:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
@ -137,7 +137,6 @@ jobs:
|
||||||
spack -d solve zlib
|
spack -d solve zlib
|
||||||
tree ~/.spack/bootstrap/store/
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
||||||
|
|
||||||
ubuntu-clingo-binaries:
|
ubuntu-clingo-binaries:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -159,3 +158,94 @@ jobs:
|
||||||
spack bootstrap untrust spack-install
|
spack bootstrap untrust spack-install
|
||||||
spack -d solve zlib
|
spack -d solve zlib
|
||||||
tree ~/.spack/bootstrap/store/
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
||||||
|
ubuntu-gnupg-binaries:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: "ubuntu:latest"
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
env:
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
run: |
|
||||||
|
apt-get update -y && apt-get upgrade -y
|
||||||
|
apt-get install -y \
|
||||||
|
bzip2 curl file g++ gcc patchelf gfortran git gzip \
|
||||||
|
make patch unzip xz-utils python3 python3-dev tree
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Setup repo and non-root user
|
||||||
|
run: |
|
||||||
|
git --version
|
||||||
|
git fetch --unshallow
|
||||||
|
. .github/workflows/setup_git.sh
|
||||||
|
useradd -m spack-test
|
||||||
|
chown -R spack-test .
|
||||||
|
- name: Bootstrap GnuPG
|
||||||
|
shell: runuser -u spack-test -- bash {0}
|
||||||
|
run: |
|
||||||
|
source share/spack/setup-env.sh
|
||||||
|
spack bootstrap untrust spack-install
|
||||||
|
spack -d gpg list
|
||||||
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
||||||
|
ubuntu-gnupg-sources:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: "ubuntu:latest"
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
env:
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
run: |
|
||||||
|
apt-get update -y && apt-get upgrade -y
|
||||||
|
apt-get install -y \
|
||||||
|
bzip2 curl file g++ gcc patchelf gfortran git gzip \
|
||||||
|
make patch unzip xz-utils python3 python3-dev tree \
|
||||||
|
gawk
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Setup repo and non-root user
|
||||||
|
run: |
|
||||||
|
git --version
|
||||||
|
git fetch --unshallow
|
||||||
|
. .github/workflows/setup_git.sh
|
||||||
|
useradd -m spack-test
|
||||||
|
chown -R spack-test .
|
||||||
|
- name: Bootstrap GnuPG
|
||||||
|
shell: runuser -u spack-test -- bash {0}
|
||||||
|
run: |
|
||||||
|
source share/spack/setup-env.sh
|
||||||
|
spack solve zlib
|
||||||
|
spack bootstrap untrust github-actions
|
||||||
|
spack -d gpg list
|
||||||
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
||||||
|
macos-gnupg-binaries:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
brew install tree
|
||||||
|
# Remove GnuPG since we want to bootstrap it
|
||||||
|
sudo rm -rf /usr/local/bin/gpg
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Bootstrap GnuPG
|
||||||
|
run: |
|
||||||
|
source share/spack/setup-env.sh
|
||||||
|
spack bootstrap untrust spack-install
|
||||||
|
spack -d gpg list
|
||||||
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
||||||
|
macos-gnupg-sources:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
brew install gawk tree
|
||||||
|
# Remove GnuPG since we want to bootstrap it
|
||||||
|
sudo rm -rf /usr/local/bin/gpg
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Bootstrap GnuPG
|
||||||
|
run: |
|
||||||
|
source share/spack/setup-env.sh
|
||||||
|
spack solve zlib
|
||||||
|
spack bootstrap untrust github-actions
|
||||||
|
spack -d gpg list
|
||||||
|
tree ~/.spack/bootstrap/store/
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import functools
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -34,11 +35,14 @@
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.store
|
import spack.store
|
||||||
import spack.user_environment as uenv
|
import spack.user_environment
|
||||||
import spack.util.executable
|
import spack.util.executable
|
||||||
import spack.util.path
|
import spack.util.path
|
||||||
from spack.util.environment import EnvironmentModifications
|
from spack.util.environment import EnvironmentModifications
|
||||||
|
|
||||||
|
#: "spack buildcache" command, initialized lazily
|
||||||
|
_buildcache_cmd = None
|
||||||
|
|
||||||
#: Map a bootstrapper type to the corresponding class
|
#: Map a bootstrapper type to the corresponding class
|
||||||
_bootstrap_methods = {}
|
_bootstrap_methods = {}
|
||||||
|
|
||||||
|
@ -171,6 +175,34 @@ def _fix_ext_suffix(candidate_spec):
|
||||||
os.symlink(abs_path, link_name)
|
os.symlink(abs_path, link_name)
|
||||||
|
|
||||||
|
|
||||||
|
def _executables_in_store(executables, abstract_spec_str):
|
||||||
|
"""Return True if at least one of the executables can be retrieved from
|
||||||
|
a spec in store, False otherwise.
|
||||||
|
|
||||||
|
The different executables must provide the same functionality and are
|
||||||
|
"alternate" to each other, i.e. the function will exit True on the first
|
||||||
|
executable found.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
executables: list of executables to be searched
|
||||||
|
abstract_spec_str: abstract spec that may provide the executable
|
||||||
|
"""
|
||||||
|
executables_str = ', '.join(executables)
|
||||||
|
msg = "[BOOTSTRAP EXECUTABLES {0}] Try installed specs with query '{1}'"
|
||||||
|
tty.debug(msg.format(executables_str, abstract_spec_str))
|
||||||
|
installed_specs = spack.store.db.query(abstract_spec_str, installed=True)
|
||||||
|
if installed_specs:
|
||||||
|
for concrete_spec in installed_specs:
|
||||||
|
bin_dir = concrete_spec.prefix.bin
|
||||||
|
# IF we have a "bin" directory and it contains
|
||||||
|
# the executables we are looking for
|
||||||
|
if (os.path.exists(bin_dir) and os.path.isdir(bin_dir) and
|
||||||
|
spack.util.executable.which_string(*executables, path=bin_dir)):
|
||||||
|
spack.util.environment.path_put_first('PATH', [bin_dir])
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
@_bootstrapper(type='buildcache')
|
@_bootstrapper(type='buildcache')
|
||||||
class _BuildcacheBootstrapper(object):
|
class _BuildcacheBootstrapper(object):
|
||||||
"""Install the software needed during bootstrapping from a buildcache."""
|
"""Install the software needed during bootstrapping from a buildcache."""
|
||||||
|
@ -178,93 +210,140 @@ def __init__(self, conf):
|
||||||
self.name = conf['name']
|
self.name = conf['name']
|
||||||
self.url = conf['info']['url']
|
self.url = conf['info']['url']
|
||||||
|
|
||||||
def try_import(self, module, abstract_spec_str):
|
@staticmethod
|
||||||
if _try_import_from_store(module, abstract_spec_str):
|
def _spec_and_platform(abstract_spec_str):
|
||||||
return True
|
"""Return the spec object and platform we need to use when
|
||||||
|
querying the buildcache.
|
||||||
|
|
||||||
tty.info("Bootstrapping {0} from pre-built binaries".format(module))
|
Args:
|
||||||
|
abstract_spec_str: abstract spec string we are looking for
|
||||||
|
"""
|
||||||
|
# This import is local since it is needed only on Cray
|
||||||
|
import spack.platforms.linux
|
||||||
|
|
||||||
# Try to install from an unsigned binary cache
|
# Try to install from an unsigned binary cache
|
||||||
abstract_spec = spack.spec.Spec(
|
abstract_spec = spack.spec.Spec(abstract_spec_str)
|
||||||
abstract_spec_str + ' ^' + spec_for_current_python()
|
|
||||||
)
|
|
||||||
|
|
||||||
# On Cray we want to use Linux binaries if available from mirrors
|
# On Cray we want to use Linux binaries if available from mirrors
|
||||||
bincache_platform = spack.platforms.real_host()
|
bincache_platform = spack.platforms.real_host()
|
||||||
if str(bincache_platform) == 'cray':
|
if str(bincache_platform) == 'cray':
|
||||||
bincache_platform = spack.platforms.Linux()
|
bincache_platform = spack.platforms.Linux()
|
||||||
with spack.platforms.use_platform(bincache_platform):
|
with spack.platforms.use_platform(bincache_platform):
|
||||||
abstract_spec = spack.spec.Spec(
|
abstract_spec = spack.spec.Spec(abstract_spec_str)
|
||||||
abstract_spec_str + ' ^' + spec_for_current_python()
|
return abstract_spec, bincache_platform
|
||||||
)
|
|
||||||
|
|
||||||
# Read information on verified clingo binaries
|
def _read_metadata(self, package_name):
|
||||||
json_filename = '{0}.json'.format(module)
|
"""Return metadata about the given package."""
|
||||||
|
json_filename = '{0}.json'.format(package_name)
|
||||||
json_path = os.path.join(
|
json_path = os.path.join(
|
||||||
spack.paths.share_path, 'bootstrap', self.name, json_filename
|
spack.paths.share_path, 'bootstrap', self.name, json_filename
|
||||||
)
|
)
|
||||||
with open(json_path) as f:
|
with open(json_path) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
|
return data
|
||||||
|
|
||||||
buildcache = spack.main.SpackCommand('buildcache')
|
def _install_by_hash(self, pkg_hash, pkg_sha256, index, bincache_platform):
|
||||||
|
global _buildcache_cmd
|
||||||
|
|
||||||
|
if _buildcache_cmd is None:
|
||||||
|
_buildcache_cmd = spack.main.SpackCommand('buildcache')
|
||||||
|
|
||||||
|
index_spec = next(x for x in index if x.dag_hash() == pkg_hash)
|
||||||
|
# Reconstruct the compiler that we need to use for bootstrapping
|
||||||
|
compiler_entry = {
|
||||||
|
"modules": [],
|
||||||
|
"operating_system": str(index_spec.os),
|
||||||
|
"paths": {
|
||||||
|
"cc": "/dev/null",
|
||||||
|
"cxx": "/dev/null",
|
||||||
|
"f77": "/dev/null",
|
||||||
|
"fc": "/dev/null"
|
||||||
|
},
|
||||||
|
"spec": str(index_spec.compiler),
|
||||||
|
"target": str(index_spec.target.family)
|
||||||
|
}
|
||||||
|
with spack.platforms.use_platform(bincache_platform):
|
||||||
|
with spack.config.override(
|
||||||
|
'compilers', [{'compiler': compiler_entry}]
|
||||||
|
):
|
||||||
|
spec_str = '/' + pkg_hash
|
||||||
|
install_args = [
|
||||||
|
'install',
|
||||||
|
'--sha256', pkg_sha256,
|
||||||
|
'--only-root',
|
||||||
|
'-a', '-u', '-o', '-f', spec_str
|
||||||
|
]
|
||||||
|
_buildcache_cmd(*install_args, fail_on_error=False)
|
||||||
|
|
||||||
|
def _install_and_test(
|
||||||
|
self, abstract_spec, bincache_platform, bincache_data, test_fn
|
||||||
|
):
|
||||||
# Ensure we see only the buildcache being used to bootstrap
|
# Ensure we see only the buildcache being used to bootstrap
|
||||||
mirror_scope = spack.config.InternalConfigScope(
|
with spack.config.override(self.mirror_scope):
|
||||||
'bootstrap_buildcache', {'mirrors:': {self.name: self.url}}
|
|
||||||
)
|
|
||||||
with spack.config.override(mirror_scope):
|
|
||||||
# This index is currently needed to get the compiler used to build some
|
# This index is currently needed to get the compiler used to build some
|
||||||
# specs that wwe know by dag hash.
|
# specs that we know by dag hash.
|
||||||
spack.binary_distribution.binary_index.regenerate_spec_cache()
|
spack.binary_distribution.binary_index.regenerate_spec_cache()
|
||||||
index = spack.binary_distribution.update_cache_and_get_specs()
|
index = spack.binary_distribution.update_cache_and_get_specs()
|
||||||
|
|
||||||
if not index:
|
if not index:
|
||||||
raise RuntimeError("The binary index is empty")
|
raise RuntimeError("The binary index is empty")
|
||||||
|
|
||||||
for item in data['verified']:
|
for item in bincache_data['verified']:
|
||||||
candidate_spec = item['spec']
|
candidate_spec = item['spec']
|
||||||
python_spec = item['python']
|
# This will be None for things that don't depend on python
|
||||||
|
python_spec = item.get('python', None)
|
||||||
# Skip specs which are not compatible
|
# Skip specs which are not compatible
|
||||||
if not abstract_spec.satisfies(candidate_spec):
|
if not abstract_spec.satisfies(candidate_spec):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if python_spec not in abstract_spec:
|
if python_spec is not None and python_spec not in abstract_spec:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for pkg_name, pkg_hash, pkg_sha256 in item['binaries']:
|
for pkg_name, pkg_hash, pkg_sha256 in item['binaries']:
|
||||||
msg = ('[BOOTSTRAP MODULE {0}] Try installing "{1}" from binary '
|
# TODO: undo installations that didn't complete?
|
||||||
'cache at "{2}"')
|
self._install_by_hash(
|
||||||
tty.debug(msg.format(module, pkg_name, self.url))
|
pkg_hash, pkg_sha256, index, bincache_platform
|
||||||
index_spec = next(x for x in index if x.dag_hash() == pkg_hash)
|
)
|
||||||
# Reconstruct the compiler that we need to use for bootstrapping
|
|
||||||
compiler_entry = {
|
|
||||||
"modules": [],
|
|
||||||
"operating_system": str(index_spec.os),
|
|
||||||
"paths": {
|
|
||||||
"cc": "/dev/null",
|
|
||||||
"cxx": "/dev/null",
|
|
||||||
"f77": "/dev/null",
|
|
||||||
"fc": "/dev/null"
|
|
||||||
},
|
|
||||||
"spec": str(index_spec.compiler),
|
|
||||||
"target": str(index_spec.target.family)
|
|
||||||
}
|
|
||||||
with spack.platforms.use_platform(bincache_platform):
|
|
||||||
with spack.config.override(
|
|
||||||
'compilers', [{'compiler': compiler_entry}]
|
|
||||||
):
|
|
||||||
spec_str = '/' + pkg_hash
|
|
||||||
install_args = [
|
|
||||||
'install',
|
|
||||||
'--sha256', pkg_sha256,
|
|
||||||
'-a', '-u', '-o', '-f', spec_str
|
|
||||||
]
|
|
||||||
buildcache(*install_args, fail_on_error=False)
|
|
||||||
# TODO: undo installations that didn't complete?
|
|
||||||
|
|
||||||
if _try_import_from_store(module, abstract_spec_str):
|
if test_fn():
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mirror_scope(self):
|
||||||
|
return spack.config.InternalConfigScope(
|
||||||
|
'bootstrap', {'mirrors:': {self.name: self.url}}
|
||||||
|
)
|
||||||
|
|
||||||
|
def try_import(self, module, abstract_spec_str):
|
||||||
|
test_fn = functools.partial(_try_import_from_store, module, abstract_spec_str)
|
||||||
|
if test_fn():
|
||||||
|
return True
|
||||||
|
|
||||||
|
tty.info("Bootstrapping {0} from pre-built binaries".format(module))
|
||||||
|
abstract_spec, bincache_platform = self._spec_and_platform(
|
||||||
|
abstract_spec_str + ' ^' + spec_for_current_python()
|
||||||
|
)
|
||||||
|
data = self._read_metadata(module)
|
||||||
|
return self._install_and_test(
|
||||||
|
abstract_spec, bincache_platform, data, test_fn
|
||||||
|
)
|
||||||
|
|
||||||
|
def try_search_path(self, executables, abstract_spec_str):
|
||||||
|
test_fn = functools.partial(
|
||||||
|
_executables_in_store, executables, abstract_spec_str
|
||||||
|
)
|
||||||
|
if test_fn():
|
||||||
|
return True
|
||||||
|
|
||||||
|
abstract_spec, bincache_platform = self._spec_and_platform(
|
||||||
|
abstract_spec_str
|
||||||
|
)
|
||||||
|
tty.info("Bootstrapping {0} from pre-built binaries".format(abstract_spec.name))
|
||||||
|
data = self._read_metadata(abstract_spec.name)
|
||||||
|
return self._install_and_test(
|
||||||
|
abstract_spec, bincache_platform, data, test_fn
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@_bootstrapper(type='install')
|
@_bootstrapper(type='install')
|
||||||
class _SourceBootstrapper(object):
|
class _SourceBootstrapper(object):
|
||||||
|
@ -307,6 +386,26 @@ def try_import(module, abstract_spec_str):
|
||||||
|
|
||||||
return _try_import_from_store(module, abstract_spec_str=abstract_spec_str)
|
return _try_import_from_store(module, abstract_spec_str=abstract_spec_str)
|
||||||
|
|
||||||
|
def try_search_path(self, executables, abstract_spec_str):
|
||||||
|
if _executables_in_store(executables, abstract_spec_str):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# If we compile code from sources detecting a few build tools
|
||||||
|
# might reduce compilation time by a fair amount
|
||||||
|
_add_externals_if_missing()
|
||||||
|
|
||||||
|
# Add hint to use frontend operating system on Cray
|
||||||
|
if str(spack.platforms.host()) == 'cray':
|
||||||
|
abstract_spec_str += ' os=fe'
|
||||||
|
|
||||||
|
concrete_spec = spack.spec.Spec(abstract_spec_str)
|
||||||
|
concrete_spec.concretize()
|
||||||
|
|
||||||
|
msg = "[BOOTSTRAP GnuPG] Try installing '{0}' from sources"
|
||||||
|
tty.debug(msg.format(abstract_spec_str))
|
||||||
|
concrete_spec.package.do_install()
|
||||||
|
return _executables_in_store(executables, abstract_spec_str)
|
||||||
|
|
||||||
|
|
||||||
def _make_bootstrapper(conf):
|
def _make_bootstrapper(conf):
|
||||||
"""Return a bootstrap object built according to the
|
"""Return a bootstrap object built according to the
|
||||||
|
@ -418,6 +517,44 @@ def ensure_module_importable_or_raise(module, abstract_spec=None):
|
||||||
raise ImportError(msg)
|
raise ImportError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_executables_in_path_or_raise(executables, abstract_spec):
|
||||||
|
"""Ensure that some executables are in path or raise.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
executables (list): list of executables to be searched in the PATH,
|
||||||
|
in order. The function exits on the first one found.
|
||||||
|
abstract_spec (str): abstract spec that provides the executables
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: if the executables cannot be ensured to be in PATH
|
||||||
|
"""
|
||||||
|
if spack.util.executable.which_string(*executables):
|
||||||
|
return
|
||||||
|
|
||||||
|
executables_str = ', '.join(executables)
|
||||||
|
source_configs = spack.config.get('bootstrap:sources', [])
|
||||||
|
for current_config in source_configs:
|
||||||
|
if not _source_is_trusted(current_config):
|
||||||
|
msg = ('[BOOTSTRAP EXECUTABLES {0}] Skipping source "{1}" since it is '
|
||||||
|
'not trusted').format(executables_str, current_config['name'])
|
||||||
|
tty.debug(msg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
b = _make_bootstrapper(current_config)
|
||||||
|
try:
|
||||||
|
if b.try_search_path(executables, abstract_spec):
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
msg = '[BOOTSTRAP EXECUTABLES {0}] Unexpected error "{1}"'
|
||||||
|
tty.debug(msg.format(executables_str, str(e)))
|
||||||
|
|
||||||
|
# We couldn't import in any way, so raise an import error
|
||||||
|
msg = 'cannot bootstrap any of the {0} executables'.format(executables_str)
|
||||||
|
if abstract_spec:
|
||||||
|
msg += ' from spec "{0}"'.format(abstract_spec)
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
|
||||||
def _python_import(module):
|
def _python_import(module):
|
||||||
try:
|
try:
|
||||||
__import__(module)
|
__import__(module)
|
||||||
|
@ -455,7 +592,9 @@ def get_executable(exe, spec=None, install=False):
|
||||||
ret = spack.util.executable.Executable(exe_path[0])
|
ret = spack.util.executable.Executable(exe_path[0])
|
||||||
envmod = EnvironmentModifications()
|
envmod = EnvironmentModifications()
|
||||||
for dep in ispec.traverse(root=True, order='post'):
|
for dep in ispec.traverse(root=True, order='post'):
|
||||||
envmod.extend(uenv.environment_modifications_for_spec(dep))
|
envmod.extend(
|
||||||
|
spack.user_environment.environment_modifications_for_spec(dep)
|
||||||
|
)
|
||||||
ret.add_default_envmod(envmod)
|
ret.add_default_envmod(envmod)
|
||||||
return ret
|
return ret
|
||||||
else:
|
else:
|
||||||
|
@ -484,7 +623,9 @@ def _raise_error(executable, exe_spec):
|
||||||
ret = spack.util.executable.Executable(exe_path[0])
|
ret = spack.util.executable.Executable(exe_path[0])
|
||||||
envmod = EnvironmentModifications()
|
envmod = EnvironmentModifications()
|
||||||
for dep in spec.traverse(root=True, order='post'):
|
for dep in spec.traverse(root=True, order='post'):
|
||||||
envmod.extend(uenv.environment_modifications_for_spec(dep))
|
envmod.extend(
|
||||||
|
spack.user_environment.environment_modifications_for_spec(dep)
|
||||||
|
)
|
||||||
ret.add_default_envmod(envmod)
|
ret.add_default_envmod(envmod)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -523,8 +664,11 @@ def _add_compilers_if_missing():
|
||||||
|
|
||||||
def _add_externals_if_missing():
|
def _add_externals_if_missing():
|
||||||
search_list = [
|
search_list = [
|
||||||
|
# clingo
|
||||||
spack.repo.path.get('cmake'),
|
spack.repo.path.get('cmake'),
|
||||||
spack.repo.path.get('bison')
|
spack.repo.path.get('bison'),
|
||||||
|
# GnuPG
|
||||||
|
spack.repo.path.get('gawk')
|
||||||
]
|
]
|
||||||
detected_packages = spack.detection.by_executable(search_list)
|
detected_packages = spack.detection.by_executable(search_list)
|
||||||
spack.detection.update_configuration(detected_packages, scope='bootstrap')
|
spack.detection.update_configuration(detected_packages, scope='bootstrap')
|
||||||
|
@ -600,10 +744,12 @@ def _config_path():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def clingo_root_spec():
|
def _root_spec(spec_str):
|
||||||
# Construct the root spec that will be used to bootstrap clingo
|
"""Add a proper compiler and target to a spec used during bootstrapping.
|
||||||
spec_str = 'clingo-bootstrap@spack+python'
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
spec_str (str): spec to be bootstrapped. Must be without compiler and target.
|
||||||
|
"""
|
||||||
# Add a proper compiler hint to the root spec. We use GCC for
|
# Add a proper compiler hint to the root spec. We use GCC for
|
||||||
# everything but MacOS.
|
# everything but MacOS.
|
||||||
if str(spack.platforms.host()) == 'darwin':
|
if str(spack.platforms.host()) == 'darwin':
|
||||||
|
@ -611,17 +757,32 @@ def clingo_root_spec():
|
||||||
else:
|
else:
|
||||||
spec_str += ' %gcc'
|
spec_str += ' %gcc'
|
||||||
|
|
||||||
# Add the generic target
|
target = archspec.cpu.host().family
|
||||||
generic_target = archspec.cpu.host().family
|
spec_str += ' target={0}'.format(target)
|
||||||
spec_str += ' target={0}'.format(str(generic_target))
|
|
||||||
|
|
||||||
tty.debug('[BOOTSTRAP ROOT SPEC] clingo: {0}'.format(spec_str))
|
|
||||||
|
|
||||||
|
tty.debug('[BOOTSTRAP ROOT SPEC] {0}'.format(spec_str))
|
||||||
return spec_str
|
return spec_str
|
||||||
|
|
||||||
|
|
||||||
|
def clingo_root_spec():
|
||||||
|
"""Return the root spec used to bootstrap clingo"""
|
||||||
|
return _root_spec('clingo-bootstrap@spack+python')
|
||||||
|
|
||||||
|
|
||||||
def ensure_clingo_importable_or_raise():
|
def ensure_clingo_importable_or_raise():
|
||||||
"""Ensure that the clingo module is available for import."""
|
"""Ensure that the clingo module is available for import."""
|
||||||
ensure_module_importable_or_raise(
|
ensure_module_importable_or_raise(
|
||||||
module='clingo', abstract_spec=clingo_root_spec()
|
module='clingo', abstract_spec=clingo_root_spec()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def gnupg_root_spec():
|
||||||
|
"""Return the root spec used to bootstrap GnuPG"""
|
||||||
|
return _root_spec('gnupg@2.3:')
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_gpg_in_path_or_raise():
|
||||||
|
"""Ensure gpg or gpg2 are in the PATH or raise."""
|
||||||
|
ensure_executables_in_path_or_raise(
|
||||||
|
executables=['gpg2', 'gpg'], abstract_spec=gnupg_root_spec(),
|
||||||
|
)
|
||||||
|
|
|
@ -104,6 +104,9 @@ def setup_parser(subparser):
|
||||||
" instead of default platform and OS")
|
" instead of default platform and OS")
|
||||||
# This argument is needed by the bootstrapping logic to verify checksums
|
# This argument is needed by the bootstrapping logic to verify checksums
|
||||||
install.add_argument('--sha256', help=argparse.SUPPRESS)
|
install.add_argument('--sha256', help=argparse.SUPPRESS)
|
||||||
|
install.add_argument(
|
||||||
|
'--only-root', action='store_true', help=argparse.SUPPRESS
|
||||||
|
)
|
||||||
|
|
||||||
arguments.add_common_arguments(install, ['specs'])
|
arguments.add_common_arguments(install, ['specs'])
|
||||||
install.set_defaults(func=installtarball)
|
install.set_defaults(func=installtarball)
|
||||||
|
@ -534,9 +537,14 @@ def install_tarball(spec, args):
|
||||||
if s.external or s.virtual:
|
if s.external or s.virtual:
|
||||||
tty.warn("Skipping external or virtual package %s" % spec.format())
|
tty.warn("Skipping external or virtual package %s" % spec.format())
|
||||||
return
|
return
|
||||||
for d in s.dependencies(deptype=('link', 'run')):
|
|
||||||
tty.msg("Installing buildcache for dependency spec %s" % d)
|
# This argument is used only for bootstrapping specs without signatures,
|
||||||
install_tarball(d, args)
|
# since we need to check the sha256 of each tarball
|
||||||
|
if not args.only_root:
|
||||||
|
for d in s.dependencies(deptype=('link', 'run')):
|
||||||
|
tty.msg("Installing buildcache for dependency spec %s" % d)
|
||||||
|
install_tarball(d, args)
|
||||||
|
|
||||||
package = spack.repo.get(spec)
|
package = spack.repo.get(spec)
|
||||||
if s.concrete and package.installed and not args.force:
|
if s.concrete and package.installed and not args.force:
|
||||||
tty.warn("Package for spec %s already installed." % spec.format())
|
tty.warn("Package for spec %s already installed." % spec.format())
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.lang import dedupe
|
from llnl.util.lang import dedupe
|
||||||
|
|
||||||
import spack.build_environment as build_environment
|
import spack.build_environment
|
||||||
import spack.config
|
import spack.config
|
||||||
import spack.environment
|
import spack.environment
|
||||||
import spack.error
|
import spack.error
|
||||||
|
@ -732,12 +732,12 @@ def environment_modifications(self):
|
||||||
# Let the extendee/dependency modify their extensions/dependencies
|
# Let the extendee/dependency modify their extensions/dependencies
|
||||||
# before asking for package-specific modifications
|
# before asking for package-specific modifications
|
||||||
env.extend(
|
env.extend(
|
||||||
build_environment.modifications_from_dependencies(
|
spack.build_environment.modifications_from_dependencies(
|
||||||
spec, context='run'
|
spec, context='run'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# Package specific modifications
|
# Package specific modifications
|
||||||
build_environment.set_module_variables_for_package(spec.package)
|
spack.build_environment.set_module_variables_for_package(spec.package)
|
||||||
spec.package.setup_run_environment(env)
|
spec.package.setup_run_environment(env)
|
||||||
|
|
||||||
# Modifications required from modules.yaml
|
# Modifications required from modules.yaml
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
import llnl.util.filesystem as fs
|
import llnl.util.filesystem as fs
|
||||||
|
|
||||||
|
import spack.bootstrap
|
||||||
import spack.util.executable
|
import spack.util.executable
|
||||||
import spack.util.gpg
|
import spack.util.gpg
|
||||||
from spack.main import SpackCommand
|
from spack.main import SpackCommand
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
|
|
||||||
#: spack command used by tests below
|
#: spack command used by tests below
|
||||||
gpg = SpackCommand('gpg')
|
gpg = SpackCommand('gpg')
|
||||||
|
bootstrap = SpackCommand('bootstrap')
|
||||||
|
|
||||||
|
|
||||||
# test gpg command detection
|
# test gpg command detection
|
||||||
|
@ -46,9 +48,10 @@ def test_find_gpg(cmd_name, version, tmpdir, mock_gnupghome, monkeypatch):
|
||||||
assert spack.util.gpg.GPGCONF is not None
|
assert spack.util.gpg.GPGCONF is not None
|
||||||
|
|
||||||
|
|
||||||
def test_no_gpg_in_path(tmpdir, mock_gnupghome, monkeypatch):
|
def test_no_gpg_in_path(tmpdir, mock_gnupghome, monkeypatch, mutable_config):
|
||||||
monkeypatch.setitem(os.environ, "PATH", str(tmpdir))
|
monkeypatch.setitem(os.environ, "PATH", str(tmpdir))
|
||||||
with pytest.raises(spack.util.gpg.SpackGPGError):
|
bootstrap('disable')
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
spack.util.gpg.init(force=True)
|
spack.util.gpg.init(force=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import spack.bootstrap
|
||||||
import spack.error
|
import spack.error
|
||||||
import spack.paths
|
import spack.paths
|
||||||
import spack.util.executable
|
import spack.util.executable
|
||||||
|
@ -59,7 +60,10 @@ def init(gnupghome=None, force=False):
|
||||||
spack.paths.gpg_path)
|
spack.paths.gpg_path)
|
||||||
|
|
||||||
# Set the executable objects for "gpg" and "gpgconf"
|
# Set the executable objects for "gpg" and "gpgconf"
|
||||||
GPG, GPGCONF = _gpg(), _gpgconf()
|
with spack.bootstrap.ensure_bootstrap_configuration():
|
||||||
|
spack.bootstrap.ensure_gpg_in_path_or_raise()
|
||||||
|
GPG, GPGCONF = _gpg(), _gpgconf()
|
||||||
|
|
||||||
GPG.add_default_env('GNUPGHOME', GNUPGHOME)
|
GPG.add_default_env('GNUPGHOME', GNUPGHOME)
|
||||||
if GPGCONF:
|
if GPGCONF:
|
||||||
GPGCONF.add_default_env('GNUPGHOME', GNUPGHOME)
|
GPGCONF.add_default_env('GNUPGHOME', GNUPGHOME)
|
||||||
|
|
204
share/spack/bootstrap/github-actions/gnupg.json
Normal file
204
share/spack/bootstrap/github-actions/gnupg.json
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
{
|
||||||
|
"verified": [
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
[
|
||||||
|
"libgpg-error",
|
||||||
|
"hph66gvb7vlinpzwoytxq27ojb7gtl2j",
|
||||||
|
"f040f513e212c428ee863d75924331f58b5f8f3946f98c757a9e0af0d0a34f63"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libiconv",
|
||||||
|
"ckpif6rcf7mxdmceyv6sqvtnwfqi7fmc",
|
||||||
|
"1d745d04f7c8a1c4d17d9735eba0ee88c8acfbb213c22a15e45e58637867ed4c"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"npth",
|
||||||
|
"fjuoy73whriauk3bt6ma5fwet6iric7y",
|
||||||
|
"78d5d9e339ef901b0def0924a72ce87a93e0a8acb7394ec2c35be6c328154444"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"zlib",
|
||||||
|
"qo6otxqnn6mxpw4zhqc4wdwqmgcfjdfe",
|
||||||
|
"f00c38ecaf316cd665399ed14c233f839ae5868387ff04998e1ec949c1f4dcd6"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libassuan",
|
||||||
|
"2upi74qccouj4k6d7wultp2u5fntayi3",
|
||||||
|
"f2118b102f9a94bb1e2804492689b44b260b7f6e46ac1208d5110ebffe24bf99"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libgcrypt",
|
||||||
|
"xzhvvm44cfxwvgqgkpbeucpnl4dbj4p2",
|
||||||
|
"ae717e068f2f7f4eaeee4bdec4a6b20ff299c59c3d724c1661b6045fda628a9b"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libksba",
|
||||||
|
"aodyg5mzfule3vimuetmzulv5mzdx37g",
|
||||||
|
"c665eb20f27b2d28fcb634fe958829165e44a27b1ad69995d5040f13d5693d52"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"pinentry",
|
||||||
|
"ihqcvdm5okxuvnln463l7h4flbkhrp44",
|
||||||
|
"b0c7781354eb4a7c9e979802590c0e4fb7eb53f440191367f0142eac4868f8d6"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"gnupg",
|
||||||
|
"47vilwybwuxved7jov7esiad3qlkv5rp",
|
||||||
|
"83f3de13b2712a05f520d16b5141797493f8b117041dd32aa5414a25d9d53439"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"spec": "gnupg@2.3: %apple-clang platform=darwin target=x86_64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
[
|
||||||
|
"libgpg-error",
|
||||||
|
"3dkguooajaaejhsebigs2e3lhk37mtem",
|
||||||
|
"09c5edd93fb479961d62d9938c1ea02b8f443babf0e79776f1539085c3422cd5"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libiconv",
|
||||||
|
"i2eqtudh3zcxt5fvxuhe6n2ztuqbadtp",
|
||||||
|
"838786e029474d668b5f83a9669d227c812253c3c3f0328aa4f888542a7de830"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"npth",
|
||||||
|
"c3z6gg3ilutvvryxkjrboampqv5u5s2s",
|
||||||
|
"967522ae988ccce8c922f28aa2124170246f501f0a45179b919d827bf28c35d2"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"zlib",
|
||||||
|
"p2jozvok56voja7652dms4gvthpcjzta",
|
||||||
|
"41cbc69850640ed4466dbedc1bb4ccb0ade0c1a1e8fcd70d1e247b1387b937b5"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libassuan",
|
||||||
|
"s2wx2xvt3iz3sigcdt5tvppj2m7e2bsf",
|
||||||
|
"5f766af4ff355769e3e456a9c95636a20a64f5ba32aecec633216a3d83a854f8"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libgcrypt",
|
||||||
|
"gznmtryix6ck4x3chnuvbctz4xa3fmxl",
|
||||||
|
"0261b03f790c5320980d27bf0a471a1a4663929689ddfaeb5e568d33be8dc889"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libksba",
|
||||||
|
"uxaryyfybbcw563jcwumufhfmbsawlbz",
|
||||||
|
"f45fff7a6a5c626a1474c7354fd00e18e629fcd086787336f7d62d1ead50c94f"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"pinentry",
|
||||||
|
"ias6sb4qi24u6i7axr5hkj4liq5dtr6l",
|
||||||
|
"a2a8e7652dceb7d080ff78726d28099f9050cb9f6e290d97f1f59f4b42521b9c"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"gnupg",
|
||||||
|
"qpm457bujhmfqy66euzhswokumuvufbz",
|
||||||
|
"d2371e26412e10fc702b9b2482aff776108194b84e1927644a3d64f5710fd163"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"spec": "gnupg@2.3: %gcc platform=linux target=aarch64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
[
|
||||||
|
"libgpg-error",
|
||||||
|
"4bp6dcfdbzbd4uuzvbgjyqunhjedg3lf",
|
||||||
|
"9a9947240c6af7e915aa8336bfaed8706c9129967eb9ab1895598217df91f301"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libiconv",
|
||||||
|
"dscneqtpyy32r6ds24izlkki3euthnbr",
|
||||||
|
"a9dc099f6c7ee9fd6c63757cb81a59fe4b81672543d5253a50bb73bc819440ef"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"npth",
|
||||||
|
"jukmafxhkxo2s4udlzi5r5b6bbb3udw5",
|
||||||
|
"d2a2b11c0f1794ab0de813753221bde073508fbec19f0b15dbfd23455bc6de87"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"zlib",
|
||||||
|
"amqfrcbn67rochzkeu2ashklo35ayqqq",
|
||||||
|
"686fc10058d208530889bc5c3779aa2cc324b77301878a5405cf65ca53d613ba"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libassuan",
|
||||||
|
"lyeih2j3miy7yugmwh37h667fogqn3fl",
|
||||||
|
"f87c474d81c890232cd8e1e4d93b5b232aa0ad428dcaa7231d7a8d182cea9ecc"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libgcrypt",
|
||||||
|
"zb33zulvwcansfzu5km4d34avujnazfa",
|
||||||
|
"e67ae6a5345f9e864bd2009c1a9d7eb65a63ca2841368bebc477a770fb8dcaf5"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libksba",
|
||||||
|
"yjuh2aplj23qyvaqixukd7a6eokfdgyp",
|
||||||
|
"6944fc047e8f0eb41daec734e2505016369319c64929f5ec8d3a8f99e01928d4"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"pinentry",
|
||||||
|
"xd7vajghgcueohv5qgahdvbjpcnrurns",
|
||||||
|
"a6b37efd6ef9f9374aa0c7d1869da990ae3668938b47ad6af50138d2ea05da02"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"gnupg",
|
||||||
|
"ti2ddl27nilobj2ctwsgzl52qque5o7z",
|
||||||
|
"43781437e3dfae158e7a6911313a4162d8ffa5313182438d1e6547a854f6f38a"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"spec": "gnupg@2.3: %gcc platform=linux target=ppc64le"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
[
|
||||||
|
"libgpg-error",
|
||||||
|
"p7chd5hhecdkc27npia4uaoeabjit4gh",
|
||||||
|
"4b5e1f418b7afdd91755d54d38a51d5d048aa3b1e5239bcaf3453c8ca1cca4b6"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libiconv",
|
||||||
|
"scpkgy6bmk3wcgfwzoiv7hw74drmnaoi",
|
||||||
|
"2bcb9a2868c20284ce65ab53d4f7bb4c7edccd4c14390460858e25a8bc48faa3"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"npth",
|
||||||
|
"6vh3jypaf7u2zez3vohn66fvo6znt35l",
|
||||||
|
"23a333c4e83910eb1f87c91caffb07f40b592561a4c44924fed9459751c017f7"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"zlib",
|
||||||
|
"uc25tb5r57nykfrxszsdy54trzqnk2jn",
|
||||||
|
"9e18c1146bc3dcb8454d18502013b8621ecf00d2f2d4d66d76cbe1e07f351ac8"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libassuan",
|
||||||
|
"vdoskg5mldu6ixhvftwplp4zdftwxwws",
|
||||||
|
"1413b84af0c58127032e7bde86dbacf35dc65205aee1c2071718678bc57ce793"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libgcrypt",
|
||||||
|
"ng7gfusjpnypmqgckq7rp4vq3bvylp3b",
|
||||||
|
"1a09e97eb2333812f8381d4737aca4d7cfd9f27ebae30eddbcf99f399ad67fec"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"libksba",
|
||||||
|
"p4feho36xa7dhabk766fzglwyo2dfbj6",
|
||||||
|
"000ef0f2ad3aa05c07272849be68e059ec60946970ab8875a824305afe832c9a"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"pinentry",
|
||||||
|
"m423kpm7k52r66q3sdctqcjxtekiyrrp",
|
||||||
|
"5739bee66271d7f0d5b9bcf5c248f1a434e9cdcb327a4a5a22fc47f565ac0de7"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"gnupg",
|
||||||
|
"dlapzqxrwduafgfq2evptizb7p4kgpkh",
|
||||||
|
"262177fa8f66468e589f8b3e10d17531f17a74ea0f5ac6905ac948198dca3c3c"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"spec": "gnupg@2.3: %gcc platform=linux target=x86_64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -511,7 +511,7 @@ _spack_buildcache_create() {
|
||||||
_spack_buildcache_install() {
|
_spack_buildcache_install() {
|
||||||
if $list_options
|
if $list_options
|
||||||
then
|
then
|
||||||
SPACK_COMPREPLY="-h --help -f --force -m --multiple -a --allow-root -u --unsigned -o --otherarch --sha256"
|
SPACK_COMPREPLY="-h --help -f --force -m --multiple -a --allow-root -u --unsigned -o --otherarch --sha256 --only-root"
|
||||||
else
|
else
|
||||||
_all_packages
|
_all_packages
|
||||||
fi
|
fi
|
||||||
|
|
Loading…
Reference in a new issue