diff --git a/e2e/smoke/testdata_mtree.spec.golden b/e2e/smoke/testdata_mtree.spec.golden new file mode 100644 index 000000000..2b80c99e4 --- /dev/null +++ b/e2e/smoke/testdata_mtree.spec.golden @@ -0,0 +1,4 @@ +testdata uid=0 gid=0 time=1672560000 mode=0755 type=dir +testdata/file\040empty\040with\040spaces.txt uid=0 gid=0 time=1672560000 mode=0755 type=file content=testdata/file\040empty\040with\040spaces.txt +testdata/file\040empty\040with\040\360\237\230\215.txt uid=0 gid=0 time=1672560000 mode=0755 type=file content=testdata/file\040empty\040with\040\360\237\230\215.txt +testdata/file-empty.txt uid=0 gid=0 time=1672560000 mode=0755 type=file content=testdata/file-empty.txt diff --git a/lib/private/tar.bzl b/lib/private/tar.bzl index 0bc8a2e35..2dcf6ade9 100644 --- a/lib/private/tar.bzl +++ b/lib/private/tar.bzl @@ -161,17 +161,15 @@ def _tar_impl(ctx): return DefaultInfo(files = depset([out]), runfiles = ctx.runfiles([out])) def _mtree_line(file, type, content = None, uid = "0", gid = "0", time = "1672560000", mode = "0755"): - spec = [ - file, - "uid=" + uid, - "gid=" + gid, - "time=" + time, - "mode=" + mode, - "type=" + type, - ] - if content: - spec.append("content=" + content) - return " ".join(spec) + return json.encode(struct( + file = file, + uid = uid, + gid = gid, + time = time, + mode = mode, + type = type, + content = content, + )) # This function exactly same as the one from "@aspect_bazel_lib//lib:paths.bzl" # except that it takes workspace_name directly instead of the ctx object. @@ -198,6 +196,7 @@ def _expand(file, expander, transform = to_repository_relative_path): def _mtree_impl(ctx): out = ctx.outputs.out or ctx.actions.declare_file(ctx.attr.name + ".spec") + json_out = ctx.actions.declare_file(out.basename + ".json", sibling = out) content = ctx.actions.args() content.set_param_file_format("multiline") @@ -230,7 +229,40 @@ def _mtree_impl(ctx): allow_closure = True, ) - ctx.actions.write(out, content = content) + ctx.actions.write(json_out, content = content) + + jq_bin = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"].jqinfo.bin + + ctx.actions.run_shell( + tools = [jq_bin], + inputs = [json_out], + outputs = [out], + command = """ +while IFS= read -r jsonl; do + file=$({jq} -r '.file' <<< "$jsonl") + gid=$({jq} -r '.gid' <<< "$jsonl") + uid=$({jq} -r '.uid' <<< "$jsonl") + time=$({jq} -r '.time' <<< "$jsonl") + mode=$({jq} -r '.mode' <<< "$jsonl") + type=$({jq} -r '.type' <<< "$jsonl") + content=$({jq} -r '.content' <<< "$jsonl") + + file_encoded=$(echo -n "$file" | vis -wo) + mtree_line="$file_encoded uid=$uid gid=$gid time=$time mode=$mode type=$type" + if [ "$content" != "null" ]; then + content_encoded=$(echo -n "$content" | vis -wo) + mtree_line="$mtree_line content=$content_encoded" + fi + + echo "$mtree_line" >> {output} +done < {input} +""".format( + jq = jq_bin.path, + input = json_out.path, + output = out.path, + ), + mnemonic = "MtreeSpec", + ) return DefaultInfo(files = depset([out]), runfiles = ctx.runfiles([out])) diff --git a/lib/tar.bzl b/lib/tar.bzl index e8051a7ef..81dde4b9f 100644 --- a/lib/tar.bzl +++ b/lib/tar.bzl @@ -58,6 +58,7 @@ mtree_spec = rule( doc = "Create an mtree specification to map a directory hierarchy. See https://man.freebsd.org/cgi/man.cgi?mtree(8)", implementation = _tar_lib.mtree_implementation, attrs = _tar_lib.mtree_attrs, + toolchains = ["@aspect_bazel_lib//lib:jq_toolchain_type"], ) tar_rule = _tar diff --git a/lib/tests/tar/BUILD.bazel b/lib/tests/tar/BUILD.bazel index a6c2bb5fe..64c182c3a 100644 --- a/lib/tests/tar/BUILD.bazel +++ b/lib/tests/tar/BUILD.bazel @@ -342,3 +342,26 @@ assert_tar_listing( "drwxrwxrwt 0 0 0 0 Aug 3 2017 ./tmp/", ], ) + +# Case 12: Special characters in filenames require running 'vis' +mtree_spec( + name = "testdata_mtree", + srcs = [":testdata_files"], +) + +tar( + name = "testdata_tar", + srcs = [":testdata_files"], + mtree = [":testdata_mtree"], +) + +filegroup( + name = "testdata_files", + srcs = glob(["testdata/**/*"]), +) + +diff_test( + name = "mtree_golden_test", + file1 = ":testdata_mtree", + file2 = "testdata_mtree.spec.golden", +) diff --git a/lib/tests/tar/testdata/file empty with spaces.txt b/lib/tests/tar/testdata/file empty with spaces.txt new file mode 100644 index 000000000..e69de29bb diff --git "a/lib/tests/tar/testdata/file empty with \360\237\230\215.txt" "b/lib/tests/tar/testdata/file empty with \360\237\230\215.txt" new file mode 100644 index 000000000..e69de29bb diff --git a/lib/tests/tar/testdata/file-empty.txt b/lib/tests/tar/testdata/file-empty.txt new file mode 100644 index 000000000..e69de29bb