Blame assemblers/org.osbuild.ostree.commit

Packit Service 863627
#!/usr/bin/python3
Packit Service 863627
"""
Packit Service 863627
Assemble a file system tree into a ostree commit
Packit Service 863627
Packit Service 863627
Takes a file system tree that is already conforming to the ostree
Packit Service 863627
system layout[1] and commits it to an archive repository.
Packit Service 863627
Packit Service 863627
The repository is located at the `/repo` directory and additional
Packit Service 863627
metadata is stored in `/compose.json` which contains the commit
Packit Service 863627
compose information.
Packit Service 863627
Packit Service 863627
Alternatively, if the `tar` option is supplied, the repository and
Packit Service 863627
the `compose.json` will be archived in a file named via the
Packit Service 863627
`tar.filename` option. This supports auto-compression via the file
Packit Service 863627
extension (see the tar man page). Requires the `tar` command to be
Packit Service 863627
in the build root.
Packit Service 863627
Packit Service 863627
[1] https://ostree.readthedocs.io/en/stable/manual/adapting-existing/
Packit Service 863627
"""
Packit Service 863627
Packit Service 863627
Packit Service 863627
import json
Packit Service 863627
import os
Packit Service 863627
import subprocess
Packit Service 863627
import sys
Packit Service 863627
import tempfile
Packit Service 863627
Packit Service 863627
from osbuild.util import ostree
Packit Service 863627
Packit Service 863627
Packit Service 863627
SCHEMA = """
Packit Service 863627
"additionalProperties": false,
Packit Service 863627
"required": ["ref"],
Packit Service 863627
"properties": {
Packit Service 863627
  "ref": {
Packit Service 863627
    "description": "OStree ref to create for the commit",
Packit Service 863627
    "type": "string",
Packit Service 863627
    "default": ""
Packit Service 863627
  },
Packit Service 863627
  "tmp-is-dir": {
Packit Service 863627
    "description": "Create a regular directory for /tmp",
Packit Service 863627
    "type": "boolean",
Packit Service 863627
    "default": true
Packit Service 863627
  },
Packit Service 863627
  "parent": {
Packit Service 863627
    "description": "commit id of the parent commit",
Packit Service 863627
    "type": "string"
Packit Service 863627
  },
Packit Service 863627
  "tar": {
Packit Service 863627
    "description": "Emit a tarball as the result",
Packit Service 863627
    "type": "object",
Packit Service 863627
    "additionalProperties": false,
Packit Service 863627
    "required": ["filename"],
Packit Service 863627
    "properties": {
Packit Service 863627
      "filename": {
Packit Service 863627
        "description": "File-name of the tarball to create. Compression is determined by the extension.",
Packit Service 863627
        "type": "string"
Packit Service 863627
      }
Packit Service 863627
    }
Packit Service 863627
  }
Packit Service 863627
}
Packit Service 863627
"""
Packit Service 863627
Packit Service 863627
TOPLEVEL_DIRS = ["dev", "proc", "run", "sys", "sysroot", "var"]
Packit Service 863627
TOPLEVEL_LINKS = {
Packit Service 863627
    "home": "var/home",
Packit Service 863627
    "media": "run/media",
Packit Service 863627
    "mnt": "var/mnt",
Packit Service 863627
    "opt": "var/opt",
Packit Service 863627
    "ostree": "sysroot/ostree",
Packit Service 863627
    "root": "var/roothome",
Packit Service 863627
    "srv": "var/srv",
Packit Service 863627
}
Packit Service 863627
Packit Service 863627
Packit Service 863627
def copy(name, source, dest):
Packit Service 863627
    subprocess.run(["cp", "--reflink=auto", "-a",
Packit Service 863627
                    os.path.join(source, name),
Packit Service 863627
                    os.path.join(dest, name)],
Packit Service 863627
                   check=True)
Packit Service 863627
Packit Service 863627
Packit Service 863627
def init_rootfs(root, tmp_is_dir):
Packit Service 863627
    """Initialize a pristine root file-system"""
Packit Service 863627
Packit Service 863627
    fd = os.open(root, os.O_DIRECTORY)
Packit Service 863627
Packit Service 863627
    os.fchmod(fd, 0o755)
Packit Service 863627
Packit Service 863627
    for d in TOPLEVEL_DIRS:
Packit Service 863627
        os.mkdir(d, mode=0o755, dir_fd=fd)
Packit Service 863627
        os.chmod(d, mode=0o755, dir_fd=fd)
Packit Service 863627
Packit Service 863627
    for l, t in TOPLEVEL_LINKS.items():
Packit Service 863627
        # <dir_fd>/l -> t
Packit Service 863627
        os.symlink(t, l, dir_fd=fd)
Packit Service 863627
Packit Service 863627
    if tmp_is_dir:
Packit Service 863627
        os.mkdir("tmp", mode=0o1777, dir_fd=fd)
Packit Service 863627
        os.chmod("tmp", mode=0o1777, dir_fd=fd)
Packit Service 863627
    else:
Packit Service 863627
        os.symlink("tmp", "sysroot/tmp", dir_fd=fd)
Packit Service 863627
Packit Service 863627
Packit Service 863627
def main(tree, output_dir, options, meta):
Packit Service 863627
    ref = options["ref"]
Packit Service 863627
    tmp_is_dir = options.get("tmp-is-dir", True)
Packit Service 863627
    parent = options.get("parent", None)
Packit Service 863627
    tar = options.get("tar", None)
Packit Service 863627
Packit Service 863627
    with tempfile.TemporaryDirectory(dir=output_dir) as root:
Packit Service 863627
        print("Initializing root filesystem", file=sys.stderr)
Packit Service 863627
        init_rootfs(root, tmp_is_dir)
Packit Service 863627
Packit Service 863627
        print("Copying data", file=sys.stderr)
Packit Service 863627
        copy("usr", tree, root)
Packit Service 863627
        copy("boot", tree, root)
Packit Service 863627
        copy("var", tree, root)
Packit Service 863627
Packit Service 863627
        for name in ["bin", "lib", "lib32", "lib64", "sbin"]:
Packit Service 863627
            if os.path.lexists(f"{tree}/{name}"):
Packit Service 863627
                copy(name, tree, root)
Packit Service 863627
Packit Service 863627
        repo = os.path.join(output_dir, "repo")
Packit Service 863627
Packit Service 863627
        subprocess.run(["ostree",
Packit Service 863627
                        "init",
Packit Service 863627
                        "--mode=archive",
Packit Service 863627
                        f"--repo={repo}"],
Packit Service 863627
                       stdout=sys.stderr,
Packit Service 863627
                       check=True)
Packit Service 863627
Packit Service 863627
        treefile = ostree.Treefile()
Packit Service 863627
        treefile["ref"] = ref
Packit Service 863627
Packit Service 863627
        argv = ["rpm-ostree", "compose", "commit"]
Packit Service 863627
        argv += [f"--repo={repo}"]
Packit Service 863627
Packit Service 863627
        if parent:
Packit Service 863627
            argv += [f"--parent={parent}"]
Packit Service 863627
Packit Service 863627
        argv += [
Packit Service 863627
            f"--add-metadata-string=rpmostree.inputhash={meta['id']}",
Packit Service 863627
            f"--write-composejson-to={output_dir}/compose.json"
Packit Service 863627
        ]
Packit Service 863627
Packit Service 863627
        with treefile.as_tmp_file() as path:
Packit Service 863627
            argv += [path, root]
Packit Service 863627
Packit Service 863627
            subprocess.run(argv,
Packit Service 863627
                           stdout=sys.stderr,
Packit Service 863627
                           check=True)
Packit Service 863627
Packit Service 863627
    if tar:
Packit Service 863627
        filename = tar["filename"]
Packit Service 863627
        command = [
Packit Service 863627
            "tar",
Packit Service 863627
            "--remove-files",
Packit Service 863627
            "--auto-compress",
Packit Service 863627
            "-cf", os.path.join(output_dir, filename),
Packit Service 863627
            "-C", output_dir,
Packit Service 863627
            "repo", "compose.json"
Packit Service 863627
        ]
Packit Service 863627
        subprocess.run(command,
Packit Service 863627
                       stdout=sys.stderr,
Packit Service 863627
                       check=True)
Packit Service 863627
Packit Service 863627
Packit Service 863627
Packit Service 863627
if __name__ == '__main__':
Packit Service 863627
    args = json.load(sys.stdin)
Packit Service 863627
    r = main(args["tree"], args["output_dir"], args["options"], args["meta"])
Packit Service 863627
    sys.exit(r)