Currently stdin is taken to be the pipeline to be built, this allows
it to be instead a map containing the suorces and the pipeline.
We would imagine passing around the sources and pipeline together, so
this just makes the behavior of osbuild more closely match the intended
use and semantics of the sources configuration.
This keeps backwards compatibility for now, but that may be dropped as
soon as osbuild-composer no longer relies on the old behavior.
Disable too-many-{branches,statements} pylint warnings in __main__.py.
These do not seem helpful, but could be reenabled if we drop some
options in the future.
Signed-off-by: Tom Gundersen <teg@jklm.no>
121 lines
3.9 KiB
Python
Executable file
121 lines
3.9 KiB
Python
Executable file
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
import osbuild
|
|
|
|
|
|
RESET = "\033[0m"
|
|
BOLD = "\033[1m"
|
|
RED = "\033[31m"
|
|
|
|
|
|
def mark_checkpoints(pipeline, checkpoints):
|
|
points = set(checkpoints)
|
|
def mark_stage(stage):
|
|
for c in points:
|
|
if stage.id == c:
|
|
stage.checkpoint = True
|
|
points.remove(c)
|
|
return
|
|
|
|
def mark_pipeline(pl):
|
|
for stage in pl.stages:
|
|
mark_stage(stage)
|
|
if pl.build:
|
|
mark_pipeline(pl.build)
|
|
|
|
mark_pipeline(pipeline)
|
|
return points
|
|
|
|
|
|
# pylint: disable=too-many-branches
|
|
# pylint: disable=too-many-statements
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Build operating system images")
|
|
parser.add_argument("pipeline_path", metavar="PIPELINE",
|
|
help="json file containing the pipeline that should be built, or a '-' to read from stdin")
|
|
parser.add_argument("--build-env", metavar="ENV", type=os.path.abspath,
|
|
help="json file containing a description of the build environment")
|
|
parser.add_argument("--store", metavar="DIRECTORY", type=os.path.abspath,
|
|
default=".osbuild",
|
|
help="the directory where intermediary os trees are stored")
|
|
parser.add_argument("--sources", metavar="SOURCES", type=os.path.abspath,
|
|
help="json file containing a dictionary of source configuration")
|
|
parser.add_argument("--secrets", metavar="SECRETS", type=os.path.abspath,
|
|
help="json file containing a dictionary of secrets that are passed to sources")
|
|
parser.add_argument("-l", "--libdir", metavar="DIRECTORY", type=os.path.abspath,
|
|
help="the directory containing stages, assemblers, and the osbuild library")
|
|
parser.add_argument("--checkpoint", metavar="CHECKPOINT", action="append", type=str, default=None,
|
|
help="stage to commit to the object store during build (can be passed multiple times)")
|
|
parser.add_argument("--json", action="store_true",
|
|
help="output results in JSON format")
|
|
args = parser.parse_args()
|
|
|
|
if args.pipeline_path == "-":
|
|
f = sys.stdin
|
|
else:
|
|
f = open(args.pipeline_path)
|
|
manifest = json.load(f)
|
|
f.close()
|
|
|
|
if "pipeline" in manifest:
|
|
pipeline = manifest["pipeline"]
|
|
sources_options = manifest.get("sources", {})
|
|
else:
|
|
# backwards compatibility
|
|
pipeline = manifest
|
|
sources_options = {}
|
|
|
|
if args.sources:
|
|
with open(args.sources) as f:
|
|
sources_options = json.load(f)
|
|
|
|
pipeline = osbuild.load(pipeline, sources_options)
|
|
|
|
if args.build_env:
|
|
with open(args.build_env) as f:
|
|
build_pipeline, runner = osbuild.load_build(json.load(f), sources_options)
|
|
pipeline.prepend_build_env(build_pipeline, runner)
|
|
|
|
secrets = {}
|
|
if args.secrets:
|
|
with open(args.secrets) as f:
|
|
secrets = json.load(f)
|
|
|
|
if args.checkpoint:
|
|
missed = mark_checkpoints(pipeline, args.checkpoint)
|
|
if missed:
|
|
for checkpoint in missed:
|
|
print(f"Checkpoint {BOLD}{checkpoint}{RESET} not found!")
|
|
print(f"{RESET}{BOLD}{RED}Failed{RESET}")
|
|
return 1
|
|
|
|
try:
|
|
r = pipeline.run(
|
|
args.store,
|
|
interactive=not args.json,
|
|
libdir=args.libdir,
|
|
secrets=secrets
|
|
)
|
|
except KeyboardInterrupt:
|
|
print()
|
|
print(f"{RESET}{BOLD}{RED}Aborted{RESET}")
|
|
return 130
|
|
|
|
if args.json:
|
|
json.dump(r, sys.stdout)
|
|
sys.stdout.write("\n")
|
|
else:
|
|
if r["success"]:
|
|
print("tree id:", pipeline.tree_id)
|
|
print("output id:", pipeline.output_id)
|
|
else:
|
|
print()
|
|
print(f"{RESET}{BOLD}{RED}Failed{RESET}")
|
|
|
|
return 0 if r["success"] else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|