feat: implement path transforms
diff --git a/docs/tar.md b/docs/tar.md
index d7f94ba..58d5eb1 100644
--- a/docs/tar.md
+++ b/docs/tar.md
@@ -25,11 +25,31 @@
## mtree_spec
<pre>
-mtree_spec(<a href="#mtree_spec-name">name</a>, <a href="#mtree_spec-out">out</a>, <a href="#mtree_spec-srcs">srcs</a>)
+mtree_spec(<a href="#mtree_spec-name">name</a>, <a href="#mtree_spec-out">out</a>, <a href="#mtree_spec-srcs">srcs</a>, <a href="#mtree_spec-transform">transform</a>)
</pre>
Create an mtree specification to map a directory hierarchy. See https://man.freebsd.org/cgi/man.cgi?mtree(8)
+Supports `$` and `^` RegExp tokens, which may be used together.
+
+* for stripping prefix, use `^path/to/strip`
+* for stripping suffix, use `path/to/strip$`
+* for exact match and replace, use `^path/to/strip$`
+* for partial match and replace, use `replace_anywhere`
+
+
+An example of stripping package path relative to the workspace
+
+```starlark
+tar(
+ srcs = ["PKGINFO"],
+ transform = {
+ "^{}".format(package_name()): ""
+ }
+)
+```
+
+
**ATTRIBUTES**
@@ -38,6 +58,7 @@
| <a id="mtree_spec-name"></a>name | A unique name for this target. | <a href="https://bazel.build/docs/build-ref.html#name">Name</a> | required | |
| <a id="mtree_spec-out"></a>out | Resulting specification file to write | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | |
| <a id="mtree_spec-srcs"></a>srcs | Files that are placed into the tar | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | required | |
+| <a id="mtree_spec-transform"></a>transform | A dict for path transforming. These are applied serially in respect to their orders. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
<a id="tar_rule"></a>
diff --git a/lib/private/tar.bzl b/lib/private/tar.bzl
index 4b301e5..29f0dec 100644
--- a/lib/private/tar.bzl
+++ b/lib/private/tar.bzl
@@ -51,6 +51,7 @@
_mtree_attrs = {
"srcs": attr.label_list(doc = "Files that are placed into the tar", mandatory = True, allow_files = True),
+ "transform": attr.string_dict(doc = """A dict for path transforming. These are applied serially in respect to their orders."""),
"out": attr.output(doc = "Resulting specification file to write"),
}
@@ -124,11 +125,7 @@
return DefaultInfo(files = depset([out]), runfiles = ctx.runfiles([out]))
-def _default_mtree_line(file):
- # Functions passed to map_each cannot take optional arguments.
- return _mtree_line(file.short_path, file.path, "dir" if file.is_directory else "file")
-
-def _mtree_line(file, content, type, uid = "0", gid = "0", time = "1672560000", mode = "0755"):
+def _mtree_line(file, content, type, uid = "0", gid = "0", time = "1672560000.000000", mode = "0755"):
return " ".join([
file,
"uid=" + uid,
@@ -139,12 +136,32 @@
"content=" + content,
])
+def _transform(path, transforms):
+ for (match, replace) in transforms.items():
+ # full match
+ if match.startswith("^") and match.endswith("$"):
+ if match.removeprefix("^").removesuffix("$") == path:
+ path = replace
+ elif match.startswith("^"):
+ if path.startswith(match.removeprefix("^")):
+ path = "".join([replace, path.removeprefix(match.removeprefix("^"))])
+ elif match.endswith("$"):
+ if path.endswith(match.removesuffix("$")):
+ path = "".join([path.removesuffix(match.removesuffix("$")), replace])
+ else:
+ path = path.replace(match, replace)
+
+ return path
+
def _mtree_impl(ctx):
out = ctx.outputs.out or ctx.actions.declare_file(ctx.attr.name + ".spec")
content = ctx.actions.args()
content.set_param_file_format("multiline")
- content.add_all(ctx.files.srcs, map_each = _default_mtree_line)
+
+ for s in ctx.files.srcs:
+ path = _transform(s.short_path, ctx.attr.transform)
+ content.add(_mtree_line(path, s.path, "dir" if s.is_directory else "file"))
for s in ctx.attr.srcs:
default_info = s[DefaultInfo]
@@ -153,7 +170,7 @@
runfiles_dir = _calculate_runfiles_dir(default_info)
for file in depset(transitive = [s.default_runfiles.files]).to_list():
- destination = _runfile_path(ctx, file, runfiles_dir)
+ destination = _transform(_runfile_path(ctx, file, runfiles_dir), ctx.attr.transform)
content.add(_mtree_line(destination, file.path, "file"))
ctx.actions.write(out, content = content)
diff --git a/lib/tar.bzl b/lib/tar.bzl
index 172c07e..98d3ec6 100644
--- a/lib/tar.bzl
+++ b/lib/tar.bzl
@@ -23,7 +23,27 @@
load("//lib/private:tar.bzl", "tar_lib", _tar = "tar")
mtree_spec = rule(
- doc = "Create an mtree specification to map a directory hierarchy. See https://man.freebsd.org/cgi/man.cgi?mtree(8)",
+ doc = """Create an mtree specification to map a directory hierarchy. See https://man.freebsd.org/cgi/man.cgi?mtree(8)
+
+Supports `$` and `^` RegExp tokens, which may be used together.
+
+* for stripping prefix, use `^path/to/strip`
+* for stripping suffix, use `path/to/strip$`
+* for exact match and replace, use `^path/to/strip$`
+* for partial match and replace, use `replace_anywhere`
+
+
+An example of stripping package path relative to the workspace
+
+```starlark
+tar(
+ srcs = ["PKGINFO"],
+ transform = {
+ "^{}".format(package_name()): ""
+ }
+)
+```
+""",
implementation = tar_lib.mtree_implementation,
attrs = tar_lib.mtree_attrs,
)
@@ -69,8 +89,11 @@
name = mtree_target,
srcs = kwargs["srcs"],
out = "{}.txt".format(mtree_target),
+ transform = kwargs.pop("transform", {}),
)
elif types.is_list(mtree):
+ if kwargs.pop("transform", None):
+ fail("transform shall be provided only when mtree=auto")
write_file(
name = mtree_target,
out = "{}.txt".format(mtree_target),
diff --git a/lib/tests/tar/BUILD.bazel b/lib/tests/tar/BUILD.bazel
index 2851bae..c781111 100644
--- a/lib/tests/tar/BUILD.bazel
+++ b/lib/tests/tar/BUILD.bazel
@@ -199,3 +199,30 @@
file1 = "src_file",
file2 = "cat_src_file_output",
)
+
+tar(
+ name = "transform",
+ srcs = [
+ "pkg/debian-binary",
+ "src_file",
+ ],
+ out = "transform.tar",
+ transform = {
+ "^lib/tests/": "",
+ "src_file$": "PKGINFO",
+ "^tar": "package",
+ # will flatten pkg/debian-binary to be inside package
+ "pkg/debian-binary": "debian-binary",
+ },
+)
+
+assert_tar_listing(
+ name = "test_transform",
+ actual = "transform",
+ expected = [
+ #
+ # TODO: https://github.com/aspect-build/bazel-lib/issues/625
+ "-rwxr-xr-x 0 0 0 0 Jan 1 2023 package/debian-binary",
+ "-rwxr-xr-x 0 0 0 21 Jan 1 2023 package/PKGINFO",
+ ],
+)
diff --git a/lib/tests/tar/pkg/debian-binary b/lib/tests/tar/pkg/debian-binary
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/tests/tar/pkg/debian-binary