summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorkwryankrattiger <80296582+kwryankrattiger@users.noreply.github.com>2024-03-26 10:47:45 -0500
committerGitHub <noreply@github.com>2024-03-26 08:47:45 -0700
commitae9c86a93082e1181691d89c80ff95411a1b50d2 (patch)
treef9f0c41d532743265fa369039d37fba3641171fa /lib
parent83199a981d2c86f804349876da32d07b239b3f56 (diff)
downloadspack-ae9c86a93082e1181691d89c80ff95411a1b50d2.tar.gz
spack-ae9c86a93082e1181691d89c80ff95411a1b50d2.tar.bz2
spack-ae9c86a93082e1181691d89c80ff95411a1b50d2.tar.xz
spack-ae9c86a93082e1181691d89c80ff95411a1b50d2.zip
buildcache sync: manifest-glob with arbitrary destination (#41284)
* buildcache sync: manifest-glob with arbitrary destination The current implementation of the --manifest-glob is a bit restrictive requiring the destination to be known by the generation stage of CI. This allows specifying an arbitrary destination mirror URL. * Add unit test for buildcache sync with manifest * Fix test and arguments for manifest-glob with override destination * Add testing path for unused mirror argument
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/cmd/buildcache.py49
-rw-r--r--lib/spack/spack/test/cmd/buildcache.py62
2 files changed, 102 insertions, 9 deletions
diff --git a/lib/spack/spack/cmd/buildcache.py b/lib/spack/spack/cmd/buildcache.py
index 8a2398b705..ad50cb94a4 100644
--- a/lib/spack/spack/cmd/buildcache.py
+++ b/lib/spack/spack/cmd/buildcache.py
@@ -275,23 +275,37 @@ def setup_parser(subparser: argparse.ArgumentParser):
# Sync buildcache entries from one mirror to another
sync = subparsers.add_parser("sync", help=sync_fn.__doc__)
- sync.add_argument(
- "--manifest-glob", help="a quoted glob pattern identifying copy manifest files"
+
+ sync_manifest_source = sync.add_argument_group(
+ "Manifest Source",
+ "Specify a list of build cache objects to sync using manifest file(s)."
+ 'This option takes the place of the "source mirror" for synchronization'
+ 'and optionally takes a "destination mirror" ',
)
- sync.add_argument(
+ sync_manifest_source.add_argument(
+ "--manifest-glob", help="a quoted glob pattern identifying CI rebuild manifest files"
+ )
+ sync_source_mirror = sync.add_argument_group(
+ "Named Source",
+ "Specify a single registered source mirror to synchronize from. This option requires"
+ "the specification of a destination mirror.",
+ )
+ sync_source_mirror.add_argument(
"src_mirror",
metavar="source mirror",
- type=arguments.mirror_name_or_url,
nargs="?",
+ type=arguments.mirror_name_or_url,
help="source mirror name, path, or URL",
)
+
sync.add_argument(
"dest_mirror",
metavar="destination mirror",
- type=arguments.mirror_name_or_url,
nargs="?",
+ type=arguments.mirror_name_or_url,
help="destination mirror name, path, or URL",
)
+
sync.set_defaults(func=sync_fn)
# Update buildcache index without copying any additional packages
@@ -1070,7 +1084,17 @@ def sync_fn(args):
requires an active environment in order to know which specs to sync
"""
if args.manifest_glob:
- manifest_copy(glob.glob(args.manifest_glob))
+ # Passing the args.src_mirror here because it is not possible to
+ # have the destination be required when specifying a named source
+ # mirror and optional for the --manifest-glob argument. In the case
+ # of manifest glob sync, the source mirror positional argument is the
+ # destination mirror if it is specified. If there are two mirrors
+ # specified, the second is ignored and the first is the override
+ # destination.
+ if args.dest_mirror:
+ tty.warn(f"Ignoring unused arguemnt: {args.dest_mirror.name}")
+
+ manifest_copy(glob.glob(args.manifest_glob), args.src_mirror)
return 0
if args.src_mirror is None or args.dest_mirror is None:
@@ -1121,7 +1145,7 @@ def sync_fn(args):
shutil.rmtree(tmpdir)
-def manifest_copy(manifest_file_list):
+def manifest_copy(manifest_file_list, dest_mirror=None):
"""Read manifest files containing information about specific specs to copy
from source to destination, remove duplicates since any binary packge for
a given hash should be the same as any other, and copy all files specified
@@ -1135,10 +1159,17 @@ def manifest_copy(manifest_file_list):
# Last duplicate hash wins
deduped_manifest[spec_hash] = copy_list
+ build_cache_dir = bindist.build_cache_relative_path()
for spec_hash, copy_list in deduped_manifest.items():
for copy_file in copy_list:
- tty.debug("copying {0} to {1}".format(copy_file["src"], copy_file["dest"]))
- copy_buildcache_file(copy_file["src"], copy_file["dest"])
+ dest = copy_file["dest"]
+ if dest_mirror:
+ src_relative_path = os.path.join(
+ build_cache_dir, copy_file["src"].rsplit(build_cache_dir, 1)[1].lstrip("/")
+ )
+ dest = url_util.join(dest_mirror.push_url, src_relative_path)
+ tty.debug("copying {0} to {1}".format(copy_file["src"], dest))
+ copy_buildcache_file(copy_file["src"], dest)
def update_index(mirror: spack.mirror.Mirror, update_keys=False):
diff --git a/lib/spack/spack/test/cmd/buildcache.py b/lib/spack/spack/test/cmd/buildcache.py
index 06d0c1d751..12ef53e856 100644
--- a/lib/spack/spack/test/cmd/buildcache.py
+++ b/lib/spack/spack/test/cmd/buildcache.py
@@ -4,6 +4,7 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import errno
+import json
import os
import shutil
@@ -234,10 +235,71 @@ def test_buildcache_sync(
# Use mirror names to specify mirrors
mirror("add", "src", src_mirror_url)
mirror("add", "dest", dest_mirror_url)
+ mirror("add", "ignored", "file:///dummy/io")
buildcache("sync", "src", "dest")
verify_mirror_contents()
+ shutil.rmtree(dest_mirror_dir)
+
+ def manifest_insert(manifest, spec, dest_url):
+ manifest[spec.dag_hash()] = [
+ {
+ "src": spack.util.url.join(
+ src_mirror_url,
+ spack.binary_distribution.build_cache_relative_path(),
+ spack.binary_distribution.tarball_name(spec, ".spec.json"),
+ ),
+ "dest": spack.util.url.join(
+ dest_url,
+ spack.binary_distribution.build_cache_relative_path(),
+ spack.binary_distribution.tarball_name(spec, ".spec.json"),
+ ),
+ },
+ {
+ "src": spack.util.url.join(
+ src_mirror_url,
+ spack.binary_distribution.build_cache_relative_path(),
+ spack.binary_distribution.tarball_path_name(spec, ".spack"),
+ ),
+ "dest": spack.util.url.join(
+ dest_url,
+ spack.binary_distribution.build_cache_relative_path(),
+ spack.binary_distribution.tarball_path_name(spec, ".spack"),
+ ),
+ },
+ ]
+
+ manifest_file = os.path.join(tmpdir.strpath, "manifest_dest.json")
+ with open(manifest_file, "w") as fd:
+ test_env = ev.active_environment()
+
+ manifest = {}
+ for spec in test_env.specs_by_hash.values():
+ manifest_insert(manifest, spec, dest_mirror_url)
+ json.dump(manifest, fd)
+
+ buildcache("sync", "--manifest-glob", manifest_file)
+
+ verify_mirror_contents()
+ shutil.rmtree(dest_mirror_dir)
+
+ manifest_file = os.path.join(tmpdir.strpath, "manifest_bad_dest.json")
+ with open(manifest_file, "w") as fd:
+ manifest = {}
+ for spec in test_env.specs_by_hash.values():
+ manifest_insert(
+ manifest, spec, spack.util.url.join(dest_mirror_url, "invalid_path")
+ )
+ json.dump(manifest, fd)
+
+ # Trigger the warning
+ output = buildcache("sync", "--manifest-glob", manifest_file, "dest", "ignored")
+
+ assert "Ignoring unused arguemnt: ignored" in output
+
+ verify_mirror_contents()
+ shutil.rmtree(dest_mirror_dir)
def test_buildcache_create_install(