wip preserve symlinks

This commit is contained in:
thesayyn 2024-10-16 10:10:53 -07:00
parent 43f8b3e524
commit e8d14e8801
No known key found for this signature in database
GPG Key ID: D10C0AE203D0E4A8
4 changed files with 96 additions and 0 deletions

View File

@ -1,5 +1,21 @@
# Edits mtree files. See the modify_mtree macro in /lib/tar.bzl.
{
if (preserve_symlink != "") {
# By default Bazel reports symlinks as regular file/dir therefore mtree_spec has no way of knowing that a file
# is a symlink. This is a problem when we want to preserve symlinks especially for symlink sensitive applications
# such as nodejs with pnpm. To work around this we need to determine if a file a symlink and if so, we need to
# determine where the symlink points to by calling readlink repeatedly until we get the final destination.
#
# We then need to decide if it's a symlink based on how many times we had to call readlink and where we ended up.
#
# Unlike Bazels own symlinks, which points out of the sandbox symlinks, symlinks created by ctx.actions.symlink
# stays within the bazel sandbox so it's possible to detect those.
#
# See https://github.com/bazelbuild/rules_pkg/pull/609
if ($0 ~ /type=file/) {
}
}
if (strip_prefix != "") {
if ($1 == strip_prefix) {
# this line declares the directory which is now the root. It may be discarded.

View File

@ -137,6 +137,8 @@ def tar(name, mtree = "auto", stamp = 0, **kwargs):
def mtree_mutate(
name,
mtree,
srcs = None,
preserve_symlinks = False,
strip_prefix = None,
package_dir = None,
mtime = None,
@ -148,6 +150,8 @@ def mtree_mutate(
Args:
name: name of the target, output will be `[name].mtree`.
srcs: source files to be used when resolving symlinks. required if `preserve_symlinks` is set to True.
preserve_symlinks: preserve symlinks
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.
package_dir: directory prefix to add to all paths in the tar.
@ -155,6 +159,7 @@ def mtree_mutate(
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 = []
@ -168,6 +173,10 @@ def mtree_mutate(
vars.append("-v owner='{}'".format(owner))
if ownername:
vars.append("-v ownername='{}'".format(ownername))
if preserve_symlinks:
vars.append("-v preserve_symlinks=1")
if not srcs:
fail("preserve_symlinks requires srcs to be set in order to resolve symlinks")
native.genrule(
name = name,

View File

@ -4,6 +4,7 @@ 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", "assert_unused_listing")
load(":node_modules_tree.bzl", "node_modules_tree")
# The examples below work with both source files and generated files.
# Here we generate a file to use in the examples.
@ -465,3 +466,22 @@ assert_unused_listing(
"lib/tests/tar/unused/space in name.txt",
],
)
#############
# Example 16: mtree_mutate preserves symlinks
node_modules_tree(
name = "e16_node_modules",
)
mtree_spec(
name = "mtree16",
srcs = [
":e16_node_modules",
],
)
assert_tar_listing(
name = "test_16_before_processing",
actual = ":mtree16",
expected = [],
)

View File

@ -0,0 +1,51 @@
# https://github.com/bazelbuild/rules_pkg/pull/609
def impl(ctx):
# packages
# - a
# - b depends on a
store_a = ctx.actions.declare_directory("node_modules/.pnpm/a@0.0.0/node_modules/a")
store_b = ctx.actions.declare_directory("node_modules/.pnpm/b@0.0.0/node_modules/b")
ctx.actions.run_shell(
outputs = [store_a, store_b],
command = "echo 'test' > %s/package.json" % store_a.path,
)
dep_symlink_b_to_a = ctx.actions.declare_directory("node_modules/.pnpm/b@0.0.0/node_modules/a")
ctx.actions.symlink(
output = dep_symlink_b_to_a,
target_file = store_a,
)
node_modules_a = ctx.actions.declare_directory("node_modules/a")
ctx.actions.symlink(
output = node_modules_a,
target_file = store_a,
)
# single file
a = ctx.actions.declare_file("dir/a")
ctx.actions.run_shell(
outputs = [a],
command = "echo 'test' > %s" % a.path,
)
b = ctx.actions.declare_file("dir/b")
ctx.actions.symlink(
output = b,
target_file = a,
)
return DefaultInfo(files = depset([
store_a,
store_b,
dep_symlink_b_to_a,
node_modules_a,
a,
b,
]))
node_modules_tree = rule(
implementation = impl,
)