@@ -154,6 +154,13 @@ def _group_artifacts(artifact_ids, max_groups):
154154 # max_groups is 0: no artifact layers at all.
155155 return []
156156
157+ # Non-maven layer slots: the data-runfiles tar and the fallback tar.
158+ _EXTRA_LAYER_SLOTS = 2
159+
160+ def jvm_jar_layer_slots (max_layers ):
161+ """Number of `<name>.layer_N` filegroups emitted for a given max_layers."""
162+ return max_layers + _EXTRA_LAYER_SLOTS
163+
157164def jvm_jar_layers (
158165 name ,
159166 binary ,
@@ -172,6 +179,13 @@ def jvm_jar_layers(
172179 The container classpath uses Java's @file syntax to reference a classpath
173180 file listing all JARs.
174181
182+ Because the number and names of the layer tars are only known at analysis
183+ time, each tar is also exposed through a fixed-name `<name>.layer_N`
184+ filegroup (N in range(jvm_jar_layer_slots(max_layers))) so image rules can
185+ map each tar to its own image layer. Slots beyond the produced tar count
186+ are padded with empty tars, which compress to byte-identical, deduplicable
187+ layer blobs.
188+
175189 Args:
176190 name: target name
177191 binary: label of a java_binary or scala_binary target
@@ -201,6 +215,13 @@ def jvm_jar_layers(
201215 ** kwargs
202216 )
203217
218+ for index in range (jvm_jar_layer_slots (max_layers )):
219+ native .filegroup (
220+ name = "%s.layer_%d" % (name , index ),
221+ srcs = [name ],
222+ output_group = "layer_%d" % index ,
223+ )
224+
204225def _jvm_jar_layers_impl (ctx ):
205226 runtime_jars = _runtime_jars (ctx .attr .binary )
206227 if not runtime_jars :
@@ -289,6 +310,14 @@ def _jvm_jar_layers_impl(ctx):
289310 args .add ("--artifact_group_layer" , "," .join (group_ids ) + "=" + group_out .path )
290311 tar_outputs .append (group_out )
291312
313+ # Pad remaining slots with empty tars so every layer_N output group (and
314+ # its filegroup) yields exactly one tar file — image rules typically reject
315+ # labels that produce no tar.
316+ for index in range (len (tar_outputs ), jvm_jar_layer_slots (ctx .attr .max_layers )):
317+ pad = ctx .actions .declare_file (ctx .label .name + ".pad_%d.tar" % index )
318+ args .add ("--pad_layer" , pad )
319+ tar_outputs .append (pad )
320+
292321 ctx .actions .run (
293322 inputs = inputs ,
294323 outputs = tar_outputs + [classpath_file ],
@@ -300,11 +329,14 @@ def _jvm_jar_layers_impl(ctx):
300329
301330 # DefaultInfo only includes tar files — the classpath file is a plain text
302331 # file and must not be passed to container_image's tars attribute.
332+ output_groups = {"classpath" : depset ([classpath_file ])}
333+ for index in range (jvm_jar_layer_slots (ctx .attr .max_layers )):
334+ files = [tar_outputs [index ]] if index < len (tar_outputs ) else []
335+ output_groups ["layer_%d" % index ] = depset (files )
336+
303337 return [
304338 DefaultInfo (files = depset (tar_outputs )),
305- OutputGroupInfo (
306- classpath = depset ([classpath_file ]),
307- ),
339+ OutputGroupInfo (** output_groups ),
308340 ]
309341
310342_jvm_jar_layers = rule (
0 commit comments