Skip to content
Snippets Groups Projects
Commit ab43ca9a authored by Eric Müller's avatar Eric Müller :mountain_bicyclist:
Browse files

draft: split out source cache fetcher and updater

parent 2a5acb94
No related branches found
No related tags found
No related merge requests found
Pipeline #57069 failed with stages
import argparse
import os
import pathlib
import subprocess
parser = argparse.ArgumentParser(
prog='fetch_cached_buildresults.py',
description='Downloading missing source files to a spack cache.',
epilog='...')
parser.add_argument(
"path_missing", type=pathlib.Path,
help="Location of the file listing the missing source files.")
parser.add_argument(
"specfiles", nargs="+",
help="Location of the file listing the missing source files.")
parser.add_argument(
"--remote-cache", type=str, required=(not (("HARBOR_HOST" in os.environ) and ("HARBOR_PROJECT" in os.environ))),
default=(("HARBOR_HOST" in os.environ) and ("HARBOR_PROJECT" in os.environ)) and
("{}/{}/build_cache".format(os.environ["HARBOR_HOST"], os.environ["HARBOR_PROJECT"])) or "",
help="Path or URL to remote cache (target).")
parser.add_argument(
"--remote-cache-type", type=str, choices=["oci"],
default="oci",
help="Type of the remote cache.")
parser.add_argument(
"--remote-cache-username", type=str,
default="HARBOR_USERNAME" in os.environ and
pathlib.Path(os.environ["HARBOR_USERNAME"]) or "",
help="Username for remote cache (if applicable)")
parser.add_argument(
"--remote-cache-password", type=str,
default="HARBOR_PASSWORD" in os.environ and
pathlib.Path(os.environ["HARBOR_PASSWORD"]) or None,
help="Password for remote cache (if applicable)")
parser.add_argument(
"--local-cache", type=str,
default="YASHCHIKI_CACHE_BUILD" in os.environ and
pathlib.Path(os.environ["YASHCHIKI_CACHE_BUILD"]) or
os.path.expanduser("~/.yashchiki/cache/"),
help="Path to local spack cache folder (build results).")
args = parser.parse_args()
local_cache = pathlib.Path(args.local_cache)
if not os.path.exists(args.local_cache):
print("Creating local build cache directory")
local_cache.mkdir(parents=True, exist_ok=False)
missing_packages = []
available_packages = []
cached_paths = []
cmd = ["oras", "repo", "tags"]
if args.remote_cache_username and args.remote_cache_password:
cmd.extend(["--username", args.remote_cache_username])
cmd.extend(["--password", args.remote_cache_password])
cmd.append(args.remote_cache)
try:
tags = subprocess.check_output(cmd)
tags = tags.decode("utf-8")
cached_paths = tags.split()
except subprocess.CalledProcessError as e:
print(f"Listing repo tags of \"{args.remote_cache}\" failed.")
for specfile in args.specfiles:
with open(specfile, "r") as fd:
fetch_paths = []
packages = {}
try:
my_spack_folder = os.environ["MY_SPACK_FOLDER"]
my_spack_python = os.environ["MY_SPACK_PYTHON"]
yashchiki_home = os.environ["YASHCHIKI_HOME"]
# FIXME: call python!
lines = subprocess.check_output(f"PATH={my_spack_folder}/bin:$PATH {my_spack_python} {yashchiki_home}/lib/yashchiki/specfile_storage_path_build.py {specfile}", shell=True)
lines = lines.decode("utf-8")
lines = lines.split("\n")
for line in lines:
if not line:
continue
elems = line.split()
packages[elems[0]] = elems[1:]
except subprocess.CalledProcessError as e:
print(f"Computing fetch buildresult paths failed:", str(e), e.output)
for package_dag_hash, fetch_paths in packages.items():
missing_paths = []
for fetch_path in fetch_paths:
basename = os.path.basename(fetch_path)
if basename in cached_paths:
cmd = ["oras", "pull"]
if args.remote_cache_username and args.remote_cache_password:
cmd.extend(["--username", args.remote_cache_username])
cmd.extend(["--password", args.remote_cache_password])
cmd.append(args.remote_cache + f":{basename}")
try:
subprocess.check_output(cmd, stderr=subprocess.STDOUT, cwd=local_cache)
except subprocess.CalledProcessError as e:
print(f"Pulling of \"{basename}\" from \"{args.remote_cache}\" failed.")
missing_paths.append(fetch_path)
else:
missing_paths.append(fetch_path)
package_missing = False
for missing_path in missing_paths:
if missing_path.endswith(".spack") or missing_path.endswith(".spec.json"):
package_missing = True
if package_missing:
missing_packages.append(f"{package_dag_hash} " + " ".join(missing_paths))
else:
available_packages.append(f"{package_dag_hash} " + " ".join(missing_paths))
print(len(missing_packages), "missing packages in remote buildresults cache.")
print(len(available_packages), "available packages in remote buildresults cache.")
if missing_packages:
with open(args.path_missing, "w") as fd:
fd.write("\n".join(missing_packages))
import argparse
import os
import pathlib
import subprocess
parser = argparse.ArgumentParser(
prog='fetch_cached_sources.py',
description='Downloading missing source files to a spack cache.',
epilog='...')
parser.add_argument(
"path_missing", type=pathlib.Path,
help="Location of the file listing the missing source files.")
parser.add_argument(
"specfiles", nargs="+",
help="Location of the file listing the missing source files.")
parser.add_argument(
"--remote-cache", type=str, required=(not (("HARBOR_HOST" in os.environ) and ("HARBOR_PROJECT" in os.environ))),
default=(("HARBOR_HOST" in os.environ) and ("HARBOR_PROJECT" in os.environ)) and
("{}/{}/source_cache".format(os.environ["HARBOR_HOST"], os.environ["HARBOR_PROJECT"])) or "",
help="Path or URL to remote cache (target).")
parser.add_argument(
"--remote-cache-type", type=str, choices=["oci"],
default="oci",
help="Type of the remote cache.")
parser.add_argument(
"--remote-cache-username", type=str,
default="HARBOR_USERNAME" in os.environ and
pathlib.Path(os.environ["HARBOR_USERNAME"]) or "",
help="Username for remote cache (if applicable)")
parser.add_argument(
"--remote-cache-password", type=str,
default="HARBOR_PASSWORD" in os.environ and
pathlib.Path(os.environ["HARBOR_PASSWORD"]) or None,
help="Password for remote cache (if applicable)")
parser.add_argument(
"--local-cache", type=str,
default="YASHCHIKI_CACHE_SOURCE" in os.environ and
pathlib.Path(os.environ["YASHCHIKI_CACHE_SOURCE"]) or
os.path.expanduser("~/.yashchiki/cache/"),
help="Path to local spack cache folder (source).")
args = parser.parse_args()
local_cache = pathlib.Path(args.local_cache)
if not os.path.exists(args.local_cache):
print("Creating local cache directory")
local_cache.mkdir(parents=True, exist_ok=False)
missing_paths = []
available_paths = []
cached_paths = []
cmd = ["oras", "repo", "tags"]
if args.remote_cache_username and args.remote_cache_password:
cmd.extend(["--username", args.remote_cache_username])
cmd.extend(["--password", args.remote_cache_password])
cmd.append(args.remote_cache)
try:
tags = subprocess.check_output(cmd)
tags = tags.decode("utf-8")
cached_paths = tags.split()
except subprocess.CalledProcessError as e:
print(f"Listing repo tags of \"{args.remote_cache}\" failed.")
for specfile in args.specfiles:
with open(specfile, "r") as fd:
fetch_paths = []
try:
my_spack_folder = os.environ["MY_SPACK_FOLDER"]
my_spack_python = os.environ["MY_SPACK_PYTHON"]
yashchiki_home = os.environ["YASHCHIKI_HOME"]
# FIXME: call python!
paths = subprocess.check_output(f"PATH={my_spack_folder}/bin:$PATH {my_spack_python} {yashchiki_home}/lib/yashchiki/specfile_storage_path.py {specfile}", shell=True)
paths = paths.decode("utf-8")
fetch_paths = paths.split()
except subprocess.CalledProcessError as e:
print(f"Computing fetch storage paths failed for {specfile}.")
continue
for fetch_path in fetch_paths:
basename = os.path.basename(fetch_path)
if basename in cached_paths:
cmd = ["oras", "pull"]
if args.remote_cache_username and args.remote_cache_password:
cmd.extend(["--username", args.remote_cache_username])
cmd.extend(["--password", args.remote_cache_password])
cmd.append(args.remote_cache + f":{basename}")
try:
subprocess.check_output(cmd, stderr=subprocess.STDOUT, cwd=local_cache)
except subprocess.CalledProcessError as e:
print(f"Pulling of \"{basename}\" from \"{args.remote_cache}\" failed.")
missing_paths.append(fetch_path)
available_paths.append(fetch_path)
else:
missing_paths.append(fetch_path)
print(len(missing_paths), "missing files in remote source cache.")
print(len(available_paths), "available files in remote source cache.")
if missing_paths:
with open(args.path_missing, "w") as fd:
fd.write("\n".join(missing_paths))
......@@ -2,7 +2,7 @@ import argparse
from collections.abc import Iterable
import pathlib
import ruamel.yaml as yaml
from spack import spec
import spack
import spack.binary_distribution as bindist
parser = argparse.ArgumentParser(
......@@ -22,17 +22,13 @@ with open(args.path_specfile, "r") as fd:
to_be_fetched = []
for rspec in data:
s = spec.Spec.from_dict(rspec)
s = spack.spec.Spec.from_dict(rspec)
if not isinstance(s, Iterable):
s = [s]
maybe_to_be_fetched = spack.traverse.traverse_nodes(s, key=spack.traverse.by_dag_hash)
for spec in maybe_to_be_fetched:
build_cache_paths = [
bindist.tarball_path_name(spec, ".spack"),
bindist.tarball_name(spec, ".spec.json.sig"),
bindist.tarball_name(spec, ".spec.json"),
bindist.tarball_name(spec, ".spec.yaml"),
]
print("\n".join(build_cache_paths))
if spec.installed:
continue
print(spec.dag_hash())
......@@ -3,7 +3,6 @@ from collections.abc import Iterable
import pathlib
import ruamel.yaml as yaml
import spack
from spack import spec
parser = argparse.ArgumentParser(
prog='specfile_storage_path.py',
......@@ -22,7 +21,7 @@ with open(args.path_specfile, "r") as fd:
to_be_fetched = []
for rspec in data:
s = spec.Spec.from_dict(rspec)
s = spack.spec.Spec.from_dict(rspec)
if not isinstance(s, Iterable):
s = [s]
......@@ -35,4 +34,3 @@ for rspec in data:
pkg = ss.package
to_be_fetched.append(pkg)
print(spack.mirror.mirror_archive_paths(pkg.fetcher, 'whatever').storage_path)
print("")
import argparse
from collections.abc import Iterable
import pathlib
import ruamel.yaml as yaml
import spack
import spack.binary_distribution as bindist
parser = argparse.ArgumentParser(
prog='specfile_dag_hash.py',
description='Extracting DAG hashes from a given specfile',
epilog='...')
parser.add_argument(
"path_specfile", type=pathlib.Path,
help="Location of the specfile to parse")
args = parser.parse_args()
with open(args.path_specfile, "r") as fd:
file_content = fd.read()
data = list(yaml.safe_load_all(file_content))
to_be_fetched = []
for rspec in data:
s = spack.spec.Spec.from_dict(rspec)
if not isinstance(s, Iterable):
s = [s]
maybe_to_be_fetched = spack.traverse.traverse_nodes(s, key=spack.traverse.by_dag_hash)
for spec in maybe_to_be_fetched:
if spec.installed:
continue
build_cache_paths = [
bindist.tarball_path_name(spec, ".spack"),
bindist.tarball_name(spec, ".spec.json.sig"),
bindist.tarball_name(spec, ".spec.json"),
bindist.tarball_name(spec, ".spec.yaml"),
]
print(spec.dag_hash(), " ".join(build_cache_paths))
import argparse
import glob
import os
import pathlib
import subprocess
import sys
parser = argparse.ArgumentParser(
prog='update_cached_buildresults.py',
description='Uploading previously missing build results to a cache.',
epilog='...')
parser.add_argument(
"path_missing", type=pathlib.Path,
help="Location of the file listing the missing source files.")
parser.add_argument(
"--remote-cache", type=str, required=(not (("HARBOR_HOST" in os.environ) and ("HARBOR_PROJECT" in os.environ))),
default=(("HARBOR_HOST" in os.environ) and ("HARBOR_PROJECT" in os.environ)) and
("{}/{}/build_cache".format(os.environ["HARBOR_HOST"], os.environ["HARBOR_PROJECT"])) or "",
help="Path or URL to remote cache (target).")
parser.add_argument(
"--remote-cache-type", type=str, choices=["oci"],
default="oci",
help="Type of the remote cache.")
parser.add_argument(
"--remote-cache-username", type=str, required=(not "HARBOR_USERNAME" in os.environ),
default="HARBOR_USERNAME" in os.environ and
pathlib.Path(os.environ["HARBOR_USERNAME"]) or "",
help="Username for remote cache (if applicable)")
parser.add_argument(
"--remote-cache-password", type=str, required=(not "HARBOR_PASSWORD" in os.environ),
default="HARBOR_PASSWORD" in os.environ and
pathlib.Path(os.environ["HARBOR_PASSWORD"]) or None,
help="Password for remote cache (if applicable)")
parser.add_argument(
"--local-cache", type=str,
default="YASHCHIKI_CACHE_BUILD" in os.environ and
pathlib.Path(os.environ["YASHCHIKI_CACHE_BUILD"]) or
os.path.expanduser("~/.yashchiki/cache/"),
help="Path to local spack cache folder (build results).")
args = parser.parse_args()
if not os.path.exists(args.path_missing):
print("File w/ missing package information is not available")
sys.exit(0)
packages = {}
with open(args.path_missing, "r") as fd:
lines = fd.readlines()
for line in lines:
elems = line.split()
packages[elems[0]] = elems[1:]
for package_dag_hash, paths in packages.items():
basenames = [ os.path.basename(path) for path in paths]
for path, basename in zip(paths, basenames):
full_path = pathlib.Path(str(args.local_cache) + "/" + path)
if ((str(full_path).endswith(".spack") or str(full_path).endswith(".spec.json")) and not full_path.exists()):
print(f"Missing local cache entry for \"{full_path}\"")
continue
if not full_path.exists():
# we don't care about other file endings for now
continue
cmd = ("oras", "push",
"--username", args.remote_cache_username,
"--password", args.remote_cache_password,
f"--annotation=path={path}",
f"{args.remote_cache}:{basename}",
f"{path}")
try:
subprocess.check_output(cmd, cwd=args.local_cache)
except subprocess.CalledProcessError as e:
print(f"Uploading of \"{path}\" to \"{args.remote_cache}:{basename}\" failed.")
import argparse
import os
import pathlib
import subprocess
import sys
parser = argparse.ArgumentParser(
prog='update_cached_sources.py',
description='Uploading previously missing source files to a cache.',
epilog='...')
parser.add_argument(
"path_missing", type=pathlib.Path,
help="Location of the file listing the missing source files.")
parser.add_argument(
"--remote-cache", type=str, required=(not (("HARBOR_HOST" in os.environ) and ("HARBOR_PROJECT" in os.environ))),
default=(("HARBOR_HOST" in os.environ) and ("HARBOR_PROJECT" in os.environ)) and
("{}/{}/source_cache".format(os.environ["HARBOR_HOST"], os.environ["HARBOR_PROJECT"])) or "",
help="Path or URL to remote cache (target).")
parser.add_argument(
"--remote-cache-type", type=str, choices=["oci"],
default="oci",
help="Type of the remote cache.")
parser.add_argument(
"--remote-cache-username", type=str, required=(not "HARBOR_USERNAME" in os.environ),
default="HARBOR_USERNAME" in os.environ and
pathlib.Path(os.environ["HARBOR_USERNAME"]) or "",
help="Username for remote cache (if applicable)")
parser.add_argument(
"--remote-cache-password", type=str, required=(not "HARBOR_PASSWORD" in os.environ),
default="HARBOR_PASSWORD" in os.environ and
pathlib.Path(os.environ["HARBOR_PASSWORD"]) or None,
help="Password for remote cache (if applicable)")
parser.add_argument(
"--local-cache", type=str,
default="YASHCHIKI_CACHE_SOURCE" in os.environ and
pathlib.Path(os.environ["YASHCHIKI_CACHE_SOURCE"]) or
os.path.expanduser("~/.yashchiki/cache/"),
help="Path to local spack cache folder (source).")
args = parser.parse_args()
if not os.path.exists(args.path_missing):
print("File w/ missing source path information is not available")
sys.exit(0)
with open(args.path_missing, "r") as fd:
missing_file_paths = fd.readlines()
for path in missing_file_paths:
stripped_path = path.rstrip()
basename = os.path.basename(stripped_path)
full_path = pathlib.Path(str(args.local_cache) + "/" + stripped_path)
cmd = ("oras", "push",
"--username", args.remote_cache_username,
"--password", args.remote_cache_password,
f"--annotation=path={stripped_path}",
f"{args.remote_cache}:{basename}",
f"{stripped_path}")
try:
subprocess.check_output(cmd, cwd=args.local_cache)
except subprocess.CalledProcessError as e:
print(f"Uploading of \"{stripped_path}\" to \"{args.remote_cache}:{basename}\" failed.")
......@@ -3,26 +3,24 @@
set -euo pipefail
shopt -s inherit_errexit
# TODO:
# expects active environment
(
specfile="./env_specfile.yaml";
# TODO: expects loaded env
spack spec -y > "${specfile}"
) && echo "done." || (echo "FAILED."; exit 1)
#set -x
head "./env_specfile.yaml"
fetch_specfiles=()
fetch_specfiles_cache=()
# spack fetch doesn't like proper multi-doc separators (---)
# FIXME: add --quiet; replace -z by long version --elide-empty-files
csplit -z --prefix=env_specfile_split --suffix-format=%02d.yaml ./env_specfile.yaml /---/ '{*}'
ls #FIXME
for split_specfile in ./env_specfile_split*.yaml; do
fetch_specfiles+=( ${split_specfile} )
done
# multi-doc style for "normal" yaml parsing
fetch_specfiles_cache+=( "./env_specfile.yaml" )
echo "Path to source cache: ${YASHCHIKI_CACHE_SOURCE}"
mkdir -p ${YASHCHIKI_CACHE_SOURCE} || true
missing_paths=()
if [ -n "${CACHE_SOURCE_TYPE:-}" ]; then
......@@ -30,18 +28,41 @@ if [ -n "${CACHE_SOURCE_TYPE:-}" ]; then
echo "Unknown cache type"
exit 1
fi
cached_paths=$(oras repo tags ${HARBOR_HOST}/${HARBOR_PROJECT}/source_cache 2>&1)
if [ $? -ne 0 ]; then
echo "ERROR: OCI repo query failed."
fi
echo "cached_paths: \"${cached_paths}\""
for fetch_specfile in "${fetch_specfiles_cache[@]}"; do
raw_paths=$(PATH=${MY_SPACK_FOLDER}/bin:$PATH ${MY_SPACK_PYTHON} ${YASHCHIKI_HOME}/lib/yashchiki/specfile_storage_path.py ${fetch_specfile})
raw_paths=$(PATH=${MY_SPACK_FOLDER}/bin:$PATH ${MY_SPACK_PYTHON} ${YASHCHIKI_HOME}/lib/yashchiki/specfile_storage_path.py ${fetch_specfile} 2>/dev/null)
echo "raw_paths: \"$raw_paths\""
fetch_paths=(${raw_paths})
pushd ${YASHCHIKI_CACHES_ROOT}/download_cache
echo "fetch_paths: \"${fetch_paths[@]}\""
pushd ${YASHCHIKI_CACHE_SOURCE} >/dev/null
for fetch_path in "${fetch_paths[@]}"; do
# FIXME: gitlab env vars!
oras pull ${HARBOR_HOST}/${HARBOR_PROJECT}/source_cache:$(basename ${fetch_path}) 2>&1 && ret=$? || ret=$?
if [ ${ret} -ne 0 ]; then
if [ -z "${fetch_path}" ]; then
echo "ERROR: fetch_path is empty: \"${fetch_path}\""
continue
else
echo "fetch_path is \"${fetch_path}\""
fi
if [[ " ${cached_paths[*]} " =~ " $(basename ${fetch_path}) " ]]; then
echo "found \"$(basename ${fetch_path})\" in cached_paths"
oras pull ${HARBOR_HOST}/${HARBOR_PROJECT}/source_cache:$(basename ${fetch_path}) >/dev/null 2>&1 && ret=$? || ret=$?
if [ ${ret} -ne 0 ]; then
echo "Fetching failed."
missing_paths+=( "${fetch_path}" )
else
echo "Fetched: \"${fetch_path}\""
fi
else
echo "Did not find \"${fetch_path}\" in cached_paths"
missing_paths+=( "${fetch_path}" )
fi
done
popd
popd >/dev/null
done
echo "Missing source cache entries: ${missing_paths[@]}"
fi
printf "%s\n" "${missing_paths[@]}" >missing_paths.dat
#!/bin/bash
set -euo pipefail
shopt -s inherit_errexit
#head missing_paths.dat
readarray -t missing_paths <missing_paths.dat
#echo "\"${missing_paths[@]}\""
if [ -n "${CACHE_SOURCE_TYPE:-}" ]; then
if [ ${CACHE_SOURCE_TYPE} != "oci" ]; then
echo "Unknown cache type"
exit 1
fi
pushd ${YASHCHIKI_CACHE_SOURCE} >/dev/null
if [ -n "${missing_paths}" ]; then
for missing_path in "${missing_paths[@]}"; do
if [ -z "${missing_path}" ]; then
echo "ERROR: missing_path is empty."
continue
fi
if [ ! -e "${missing_path}" ]; then
echo "ERROR: missing_path is empty."
continue
fi
echo "Uploading to OCI cache: ${missing_path}"
oras push \
--username ${HARBOR_USERNAME} \
--password ${HARBOR_PASSWORD} \
--annotation="path=${missing_path}" \
${HARBOR_HOST}/${HARBOR_PROJECT}/source_cache:$(basename ${missing_path}) \
${missing_path} 2>&1 && ret=$? || ret=$?
if [ ${ret} -ne 0 ]; then
echo "Uploading of \"${missing_path}\" to OCI cache failed."
fi
done
fi
popd >/dev/null
fi
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment