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
This commit is contained in:
kwryankrattiger 2024-03-26 10:47:45 -05:00 committed by GitHub
parent 83199a981d
commit ae9c86a930
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 103 additions and 13 deletions

View file

@ -275,23 +275,37 @@ def setup_parser(subparser: argparse.ArgumentParser):
# Sync buildcache entries from one mirror to another # Sync buildcache entries from one mirror to another
sync = subparsers.add_parser("sync", help=sync_fn.__doc__) 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", "src_mirror",
metavar="source mirror", metavar="source mirror",
type=arguments.mirror_name_or_url,
nargs="?", nargs="?",
type=arguments.mirror_name_or_url,
help="source mirror name, path, or URL", help="source mirror name, path, or URL",
) )
sync.add_argument( sync.add_argument(
"dest_mirror", "dest_mirror",
metavar="destination mirror", metavar="destination mirror",
type=arguments.mirror_name_or_url,
nargs="?", nargs="?",
type=arguments.mirror_name_or_url,
help="destination mirror name, path, or URL", help="destination mirror name, path, or URL",
) )
sync.set_defaults(func=sync_fn) sync.set_defaults(func=sync_fn)
# Update buildcache index without copying any additional packages # 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 requires an active environment in order to know which specs to sync
""" """
if args.manifest_glob: 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 return 0
if args.src_mirror is None or args.dest_mirror is None: if args.src_mirror is None or args.dest_mirror is None:
@ -1121,7 +1145,7 @@ def sync_fn(args):
shutil.rmtree(tmpdir) 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 """Read manifest files containing information about specific specs to copy
from source to destination, remove duplicates since any binary packge for 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 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 # Last duplicate hash wins
deduped_manifest[spec_hash] = copy_list deduped_manifest[spec_hash] = copy_list
build_cache_dir = bindist.build_cache_relative_path()
for spec_hash, copy_list in deduped_manifest.items(): for spec_hash, copy_list in deduped_manifest.items():
for copy_file in copy_list: for copy_file in copy_list:
tty.debug("copying {0} to {1}".format(copy_file["src"], copy_file["dest"])) dest = copy_file["dest"]
copy_buildcache_file(copy_file["src"], 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): def update_index(mirror: spack.mirror.Mirror, update_keys=False):

View file

@ -4,6 +4,7 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import errno import errno
import json
import os import os
import shutil import shutil
@ -234,10 +235,71 @@ def verify_mirror_contents():
# Use mirror names to specify mirrors # Use mirror names to specify mirrors
mirror("add", "src", src_mirror_url) mirror("add", "src", src_mirror_url)
mirror("add", "dest", dest_mirror_url) mirror("add", "dest", dest_mirror_url)
mirror("add", "ignored", "file:///dummy/io")
buildcache("sync", "src", "dest") buildcache("sync", "src", "dest")
verify_mirror_contents() 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( def test_buildcache_create_install(

View file

@ -861,7 +861,7 @@ set -g __fish_spack_optspecs_spack_buildcache_sync h/help manifest-glob=
complete -c spack -n '__fish_spack_using_command buildcache sync' -s h -l help -f -a help complete -c spack -n '__fish_spack_using_command buildcache sync' -s h -l help -f -a help
complete -c spack -n '__fish_spack_using_command buildcache sync' -s h -l help -d 'show this help message and exit' complete -c spack -n '__fish_spack_using_command buildcache sync' -s h -l help -d 'show this help message and exit'
complete -c spack -n '__fish_spack_using_command buildcache sync' -l manifest-glob -r -f -a manifest_glob complete -c spack -n '__fish_spack_using_command buildcache sync' -l manifest-glob -r -f -a manifest_glob
complete -c spack -n '__fish_spack_using_command buildcache sync' -l manifest-glob -r -d 'a quoted glob pattern identifying copy manifest files' complete -c spack -n '__fish_spack_using_command buildcache sync' -l manifest-glob -r -d 'a quoted glob pattern identifying CI rebuild manifest files'
# spack buildcache update-index # spack buildcache update-index
set -g __fish_spack_optspecs_spack_buildcache_update_index h/help k/keys set -g __fish_spack_optspecs_spack_buildcache_update_index h/help k/keys

View file

@ -204,7 +204,6 @@ def configure_args(self):
args.append("--disable-gpu") args.append("--disable-gpu")
if self.compiler.name == "gcc": if self.compiler.name == "gcc":
flags["CFLAGS"].append("-g") flags["CFLAGS"].append("-g")
flags["ICON_CFLAGS"].append("-O3") flags["ICON_CFLAGS"].append("-O3")
flags["ICON_BUNDLED_CFLAGS"].append("-O2") flags["ICON_BUNDLED_CFLAGS"].append("-O2")
@ -217,7 +216,6 @@ def configure_args(self):
) )
elif self.compiler.name in ["intel", "oneapi"]: elif self.compiler.name in ["intel", "oneapi"]:
args.append("--enable-intel-consistency") args.append("--enable-intel-consistency")
flags["CFLAGS"].extend(["-g", "-ftz", "-fma", "-ip", "-qno-opt-dynamic-align"]) flags["CFLAGS"].extend(["-g", "-ftz", "-fma", "-ip", "-qno-opt-dynamic-align"])
@ -254,7 +252,6 @@ def configure_args(self):
flags["ICON_ECRAD_FCFLAGS"].extend(["-qno-opt-dynamic-align", "-no-fma", "-fpe0"]) flags["ICON_ECRAD_FCFLAGS"].extend(["-qno-opt-dynamic-align", "-no-fma", "-fpe0"])
elif self.compiler.name == "nvhpc": elif self.compiler.name == "nvhpc":
flags["CFLAGS"].extend(["-g", "-O2"]) flags["CFLAGS"].extend(["-g", "-O2"])
flags["FCFLAGS"].extend( flags["FCFLAGS"].extend(
["-g", "-O2", "-Mrecursive", "-Mallocatable=03", "-Mstack_arrays"] ["-g", "-O2", "-Mrecursive", "-Mallocatable=03", "-Mstack_arrays"]