Skip to content

Commit f25010c

Browse files
authored
fix: correctly track treeartifact contents (#2217)
1 parent c7cdcdd commit f25010c

File tree

3 files changed

+62
-77
lines changed

3 files changed

+62
-77
lines changed

js/private/js_image_layer.bzl

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ _DEFAULT_LAYER_GROUPS = {
2626

2727
_DOC = """Create container image layers from js_binary targets.
2828
29-
By design, js_image_layer doesn't have any preference over which rule assembles the container image.
29+
By design, js_image_layer doesn't have any preference over which rule assembles the container image.
3030
This means the downstream rule (`oci_image` from [rules_oci](https://github.com/bazel-contrib/rules_oci)
3131
or `container_image` from [rules_docker](https://github.com/bazelbuild/rules_docker)) must
3232
set a proper `workdir` and `cmd` to for the container work.
@@ -264,7 +264,7 @@ container_image(
264264
```
265265
266266
267-
## Performance
267+
## Performance
268268
269269
For better performance, it is recommended to split the large parts of a `js_binary` to have a separate layer.
270270
@@ -436,7 +436,7 @@ def _to_rlocation_path(file, workspace):
436436
def _repo_mapping_manifest(files_to_run):
437437
return getattr(files_to_run, "repo_mapping_manifest", None)
438438

439-
_ENTRY = '"%s":{"dest":%s,"root":"%s","is_external":%s,"is_source":%s,"is_directory":%s,"repo_name":"%s"},\n%s:"%s"'
439+
_ENTRY = '"%s":{"dest":%s,"root":"%s","is_external":%s,"is_source":%s,"repo_name":"%s"},\n%s:"%s"'
440440

441441
def _js_image_layer_impl(ctx):
442442
if ctx.attr.generate_empty_layers:
@@ -464,22 +464,47 @@ def _js_image_layer_impl(ctx):
464464

465465
# be careful about what you access outside of the function closure. accessing objects
466466
# such as ctx within this function will make it significantly slower.
467-
def map_entry(f, _):
467+
def map_entry(f, expander):
468468
runfiles_dest = runfiles_dir + "/" + _to_rlocation_path(f, workspace_name)
469469
path = json.encode(f.path)
470-
return _ENTRY % (
471-
runfiles_dest,
472-
path,
473-
f.root.path,
474-
"true" if f.owner.repo_name != "" else "false",
475-
"true" if f.is_source else "false",
476-
"true" if f.is_directory else "false",
477-
f.owner.repo_name,
478-
# To avoid O(N ^ N) complexity when searching for entries by their destination
479-
# the map also has to have entries by their path on bazel-out,
480-
path,
481-
runfiles_dest,
482-
)
470+
if not f.is_directory:
471+
return _ENTRY % (
472+
runfiles_dest,
473+
path,
474+
f.root.path,
475+
"true" if f.owner.repo_name != "" else "false",
476+
"true" if f.is_source else "false",
477+
f.owner.repo_name,
478+
# To avoid O(N ^ N) complexity when searching for entries by their destination
479+
# the map also has to have entries by their path on bazel-out,
480+
path,
481+
runfiles_dest,
482+
)
483+
else:
484+
# Directory expansion needs to happen during execution phase to
485+
# correctly track the contents of the treeartifact.
486+
tree = expander.expand(f)
487+
contents = ""
488+
for f in tree:
489+
# only add command after first iteration.
490+
if contents:
491+
contents += ","
492+
493+
runfiles_dest = runfiles_dest + f.tree_relative_path
494+
path = path + f.tree_relative_path
495+
contents += _ENTRY % (
496+
runfiles_dest,
497+
path,
498+
f.root.path,
499+
"true" if f.owner.repo_name != "" else "false",
500+
"true" if f.is_source else "false",
501+
f.owner.repo_name,
502+
# To avoid O(N ^ N) complexity when searching for entries by their destination
503+
# the map also has to have entries by their path on bazel-out,
504+
path,
505+
runfiles_dest,
506+
)
507+
return contents
483508

484509
entries = ctx.actions.args()
485510
entries.set_param_file_format("multiline")
@@ -492,7 +517,7 @@ def _js_image_layer_impl(ctx):
492517
)
493518
entries.add_all(
494519
runfiles_plus_files,
495-
expand_directories = False,
520+
expand_directories = True,
496521
map_each = map_entry,
497522
allow_closure = True,
498523
before_each = ",",
@@ -638,8 +663,8 @@ By default symlinks within the `node_modules` is preserved.
638663
),
639664
"layer_groups": attr.string_dict(
640665
doc = """Layer groups to create.
641-
These are utilized to categorize files into distinct layers, determined by their respective paths.
642-
The expected format for each entry is "<key>": "<value>", where <key> MUST be a valid Bazel and
666+
These are utilized to categorize files into distinct layers, determined by their respective paths.
667+
The expected format for each entry is "<key>": "<value>", where <key> MUST be a valid Bazel and
643668
JavaScript identifier (alphanumeric characters), and <value> MAY be either an empty string (signifying a universal match)
644669
or a valid regular expression.""",
645670
),

js/private/js_image_layer.mjs

Lines changed: 2 additions & 57 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/private/test/image/BUILD.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@aspect_bazel_lib//lib:transitions.bzl", "platform_transition_filegroup")
12
load("@npm//:defs.bzl", "npm_link_all_packages")
23
load("//js:defs.bzl", "js_binary")
34
load(":asserts.bzl", "assert_checksum", "assert_js_image_layer_listings", "make_js_image_layer")
@@ -107,3 +108,17 @@ assert_js_image_layer_listings(
107108
name = "custom_layers_nomatch_test",
108109
js_image_layer = ":custom_layers_nomatch",
109110
)
111+
112+
# Case 5: transition the edge instead of just the binary
113+
# bazel run :custom_owner_test_update_all
114+
make_js_image_layer(
115+
name = "js_image_layer_untransitioned",
116+
binary = ":bin",
117+
)
118+
119+
platform_transition_filegroup(
120+
name = "transition_js_image_layer",
121+
testonly = True,
122+
srcs = [":js_image_layer_untransitioned"],
123+
target_platform = ":linux_amd64",
124+
)

0 commit comments

Comments
 (0)