diff --git a/docs/tar.md b/docs/tar.md index 5f59d91ef..cc3a368c9 100644 --- a/docs/tar.md +++ b/docs/tar.md @@ -15,13 +15,13 @@ this: We also provide full control for tar'ring binaries including their runfiles. -## Modifying metadata +## Mutating the tar contents The `mtree_spec` rule can be used to create an mtree manifest for the tar file. -Then you can mutate that spec, as it's just a simple text file, and feed the result +Then you can mutate that spec using `mtree_mutate` and feed the result as the `mtree` attribute of the `tar` rule. -For example, to set the `uid` property, you could: +For example, to set the owner uid of files in the tar, you could: ```starlark mtree_spec( @@ -29,11 +29,10 @@ mtree_spec( srcs = ["//some:files"], ) -genrule( +mtree_mutate( name = "change_owner", - srcs = ["mtree"], - outs = ["mtree.mutated"], - cmd = "sed 's/uid=0/uid=1000/' <$< >$@", + mtree = ":mtree", + owner = "1000", ) tar( @@ -43,10 +42,6 @@ tar( ) ``` -Note: We intend to contribute mutation features to https://github.com/vbatts/go-mtree -to provide a richer API for things like `strip_prefix`. -In the meantime, see the `lib/tests/tar/BUILD.bazel` file in this repo for examples. - TODO: - Provide convenience for rules_pkg users to re-use or replace pkg_files trees @@ -95,6 +90,31 @@ Rule that executes BSD `tar`. Most users should use the [`tar`](#tar) macro, rat | srcs | Files, directories, or other targets whose default outputs are placed into the tar.

If any of the srcs are binaries with runfiles, those are copied into the resulting tar as well. | List of labels | optional | [] | + + +## mtree_mutate + +
+mtree_mutate(name, mtree, strip_prefix, mtime, owner, ownername, awk_script, kwargs)
+
+ +Modify metadata in an mtree file. + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| name | name of the target, output will be [name].mtree. | none | +| mtree | input mtree file, typically created by mtree_spec. | none | +| strip_prefix | prefix to remove from all paths in the tar. Files and directories not under this prefix are dropped. | None | +| mtime | new modification time for all entries. | None | +| owner | new uid for all entries. | None | +| ownername | new uname for all entries. | None | +| awk_script | may be overridden to change the script containing the modification logic. | "@aspect_bazel_lib//lib/private:modify_mtree.awk" | +| kwargs | additional named parameters to genrule | none | + + ## tar diff --git a/lib/private/BUILD.bazel b/lib/private/BUILD.bazel index a0e092429..1980f3fd1 100644 --- a/lib/private/BUILD.bazel +++ b/lib/private/BUILD.bazel @@ -5,6 +5,7 @@ exports_files( [ "diff_test_tmpl.sh", "diff_test_tmpl.bat", + "modify_mtree.awk", "parse_status_file.jq", "parse_status_file.yq", ], diff --git a/lib/private/modify_mtree.awk b/lib/private/modify_mtree.awk new file mode 100644 index 000000000..2fe659801 --- /dev/null +++ b/lib/private/modify_mtree.awk @@ -0,0 +1,32 @@ +# Edits mtree files. See the modify_mtree macro in /lib/tar.bzl. +{ + if (strip_prefix != "") { + if ($1 == strip_prefix) { + # this line declares the directory which is now the root. It may be discarded. + next; + } else if (index($1, strip_prefix) == 1) { + # this line starts with the strip_prefix + sub("^" strip_prefix "/", ""); + } else { + # this line declares some path under a parent directory, which will be discarded + next; + } + } + + if (mtime != "") { + sub(/time=[0-9\.]+/, "time=" mtime); + } + + if (owner != "") { + sub(/uid=[0-9\.]+/, "uid=" owner) + } + + if (ownername != "") { + sub(/uname=[^ ]+/, "uname=" ownername) + } + + if (package_dir != "") { + sub(/^/, package_dir "/") + } + print; +} diff --git a/lib/tar.bzl b/lib/tar.bzl index e8051a7ef..30ad7aeb3 100644 --- a/lib/tar.bzl +++ b/lib/tar.bzl @@ -13,13 +13,13 @@ this: We also provide full control for tar'ring binaries including their runfiles. -## Modifying metadata +## Mutating the tar contents The `mtree_spec` rule can be used to create an mtree manifest for the tar file. -Then you can mutate that spec, as it's just a simple text file, and feed the result +Then you can mutate that spec using `mtree_mutate` and feed the result as the `mtree` attribute of the `tar` rule. -For example, to set the `uid` property, you could: +For example, to set the owner uid of files in the tar, you could: ```starlark mtree_spec( @@ -27,11 +27,10 @@ mtree_spec( srcs = ["//some:files"], ) -genrule( +mtree_mutate( name = "change_owner", - srcs = ["mtree"], - outs = ["mtree.mutated"], - cmd = "sed 's/uid=0/uid=1000/' <$< >$@", + mtree = ":mtree", + owner = "1000", ) tar( @@ -41,10 +40,6 @@ tar( ) ``` -Note: We intend to contribute mutation features to https://github.com/vbatts/go-mtree -to provide a richer API for things like `strip_prefix`. -In the meantime, see the `lib/tests/tar/BUILD.bazel` file in this repo for examples. - TODO: - Provide convenience for rules_pkg users to re-use or replace pkg_files trees """ @@ -130,3 +125,43 @@ def tar(name, mtree = "auto", stamp = 0, **kwargs): mtree = mtree_target, **kwargs ) + +def mtree_mutate( + name, + mtree, + strip_prefix = None, + mtime = None, + owner = None, + ownername = None, + awk_script = "@aspect_bazel_lib//lib/private:modify_mtree.awk", + **kwargs): + """Modify metadata in an mtree file. + + Args: + name: name of the target, output will be `[name].mtree`. + mtree: input mtree file, typically created by `mtree_spec`. + strip_prefix: prefix to remove from all paths in the tar. Files and directories not under this prefix are dropped. + mtime: new modification time for all entries. + owner: new uid for all entries. + ownername: new uname for all entries. + awk_script: may be overridden to change the script containing the modification logic. + **kwargs: additional named parameters to genrule + """ + vars = [] + if strip_prefix: + vars.append("-v strip_prefix='{}'".format(strip_prefix)) + if mtime: + vars.append("-v mtime='{}'".format(mtime)) + if owner: + vars.append("-v owner='{}'".format(owner)) + if ownername: + vars.append("-v ownername='{}'".format(ownername)) + + native.genrule( + name = name, + srcs = [mtree], + outs = [name + ".mtree"], + cmd = "awk {} -f $(execpath {}) <$< >$@".format(" ".join(vars), awk_script), + tools = [awk_script], + **kwargs + ) diff --git a/lib/tests/tar/BUILD.bazel b/lib/tests/tar/BUILD.bazel index a6c2bb5fe..497f70782 100644 --- a/lib/tests/tar/BUILD.bazel +++ b/lib/tests/tar/BUILD.bazel @@ -1,6 +1,6 @@ load("@aspect_bazel_lib//lib:copy_directory.bzl", "copy_directory") load("@aspect_bazel_lib//lib:diff_test.bzl", "diff_test") -load("@aspect_bazel_lib//lib:tar.bzl", "mtree_spec", "tar") +load("@aspect_bazel_lib//lib:tar.bzl", "mtree_mutate", "mtree_spec", "tar") load("@aspect_bazel_lib//lib:testing.bzl", "assert_archive_contains") load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:write_file.bzl", "write_file") @@ -123,25 +123,10 @@ mtree_spec( srcs = _SRCS5, ) -# This is a low-tech way to mutate the mtree specification, just using regex. -# See docs on tar about future directions for mtree mutation -genrule( +mtree_mutate( name = "strip_prefix", - srcs = ["mtree5"], - outs = ["mtree5.stripped"], - # Modify lines starting with the package name, e.g. - # lib/tests/tar/a uid=0 gid=0 time=1672560000 mode=0755 type=file content=bazel-out/darwin_arm64-opt/bin/lib/tests/tar/a - # -> - # a uid=0 gid=0 time=1672560000 mode=0755 type=file content=bazel-out/darwin_arm64-opt/bin/lib/tests/tar/a - cmd = "sed '{}' <$< | sed '/^\\ /d' > $@".format( - "; ".join(reversed([ - "s#^{s}/##; s#^{s}##".format(s = "/".join(package_name().split("/")[:i])) - for (i, _) in enumerate( - package_name().split("/"), - 1, - ) - ])), - ), + mtree = "mtree5", + strip_prefix = package_name(), ) tar( @@ -342,3 +327,30 @@ assert_tar_listing( "drwxrwxrwt 0 0 0 0 Aug 3 2017 ./tmp/", ], ) + +# Case 12: arbitrary mtree modifications +mtree_mutate( + name = "modified1", + mtree = "source-casync.mtree", + strip_prefix = "xattr", +) + +diff_test( + name = "test1", + file1 = "modified1.mtree", + file2 = "expected1.mtree", +) + +mtree_mutate( + name = "modified2", + mtime = 946684740, # 1999-12-31, 23:59 + mtree = "source-casync.mtree", + owner = "123", + ownername = "fred", +) + +diff_test( + name = "test2", + file1 = "modified2.mtree", + file2 = "expected2.mtree", +) diff --git a/lib/tests/tar/expected1.mtree b/lib/tests/tar/expected1.mtree new file mode 100644 index 000000000..2ee0ab4f8 --- /dev/null +++ b/lib/tests/tar/expected1.mtree @@ -0,0 +1,4 @@ +xattr.go type=file mode=0664 size=984 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=a2700b603df30c3b0a91bdcf9045e64aea42f62647b0128ea154f51a0c48991e +xattr_test.go type=file mode=0664 size=859 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=91294ea554801b75f6a9e33c268807c9620b531eb813ea24512dd4eeaf0592e4 +xattr_unsupported.go type=file mode=0664 size=509 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=81ced06a1cdf88c4936d10bbf8d46edc2d42dc26efeed3691ddbeeb469865f8a +xattr_unsupported_test.go type=file mode=0664 size=877 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=46605a03a985c7a3a4ab1a488f81382db4865f77b90b6a2b32693af39a8e1fba diff --git a/lib/tests/tar/expected2.mtree b/lib/tests/tar/expected2.mtree new file mode 100644 index 000000000..eb253b160 --- /dev/null +++ b/lib/tests/tar/expected2.mtree @@ -0,0 +1,5 @@ +xattr type=dir mode=0775 uid=123 gid=1000 uname=fred gname=vbatts time=946684740 +xattr/xattr.go type=file mode=0664 size=984 uid=123 gid=1000 uname=fred gname=vbatts time=946684740 sha512256digest=a2700b603df30c3b0a91bdcf9045e64aea42f62647b0128ea154f51a0c48991e +xattr/xattr_test.go type=file mode=0664 size=859 uid=123 gid=1000 uname=fred gname=vbatts time=946684740 sha512256digest=91294ea554801b75f6a9e33c268807c9620b531eb813ea24512dd4eeaf0592e4 +xattr/xattr_unsupported.go type=file mode=0664 size=509 uid=123 gid=1000 uname=fred gname=vbatts time=946684740 sha512256digest=81ced06a1cdf88c4936d10bbf8d46edc2d42dc26efeed3691ddbeeb469865f8a +xattr/xattr_unsupported_test.go type=file mode=0664 size=877 uid=123 gid=1000 uname=fred gname=vbatts time=946684740 sha512256digest=46605a03a985c7a3a4ab1a488f81382db4865f77b90b6a2b32693af39a8e1fba diff --git a/lib/tests/tar/source-casync.mtree b/lib/tests/tar/source-casync.mtree new file mode 100644 index 000000000..597813090 --- /dev/null +++ b/lib/tests/tar/source-casync.mtree @@ -0,0 +1,5 @@ +xattr type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 +xattr/xattr.go type=file mode=0664 size=984 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=a2700b603df30c3b0a91bdcf9045e64aea42f62647b0128ea154f51a0c48991e +xattr/xattr_test.go type=file mode=0664 size=859 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=91294ea554801b75f6a9e33c268807c9620b531eb813ea24512dd4eeaf0592e4 +xattr/xattr_unsupported.go type=file mode=0664 size=509 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=81ced06a1cdf88c4936d10bbf8d46edc2d42dc26efeed3691ddbeeb469865f8a +xattr/xattr_unsupported_test.go type=file mode=0664 size=877 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=46605a03a985c7a3a4ab1a488f81382db4865f77b90b6a2b32693af39a8e1fba