summaryrefslogtreecommitdiff
path: root/mdbp/streamapi.py
diff options
context:
space:
mode:
Diffstat (limited to 'mdbp/streamapi.py')
-rw-r--r--mdbp/streamapi.py73
1 files changed, 73 insertions, 0 deletions
diff --git a/mdbp/streamapi.py b/mdbp/streamapi.py
new file mode 100644
index 0000000..8f67366
--- /dev/null
+++ b/mdbp/streamapi.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: MIT
+"""mdbp frontend without filesystem interaction. It basically wraps another
+backend and is used as frontend from the ssh backend on the remote side.
+Differences to the regular backend API:
+ * It expects an uncompressed tar file on stdin. The first member must be named
+ "build.json". Any other members must be regular files. The build.json file
+ should lack the .output.directory and if an .input.dscpath is given, it
+ should not contain any slashes.
+ * The build log is issued on stderr instead of stdout.
+ * All the requested artifacts are emitted as a tar stream on stdout.
+"""
+
+import argparse
+import json
+import pathlib
+import subprocess
+import sys
+import tarfile
+import tempfile
+
+from .common import json_load, buildjson_validate, buildjson_patch_relative, \
+ tar_add
+
+def main() -> None:
+ """Entry point for mdbp-streamapi wrapper"""
+ parser = argparse.ArgumentParser()
+ parser.add_argument("command", nargs=argparse.REMAINDER)
+ args = parser.parse_args()
+ if not args.command:
+ parser.error("missing command")
+
+ with tempfile.TemporaryDirectory() as tdirname:
+ indir = pathlib.Path(tdirname) / "input"
+ outdir = pathlib.Path(tdirname) / "output"
+ indir.mkdir()
+ outdir.mkdir()
+ with tarfile.open(fileobj=sys.stdin.buffer, mode="r|") as intar:
+ seenjson = False
+ for member in intar:
+ if "/" in member.name or not member.isfile():
+ raise ValueError("expected flat tar as input")
+ if seenjson:
+ intar.extract(member, indir, set_attrs=False)
+ continue
+ if member.name != "build.json":
+ raise ValueError("first input member must be build.json")
+ jsonfileobj = intar.extractfile(member)
+ # We already checked .isfile(), but mypy doesn't know.
+ assert jsonfileobj is not None
+ build = json_load(jsonfileobj)
+ build["output"]["directory"] = str(outdir)
+ buildjson_validate(build)
+ buildjson_patch_relative(build, indir)
+ (indir / "build.json").write_text(json.dumps(build))
+ seenjson = True
+ if not seenjson:
+ raise ValueError("input is an empty tar archive")
+ proc = subprocess.Popen([*args.command, str(indir / "build.json")],
+ stdout=sys.stderr
+ if build["output"].get("log", True)
+ else subprocess.DEVNULL,
+ stderr=None if build["output"].get("log", True)
+ else subprocess.DEVNULL)
+ code = proc.wait()
+ if code != 0:
+ sys.exit(code)
+ with tarfile.open(fileobj=sys.stdout.buffer, mode="w|") as outtar:
+ for elem in outdir.iterdir():
+ tar_add(outtar, elem)
+
+if __name__ == "__main__":
+ main()