wip preserve symlinks
This commit is contained in:
parent
43f8b3e524
commit
e8d14e8801
|
@ -1,5 +1,21 @@
|
||||||
# Edits mtree files. See the modify_mtree macro in /lib/tar.bzl.
|
# 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 (strip_prefix != "") {
|
||||||
if ($1 == strip_prefix) {
|
if ($1 == strip_prefix) {
|
||||||
# this line declares the directory which is now the root. It may be discarded.
|
# this line declares the directory which is now the root. It may be discarded.
|
||||||
|
|
|
@ -137,6 +137,8 @@ def tar(name, mtree = "auto", stamp = 0, **kwargs):
|
||||||
def mtree_mutate(
|
def mtree_mutate(
|
||||||
name,
|
name,
|
||||||
mtree,
|
mtree,
|
||||||
|
srcs = None,
|
||||||
|
preserve_symlinks = False,
|
||||||
strip_prefix = None,
|
strip_prefix = None,
|
||||||
package_dir = None,
|
package_dir = None,
|
||||||
mtime = None,
|
mtime = None,
|
||||||
|
@ -148,6 +150,8 @@ def mtree_mutate(
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: name of the target, output will be `[name].mtree`.
|
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`.
|
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.
|
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.
|
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.
|
owner: new uid for all entries.
|
||||||
ownername: new uname for all entries.
|
ownername: new uname for all entries.
|
||||||
awk_script: may be overridden to change the script containing the modification logic.
|
awk_script: may be overridden to change the script containing the modification logic.
|
||||||
|
|
||||||
**kwargs: additional named parameters to genrule
|
**kwargs: additional named parameters to genrule
|
||||||
"""
|
"""
|
||||||
vars = []
|
vars = []
|
||||||
|
@ -168,6 +173,10 @@ def mtree_mutate(
|
||||||
vars.append("-v owner='{}'".format(owner))
|
vars.append("-v owner='{}'".format(owner))
|
||||||
if ownername:
|
if ownername:
|
||||||
vars.append("-v ownername='{}'".format(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(
|
native.genrule(
|
||||||
name = name,
|
name = name,
|
||||||
|
|
|
@ -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("@aspect_bazel_lib//lib:testing.bzl", "assert_archive_contains")
|
||||||
load("@bazel_skylib//rules:write_file.bzl", "write_file")
|
load("@bazel_skylib//rules:write_file.bzl", "write_file")
|
||||||
load(":asserts.bzl", "assert_tar_listing", "assert_unused_listing")
|
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.
|
# The examples below work with both source files and generated files.
|
||||||
# Here we generate a file to use in the examples.
|
# 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",
|
"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 = [],
|
||||||
|
)
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
Loading…
Reference in New Issue