1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
#!/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.source_package_path 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 fnmatch
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")
with 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
) as proc:
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():
if any(fnmatch.fnmatchcase(elem.name, pattern)
for pattern in build["output"].get("artifacts", ["*"])):
tar_add(outtar, elem)
if __name__ == "__main__":
main()
|