stages/tar: allow chosen compression

The `org.osbuild.tar` stage only supports auto compression which is
based on the filename. For several (newer) artifacts such as Vagrant
(`.box`) and WSL (`.wsl`) we want to explicitly give the compression
algorithm.

I've chosen a (few) commonly used compression algorithms. If others are
needed they are one-line followups away.

Signed-off-by: Simon de Vlieger <supakeen@redhat.com>
This commit is contained in:
Simon de Vlieger 2025-05-22 08:57:11 +02:00 committed by Simon de Vlieger
parent b5e4775b24
commit a464815ea8
3 changed files with 51 additions and 1 deletions

View file

@ -37,10 +37,19 @@ def main(inputs, output_dir, options):
if transform:
extra_args += ["--transform", transform]
compression = options.get("compression", "auto")
if compression == "auto":
extra_args += ["--auto-compress"]
else:
# Note that the enums in the schema have been chosen exactly
# as the long forms for the compression flag(s) that GNU tar
# accepts
extra_args += [f"--{compression}"]
# Set up the tar command.
tar_cmd = [
"tar",
"--auto-compress",
f"--format={tarfmt}",
*extra_args,
"-cf", os.path.join(output_dir, filename),

View file

@ -65,6 +65,17 @@
],
"default": "gnu"
},
"compression": {
"description": "Compression to use",
"type": "string",
"enum": [
"auto",
"xz",
"gzip",
"zstd"
],
"default": "auto"
},
"acls": {
"description": "Enable support for POSIX ACLs",
"type": "boolean",

View file

@ -24,12 +24,18 @@ STAGE_NAME = "org.osbuild.tar"
"filename": "foo",
"transform": ["transform-cannot-be-passed-multiple-times"],
}, " is not of type 'string'"),
({
"filename": "foo",
"compression": "EXTREME",
}, "'EXTREME' is not one of"),
# good
({"filename": "out.tar", "root-node": "include"}, ""),
({"filename": "out.tar", "paths": ["file1"]}, ""),
({"filename": "out.tar", "sparse": True}, ""),
({"filename": "out.tar"}, ""),
({"filename": "out.tar", "transform": "s/foo/bar"}, ""),
({"filename": "out.tar", "compression": "auto"}, ""),
({"filename": "out.tar", "compression": "gzip"}, ""),
])
def test_schema_validation_tar(stage_schema, test_data, expected_err):
test_input = {
@ -160,3 +166,27 @@ def test_tar_disk_full(stage_module, fake_inputs, tmp_path_disk_full, capfd):
assert ex.value.returncode == 2
assert re.search(r"Wrote only \d+ of \d+ bytes", str(capfd.readouterr().err))
@pytest.mark.skipif(not has_executable("tar"), reason="no tar executable")
@pytest.mark.parametrize("filename,compression,expected", [
("out.tar.gz", "auto", "gzip"), # Auto uses the filename, which ends in .gz and should lead to gzip
("out.unknown", "xz", "xz"),
("out.unknown", "gzip", "gzip"),
("out.unknown", "zstd", "zstandard"),
])
def test_tar_compress(tmp_path, stage_module, fake_inputs, filename, compression, expected):
options = {
"filename": filename,
"paths": [
"file1",
"file2",
],
"compression": compression,
}
stage_module.main(fake_inputs, tmp_path, options)
tar_path = os.path.join(tmp_path, filename)
assert os.path.exists(tar_path)
output = subprocess.check_output(["file", tar_path], encoding="utf-8")
assert expected in output.lower()