| 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_mutate", "mtree_spec", "tar") |
| load("@aspect_bazel_lib//lib:testing.bzl", "assert_archive_contains") |
| load("@bazel_skylib//rules:write_file.bzl", "write_file") |
| load(":asserts.bzl", "assert_tar_listing") |
| |
| # The examples below work with both source files and generated files. |
| # Here we generate a file to use in the examples. |
| write_file( |
| name = "fixture1", |
| out = "generated.txt", |
| content = ["hello a"], |
| ) |
| |
| ############# |
| # Example 1: Show that you can run any `tar` command you like, using a genrule. |
| # This is advanced, atypical usage where you need such a level of control and don't want to use the `tar` rule. |
| genrule( |
| name = "tar_genrule", |
| srcs = [ |
| ":fixture1", |
| "src_file", |
| ], |
| outs = ["1.tar"], |
| cmd = "$(BSDTAR_BIN) --create --dereference --file $@ -s '#$(BINDIR)##' $(execpath :fixture1) $(execpath src_file)", |
| target_compatible_with = select({ |
| # bsdtar.exe: -s is not supported by this version of bsdtar |
| "@platforms//os:windows": ["@platforms//:incompatible"], |
| "//conditions:default": [], |
| }), |
| toolchains = ["@bsd_tar_toolchains//:resolved_toolchain"], |
| ) |
| |
| assert_archive_contains( |
| name = "test_genrule", |
| archive = "1.tar", |
| expected = [ |
| "lib/tests/tar/generated.txt", |
| "lib/tests/tar/src_file", |
| ], |
| ) |
| |
| ############# |
| # Example 2: exact control of the resulting tar file, using a custom specification in the "mtree" format. |
| # Copied from the output of `man tar`: |
| # An input file in mtree(5) format can be used to create an output |
| # archive with arbitrary ownership, permissions, or names that differ |
| # from existing data on disk: |
| # $ cat input.mtree |
| # #mtree |
| # usr/bin uid=0 gid=0 mode=0755 type=dir |
| # usr/bin/ls uid=0 gid=0 mode=0755 type=file content=myls |
| # $ tar -cvf output.tar @input.mtree |
| tar( |
| name = "tar_custom_mtree", |
| srcs = ["src_file"], |
| mtree = [ |
| "usr/bin uid=0 gid=0 mode=0755 time=1672560000 type=dir", |
| "usr/bin/ls uid=0 gid=0 mode=0755 time=1672560000 type=file content={}/src_file".format(package_name()), |
| ], |
| ) |
| |
| assert_tar_listing( |
| name = "test_custom_mtree", |
| actual = "tar_custom_mtree", |
| expected = [ |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 usr/bin/", |
| "-rwxr-xr-x 0 0 0 21 Jan 1 2023 usr/bin/ls", |
| ], |
| ) |
| |
| ############# |
| # Example 3: compression. |
| # This uses gzip, see the `compress` attribute documentation for other legal values. |
| tar( |
| name = "tar_compress", |
| srcs = ["generated.txt"], |
| out = "3.tgz", |
| compress = "gzip", |
| ) |
| |
| assert_archive_contains( |
| name = "test_compress", |
| archive = "3.tgz", |
| expected = ["lib/tests/tar/generated.txt"], |
| type = "tar", |
| ) |
| |
| ############# |
| # Example 4: you can pass arbitrary command-line flags to the bsdtar executable. |
| write_file( |
| name = "fixture4", |
| out = ".git", |
| content = ["it's a folder"], |
| ) |
| |
| tar( |
| name = "tar_flags", |
| srcs = [ |
| ".git", |
| "src_file", |
| ":fixture1", |
| ], |
| out = "4.tar", |
| # Due to this argument, .git should not appear in the resulting tar |
| args = ["--exclude-vcs"], |
| ) |
| |
| assert_tar_listing( |
| name = "test_flags", |
| actual = "tar_flags", |
| expected = [ |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 lib/", |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/", |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/tar/", |
| "-rwxr-xr-x 0 0 0 21 Jan 1 2023 lib/tests/tar/src_file", |
| "-rwxr-xr-x 0 0 0 7 Jan 1 2023 lib/tests/tar/generated.txt", |
| ], |
| ) |
| |
| ############# |
| # Example 5: features like `strip_prefix` are supported by `mtree_mutate`. |
| # This lets you port code that used the `pkg_tar` rule from bazelbuild/rules_pkg. |
| _SRCS5 = [ |
| ":fixture1", |
| "src_file", |
| ] |
| |
| mtree_spec( |
| name = "mtree5", |
| srcs = _SRCS5, |
| ) |
| |
| mtree_mutate( |
| name = "strip_prefix", |
| mtree = "mtree5", |
| strip_prefix = package_name(), |
| ) |
| |
| tar( |
| name = "tar_strip_prefix", |
| srcs = _SRCS5, |
| out = "5.tar", |
| mtree = "strip_prefix", |
| ) |
| |
| assert_tar_listing( |
| name = "test_strip_prefix", |
| actual = "tar_strip_prefix", |
| expected = [ |
| "-rwxr-xr-x 0 0 0 7 Jan 1 2023 generated.txt", |
| "-rwxr-xr-x 0 0 0 21 Jan 1 2023 src_file", |
| ], |
| ) |
| |
| ############# |
| # Example 6: When archiving a binary, the "runfiles" are included. |
| sh_binary( |
| name = "cat_src_file", |
| srcs = ["cat_src_file.sh"], |
| data = ["src_file"], |
| deps = ["@bazel_tools//tools/bash/runfiles"], |
| ) |
| |
| tar( |
| name = "tar_runfiles", |
| srcs = [":cat_src_file"], |
| out = "6.tar", |
| ) |
| |
| genrule( |
| name = "run_program_with_runfiles", |
| srcs = [":tar_runfiles"], |
| outs = ["cat_src_file_output"], |
| cmd = """\ |
| export DIR=$$(mktemp -d) |
| $(BSDTAR_BIN) --extract --file $(execpath :tar_runfiles) --directory $$DIR |
| ( |
| cd $$DIR |
| ./lib/tests/tar/cat_src_file |
| ) > $@ |
| """, |
| target_compatible_with = select({ |
| # requires runfiles tree, otherwise get |
| # ERROR: cannot find bazel_tools/tools/bash/runfiles/runfiles.bash |
| "@platforms//os:windows": ["@platforms//:incompatible"], |
| # TODO(sahin): incompatible with bzlmod |
| "@aspect_bazel_lib//lib:bzlmod": ["@platforms//:incompatible"], |
| "//conditions:default": [], |
| }), |
| toolchains = ["@bsd_tar_toolchains//:resolved_toolchain"], |
| ) |
| |
| diff_test( |
| name = "test_runfiles", |
| timeout = "short", |
| file1 = "src_file", |
| file2 = "cat_src_file_output", |
| ) |
| |
| ############# |
| # Example 7: You can archive directories, |
| # both those in the source tree and those produced by rules that understand "tree artifacts". |
| copy_directory( |
| name = "treeartifact", |
| src = "srcdir", |
| out = "treeartifact", |
| ) |
| |
| tar( |
| name = "dirs", |
| # Note, testonly should be propagated, proven by |
| # % bazel query --output=label_kind 'attr("testonly", 1, lib/tests/tar:all)' |
| # mtree_spec rule //lib/tests/tar:_dirs.mtree |
| # tar rule //lib/tests/tar:dirs |
| testonly = True, |
| srcs = glob(["srcdir/**"]) + [ |
| "treeartifact", |
| ], |
| out = "7.tar", |
| ) |
| |
| assert_tar_listing( |
| name = "test_dirs", |
| actual = "dirs", |
| expected = [ |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 lib/", |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/", |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/tar/", |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/tar/srcdir/", |
| "-rwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/tar/srcdir/info", |
| "-rwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/tar/srcdir/pkg", |
| "-rwxr-xr-x 0 0 0 1 Jan 1 2023 lib/tests/tar/srcdir/space in name.txt", |
| "drwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/tar/treeartifact/", |
| "-rwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/tar/treeartifact/info", |
| "-rwxr-xr-x 0 0 0 0 Jan 1 2023 lib/tests/tar/treeartifact/pkg", |
| "-rwxr-xr-x 0 0 0 1 Jan 1 2023 lib/tests/tar/treeartifact/space in name.txt", |
| ], |
| ) |
| |
| ############# |
| # Example 8: arbitrary mutations of the mtree spec can be performed. |
| # Typically use the `mtree_mutate` rule which supports specific mutations using a more ergonomic API, |
| # see Example 12 below. |
| _SRCS8 = [ |
| ":fixture1", |
| "src_file", |
| ] |
| |
| mtree_spec( |
| name = "mtree8", |
| srcs = _SRCS8, |
| ) |
| |
| # This is a very simple way to mutate the mtree specification, just using regex. |
| # See docs on tar about future directions for mtree mutation |
| genrule( |
| name = "change_owner", |
| srcs = ["mtree8"], |
| outs = ["mtree8.mutated"], |
| # Modify uid and gid, 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 |
| # -> |
| # lib/tests/tar/a uid=1000 gid=500 time=1672560000 mode=0755 type=file content=bazel-out/darwin_arm64-opt/bin/lib/tests/tar/a |
| cmd = "sed 's/uid=0/uid=1000/;s/gid=0/gid=500/' <$< >$@", |
| ) |
| |
| tar( |
| name = "tar_change_owner", |
| srcs = _SRCS8, |
| out = "8.tar", |
| mtree = "change_owner", |
| ) |
| |
| assert_tar_listing( |
| name = "test_change_owner", |
| actual = "tar_change_owner", |
| expected = [ |
| "drwxr-xr-x 0 1000 500 0 Jan 1 2023 lib/", |
| "drwxr-xr-x 0 1000 500 0 Jan 1 2023 lib/tests/", |
| "drwxr-xr-x 0 1000 500 0 Jan 1 2023 lib/tests/tar/", |
| "-rwxr-xr-x 0 1000 500 7 Jan 1 2023 lib/tests/tar/generated.txt", |
| "-rwxr-xr-x 0 1000 500 21 Jan 1 2023 lib/tests/tar/src_file", |
| ], |
| ) |
| |
| ############# |
| # Example 9: Files from a different repository (see #697) |
| # Note: This test uses an exported file from skylib, so we do not need to create |
| # an additional workspace just for this test. |
| tar( |
| name = "tar_different_repo", |
| srcs = ["@bazel_skylib//:LICENSE"], |
| out = "9.tar", |
| ) |
| |
| assert_archive_contains( |
| name = "test_different_repo", |
| archive = "9.tar", |
| expected = [ |
| "LICENSE", |
| ], |
| ) |
| |
| ############# |
| # Example 10: Similar to Example 9, you can reference generated files in the `mtree` attribute as well. |
| tar( |
| name = "tar_location_expansion", |
| srcs = ["@bazel_skylib//:LICENSE"], |
| out = "10.tar", |
| mtree = [ |
| "license uid=0 gid=0 time=1672560000 mode=0755 type=file content=$(location @bazel_skylib//:LICENSE)", |
| ], |
| ) |
| |
| assert_tar_listing( |
| name = "test_tar_location_expansion", |
| actual = "tar_location_expansion", |
| expected = [ |
| "-rwxr-xr-x 0 0 0 11358 Jan 1 2023 license", |
| ], |
| ) |
| |
| ############# |
| # Example 11: You can create a tar without srcs, only empty directories |
| tar( |
| name = "create_tmp", |
| mtree = ["./tmp time=1501783453.0 mode=1777 gid=0 uid=0 type=dir"], |
| ) |
| |
| assert_tar_listing( |
| name = "test_create_create_tmp", |
| actual = "create_tmp", |
| expected = [ |
| "drwxrwxrwt 0 0 0 0 Aug 3 2017 ./tmp/", |
| ], |
| ) |
| |
| ############# |
| # Example 12: arbitrary mtree modifications |
| mtree_mutate( |
| name = "modified1", |
| mtree = "source-casync.mtree", |
| package_dir = "test", |
| 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", |
| ) |
| |
| ############# |
| # Example 13: Ensure that multiple entries at the root directory are handled correctly (bug #851) |
| # NOTE: The mtree_spec part of this test is placed at the root BUILD.bazel because |
| # that's the only way to ensure that the mtree_spec generates single-component |
| # entries (which would trigger the bug). |
| exports_files(["expected13.mtree"]) |
| |
| ############# |
| # Example 14: Ensure mtree_mutate correctly handles prefix stripping for top-level directories (bug #851) |
| write_file( |
| name = "test14_main", |
| out = "14project/__main__.py", |
| content = ["__main__.py"], |
| ) |
| |
| write_file( |
| name = "test14_bin", |
| out = "14project_bin", |
| content = ["project_bin"], |
| ) |
| |
| mtree_spec( |
| name = "mtree14", |
| srcs = [ |
| ":test14_bin", |
| ":test14_main", |
| ], |
| ) |
| |
| mtree_mutate( |
| name = "strip_prefix14_unsorted", |
| mtree = "mtree14", |
| strip_prefix = "lib/tests/tar", |
| ) |
| |
| # NOTE: On some systems, the mtree_spec output can have a different order. |
| # To make the test less brittle, we sort the mtree output and replace the BINDIR with a constant placeholder |
| genrule( |
| name = "strip_prefix14", |
| srcs = [":strip_prefix14_unsorted"], |
| outs = ["actual14.mtree"], |
| cmd = "sort $< | sed 's#$(BINDIR)#{BINDIR}#' >$@", |
| ) |
| |
| diff_test( |
| name = "test14", |
| file1 = ":strip_prefix14", |
| file2 = "expected14.mtree", |
| ) |