blob: c46c3cd07f0859bc597fd0996b08df683dca517f [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
## Roll a new compiler (really, any CIPD package) into Fuchsia
## Usage: See `fx roll-compiler --help`
import argparse
import json
import os
import subprocess
import sys
import tempfile
FUCHSIA_DIR = os.path.normpath(
os.path.join(__file__, os.pardir, os.pardir, os.pardir, os.pardir)
)
JIRI_BIN = os.path.join(FUCHSIA_DIR, ".jiri_root", "bin")
CIPD = os.path.join(JIRI_BIN, "cipd")
JIRI = os.path.join(JIRI_BIN, "jiri")
def CallCipd(args):
with tempfile.NamedTemporaryFile(mode="r", suffix=".json") as f:
cmd = [CIPD] + args + ["-json-output", f.name]
with open(os.devnull, "w") as devnull:
subprocess.check_call(cmd, stdout=devnull)
return json.load(f)["result"]
def ResolvePackage(package, version):
return CallCipd(["describe", package, "-version", version])
def main():
parser = argparse.ArgumentParser(
"fx roll-compiler",
description="Roll a new compiler into Fuchsia",
epilog="""
With multiple --package switches, all packages must resolve successfully
before commands are run for any package.
""",
)
parser.add_argument(
"version", nargs="?", default="latest", help="CIPD version to promote"
)
parser.add_argument("--package", "-p", action="append", help="CIPD package name")
parser.add_argument(
"--manifest",
default=os.path.join(FUCHSIA_DIR, "integration", "fuchsia", "toolchain"),
help="Jiri manifest file to edit",
)
parser.add_argument("--tag", default="git_revision", help="CIPD tag to publish")
parser.add_argument(
"--platforms",
action="append",
metavar="PLATFORM",
help="CIPD platforms with matching packages",
)
parser.add_argument(
"--dry-run",
action="store_const",
default=False,
const=True,
help="Only print final command but do not run it",
)
args = parser.parse_args()
if not args.platforms:
args.platforms = ["linux-arm64", "linux-amd64", "mac-amd64"]
if not args.package:
args.package = ["clang"]
packages = [
package if "/" in package else "fuchsia/third_party/" + package
for package in args.package
]
def PackageTag(package):
[tag] = [
tag["tag"]
for tag in package["tags"]
if tag["tag"].startswith(args.tag + ":")
]
return tag
all_packages = [
ResolvePackage("%s/%s" % (package, platform), args.version)
for platform in args.platforms
for package in packages
]
package_tags = {
package["pin"]["package"]: PackageTag(package) for package in all_packages
}
tag_set = set(t for t in package_tags.values())
if len(tag_set) != 1:
sys.stderr.write(
f"Not all packages have matching {args.tag} tags at version {args.version}:\n")
json.dump(package_tags, sys.stderr, sort_keys=True, indent=4)
sys.stderr.write("\n")
sys.exit(1)
[tag] = tag_set
print(f"Resolved {args.version} to {tag}")
cmd = [JIRI, "edit"]
for package in packages:
cmd += ["-package", "%s/${platform}=%s" % (package, tag)]
cmd.append(args.manifest)
def DryRun(args):
print(args)
run = DryRun if args.dry_run else subprocess.check_call
run(cmd)
run([os.path.join(FUCHSIA_DIR, "integration", "update-lockfiles.sh")])
return 0
if __name__ == "__main__":
sys.exit(main())