#!/usr/bin/python3 """ Copy files from a source to the tree Copies files obtained via a `source` to the tree. Multiple files or directories can be copied by specifying multiple entries in `paths`. If no paths are specified the whole contents of `source` is copied. The source and the target path for each individual path entry might optionally be specified via `from` and `to`, respectively; if no path is given for any of the two, the root `/` is assumed. Supported sources are currently: o `archive`: Fetch an archive via the org.osbuild.files source and extract it to a temporary directory. Currently only tar archives are supported. """ import json import os import sys import subprocess import tempfile import osbuild.sources SCHEMA = """ "additionalProperties": false, "definitions": { "source-archive": { "description": "Fetch an via org.osbuild.files and extract it", "type": "object", "required": ["type", "checksum"], "additionalProperties": false, "properties": { "type": { "type": "string", "description": "The type of the source, here 'archive'", "enum": ["archive"] }, "checksum": { "type": "string", "description": "The checksum of the archive to fetch" }, "strip-components": { "type": "number", "description": "Strip 'N' leading components from file names on extraction", "default": 1 } } } }, "properties": { "source": { "oneOf": [{ "$ref": "#/definitions/source-archive" }] }, "paths": { "description": "Array of items to copy", "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "from": { "type": "string", "description": "The source path", "default": "/" }, "to": { "type": "string", "description": "The destination path", "default": "/" } } } } } """ def get_archive(options, srcdir, workdir): checksum = options["checksum"] strip = options.get("strip-components", 1) source_path = os.path.join(srcdir, "org.osbuild.files") target = os.path.join(workdir, checksum) os.makedirs(target) # actually fetch the archive res = osbuild.sources.get("org.osbuild.files", [checksum]) tar = [ "tar", "--strip-components=" + str(strip), "-x", "-C", target, "-f", os.path.join(source_path, checksum) ] subprocess.run(tar, check=True) return target, res def main(tree, srcdir, options, workdir): source_options = options["source"] source_type = source_options["type"] paths = options.get("paths", [{}]) if source_type == "archive": source = get_archive else: raise ValueError(f"Unsupported source: {source_type}") # Fetch the requested data via the selected source source_path, _ = source(source_options, srcdir, workdir) for path in paths: src = path.get("from", "/") dst = path.get("to", "/") subprocess.run(["cp", "--reflink=auto", "-a", f"{source_path}{src}", f"{tree}{dst}"], check=True) if __name__ == '__main__': stage_args = json.load(sys.stdin) with tempfile.TemporaryDirectory(dir="/var/tmp") as _workdir: r = main(stage_args["tree"], stage_args["sources"], stage_args["options"], _workdir) sys.exit(r)