debian-forge/sources/org.osbuild.ostree
Christian Kellner ee9df25a02 sources/ostree: ability to only pull commits
Split the internal logic into two parts: 1) fetching the commit
into the internal cache repo and then 2) exporting that commit,
i.e. a local pull from the cache repo to the output directory.
If no `output` directory was specified, only fetch the commit,
do not attempt to export it.
NB: this commit changes at what point the gpg verification is
done. Previously the check was on export. Now, we are checking
the signature on import only. The export step will be replaced
by an ostree `Input` that will have the ability to verify
commits a second time.
2021-02-06 12:04:30 +01:00

142 lines
3.7 KiB
Python
Executable file

#!/usr/bin/python3
"""Fetch OSTree commits from an repository
Uses ostree to pull specific commits from (remote) repositories
at the provided `url`. Can verify the commit, if one or more
gpg keys are provided via `gpgkeys`.
"""
import json
import os
import sys
import subprocess
import uuid
SCHEMA = """
"additionalProperties": false,
"properties": {
"commits": {
"description": "The commits to fetch indexed their checksum",
"type": "object",
"additionalProperties": false,
"patternProperties": {
"[0-9a-f]{5,64}": {
"type": "object",
"additionalProperties": false,
"required": ["remote"],
"properties": {
"remote": {
"type": "object",
"additionalProperties": false,
"required": ["url"],
"properties": {
"url": {
"type": "string",
"description": "URL of the repository."
},
"gpgkeys": {
"type": "array",
"items": {
"type": "string",
"description": "GPG keys to verify the commits"
}
}
}
}
}
}
}
}
}
"""
def ostree(*args, _input=None, **kwargs):
args = list(args) + [f'--{k}={v}' for k, v in kwargs.items()]
print("ostree " + " ".join(args), file=sys.stderr)
subprocess.run(["ostree"] + args,
encoding="utf-8",
stdout=sys.stderr,
input=_input,
check=True)
def download(commits, checksums, cache):
# Prepare the cache and the output repo
repo_cache = os.path.join(cache, "repo")
ostree("init", mode="archive", repo=repo_cache)
# Make sure the cache repository uses locks to protect the metadata during
# shared access. This is the default since `2018.5`, but lets document this
# explicitly here.
ostree("config", "set", "repo.locking", "true", repo=repo_cache)
for commit in checksums:
remote = commits[commit]["remote"]
url = remote["url"]
gpg = remote.get("gpgkeys", [])
uid = str(uuid.uuid4())
verify_args = []
if not gpg:
verify_args = ["--no-gpg-verify"]
ostree("remote", "add",
uid, url,
*verify_args,
repo=repo_cache)
for key in gpg:
ostree("remote", "gpg-import", "--stdin", uid,
repo=repo_cache, _input=key)
# Transfer the commit: remote → cache
print(f"pulling {commit}", file=sys.stderr)
ostree("pull", uid, commit, repo=repo_cache)
# Remove the temporary remotes again
ostree("remote", "delete", uid,
repo=repo_cache)
def export(checksums, cache, output):
repo_cache = os.path.join(cache, "repo")
repo_out = os.path.join(output, "repo")
ostree("init", mode="archive", repo=repo_out)
for commit in checksums:
# Transfer the commit: remote → cache
print(f"exporting {commit}", file=sys.stderr)
ostree("pull-local", repo_cache, commit,
repo=repo_out)
json.dump({}, sys.stdout)
def main(options, checksums, cache, output):
commits = options["commits"]
os.makedirs(cache, exist_ok=True)
download(commits, checksums, cache)
if not output:
json.dump({}, sys.stdout)
return 0
os.makedirs(output, exist_ok=True)
export(checksums, cache, output)
return 0
if __name__ == '__main__':
source_args = json.load(sys.stdin)
r = main(source_args["options"],
source_args["checksums"],
source_args["cache"],
source_args["output"])
sys.exit(r)