diff --git a/src/cmd-buildprep b/src/cmd-buildprep index c8b1c48f68..9f4335bf53 100755 --- a/src/cmd-buildprep +++ b/src/cmd-buildprep @@ -16,7 +16,7 @@ from tenacity import retry, retry_if_exception_type sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -from cosalib.builds import Builds +from cosalib.builds import Builds, BUILDFILES from cosalib.cmdlib import load_json, rm_allow_noent, retry_stop, retry_s3_exception, retry_callback # noqa: E402 retry_requests_exception = (retry_if_exception_type(requests.Timeout) | @@ -39,7 +39,22 @@ def main(): builds = None if fetcher.exists('builds.json'): - fetcher.fetch_json('builds.json') + if not args.refresh: + if os.path.isfile(BUILDFILES['sourcedata']): + # If we have local builds, don't overwrite that by default. + if subprocess.call(['cmp', BUILDFILES['sourcedata'], BUILDFILES['list']], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) != 0: + raise SystemExit(f"{BUILDFILES['list']} modified locally, run with --refresh") + fetcher.fetch_json('builds.json') + else: + fetcher.fetch('builds.json', dest=BUILDFILES['sourcedata']) + print(f"Updated {BUILDFILES['sourcedata']}") + return + # Record the origin and original state + with open(BUILDFILES['sourceurl'], 'w') as f: + f.write(args.url + '\n') + subprocess.check_call(['cp', '-pf', '--reflink=auto', BUILDFILES['list'], BUILDFILES['sourcedata']]) builds = Builds() if not builds or builds.is_empty(): @@ -87,6 +102,8 @@ def parse_args(): help="URL from which to fetch metadata") parser.add_argument("--ostree", action='store_true', help="Also download full OSTree commit") + parser.add_argument("--refresh", action='store_true', + help="Assuming local changes, only update {BUILDFILES['sourcedata']}") return parser.parse_args() diff --git a/src/cmd-buildupload b/src/cmd-buildupload index 34a6c242ff..9a31302499 100755 --- a/src/cmd-buildupload +++ b/src/cmd-buildupload @@ -8,6 +8,7 @@ import json import os import sys import tempfile +import subprocess import boto3 from botocore.exceptions import ClientError from tenacity import retry @@ -20,7 +21,7 @@ CACHE_MAX_AGE_ARTIFACT = 60 * 60 * 24 * 365 # set metadata caching to 5m CACHE_MAX_AGE_METADATA = 60 * 5 -from cosalib.builds import Builds +from cosalib.builds import Builds, BUILDFILES from cosalib.cmdlib import load_json, retry_stop, retry_s3_exception, retry_callback # noqa: E402 @@ -56,6 +57,9 @@ def parse_args(): def cmd_upload_s3(args): bucket, prefix = args.url.split('/', 1) builds = Builds() + # This can't be an error for backcompat reasons, but let's print something + if not os.path.isfile(BUILDFILES['sourceurl']): + print(f"NOTICE: No {BUILDFILES['sourceurl']} file; uploading without buildprep?") if args.build == 'latest': args.build = builds.get_latest() print(f"Targeting build: {args.build}") @@ -72,8 +76,12 @@ def cmd_upload_s3(args): s3_copy(f'builds/{args.build}/{f}', bucket, f'{prefix}/{args.build}/{f}', CACHE_MAX_AGE_METADATA, args.acl) if not args.skip_builds_json: - s3_copy('builds/builds.json', bucket, f'{prefix}/builds.json', + s3_copy(BUILDFILES['list'], bucket, f'{prefix}/builds.json', CACHE_MAX_AGE_METADATA, args.acl, extra_args={}, dry_run=args.dry_run) + # And now update our cached copy to note we've successfully sync'd. + with open(BUILDFILES['sourceurl'], 'w') as f: + f.write(f"s3://{bucket}/{prefix}\n") + subprocess.check_call(['cp', '-pf', '--reflink=auto', BUILDFILES['list'], BUILDFILES['sourcedata']]) def s3_upload_build(args, builddir, bucket, prefix): diff --git a/src/cosalib/builds.py b/src/cosalib/builds.py index ca98b296ff..e6c1be7c69 100644 --- a/src/cosalib/builds.py +++ b/src/cosalib/builds.py @@ -16,11 +16,20 @@ load_json, write_json) +BUILDFILES = { + # The list of builds. + 'list': 'builds/builds.json', + # This copy of builds.json tracks what we last downloaded from the source + 'sourcedata': 'tmp/builds-source.json', + # This tracks the URL passed to buildprep + 'sourceurl': 'tmp/builds-source.txt', +} + class Builds: # pragma: nocover def __init__(self, workdir=None): self._workdir = workdir - self._fn = self._path("builds/builds.json") + self._fn = self._path(BUILDFILES['list']) if not os.path.isdir(self._path("builds")): raise Exception("No builds/ dir found!") elif os.path.isfile(self._fn):