Skip to content

Commit ba60c0b

Browse files
liucijuscopybara-github
authored andcommitted
ijar: fix manifest sections handling
Fixes bazelbuild#12730 Important changes: - removed line stripping from the original implementation - label/rule attributes are appended after main attributes, then the rest of the `MANIFEST.MF` content is appended - this way sections data is preserved. Closes bazelbuild#12771. PiperOrigin-RevId: 354909855
1 parent 165c1a0 commit ba60c0b

File tree

4 files changed

+175
-6
lines changed

4 files changed

+175
-6
lines changed

third_party/ijar/ijar.cc

+15-6
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,10 @@ u1 *JarCopierProcessor::AppendTargetLabelToManifest(
302302
const char *target_label, const char *injecting_rule_kind) {
303303
const char *line_start = (const char *)manifest_data;
304304
const char *data_end = (const char *)manifest_data + size;
305-
while (line_start < data_end) {
305+
306+
// Write main attributes part
307+
while (line_start < data_end && line_start[0] != '\r' &&
308+
line_start[0] != '\n') {
306309
const char *line_end = strchr(line_start, '\n');
307310
// Go past return char to point to next line, or to end of data buffer
308311
line_end = line_end != nullptr ? line_end + 1 : data_end;
@@ -313,18 +316,24 @@ u1 *JarCopierProcessor::AppendTargetLabelToManifest(
313316
strncmp(line_start, INJECTING_RULE_KIND_KEY,
314317
INJECTING_RULE_KIND_KEY_LENGTH) != 0) {
315318
size_t len = line_end - line_start;
316-
// Skip empty lines
317-
if (len > 0 && line_start[0] != '\r' && line_start[0] != '\n') {
318-
memcpy(buf, line_start, len);
319-
buf += len;
320-
}
319+
memcpy(buf, line_start, len);
320+
buf += len;
321321
}
322322
line_start = line_end;
323323
}
324+
325+
// Append target label and, if given, rule kind
324326
buf = WriteManifestAttr(buf, TARGET_LABEL_KEY, target_label);
325327
if (injecting_rule_kind != nullptr) {
326328
buf = WriteManifestAttr(buf, INJECTING_RULE_KIND_KEY, injecting_rule_kind);
327329
}
330+
331+
// Write the rest of the manifest file
332+
size_t sections_len = data_end - line_start;
333+
if (sections_len > 0) {
334+
memcpy(buf, line_start, sections_len);
335+
buf += sections_len;
336+
}
328337
return buf;
329338
}
330339

third_party/ijar/test/BUILD

+45
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,24 @@ genrule(
144144
tools = ["//third_party/ijar"],
145145
)
146146

147+
genrule(
148+
name = "jar_with_manifest_sections_nostrip",
149+
testonly = 1,
150+
srcs = [":jar_with_manifest_sections"],
151+
outs = ["jar-with-manifest-sections-nostrip.jar"],
152+
cmd = "$(location //third_party/ijar) --target_label //foo:foo --nostrip_jar $< $@",
153+
tools = ["//third_party/ijar"],
154+
)
155+
156+
genrule(
157+
name = "jar_with_target_label_and_manifest_sections_nostrip",
158+
testonly = 1,
159+
srcs = [":jar_with_target_label_and_manifest_sections"],
160+
outs = ["jar-with-target-label-and-manifest-sections-nostrip.jar"],
161+
cmd = "$(location //third_party/ijar) --target_label //foo:foo --nostrip_jar $< $@",
162+
tools = ["//third_party/ijar"],
163+
)
164+
147165
genrule(
148166
name = "jar_without_manifest_nostrip_idempotence",
149167
srcs = ["jar-without-manifest-nostrip.jar"],
@@ -292,6 +310,30 @@ genrule(
292310
tools = ["//third_party/ijar"],
293311
)
294312

313+
java_binary(
314+
name = "GenJarWithManifestSections",
315+
testonly = 1,
316+
srcs = ["GenJarWithManifestSections.java"],
317+
main_class = "GenJarWithManifestSections",
318+
deps = ["//third_party:guava"],
319+
)
320+
321+
genrule(
322+
name = "jar_with_manifest_sections",
323+
testonly = 1,
324+
outs = ["jar-with-manifest-sections.jar"],
325+
cmd = "$(location :GenJarWithManifestSections) $@",
326+
tools = [":GenJarWithManifestSections"],
327+
)
328+
329+
genrule(
330+
name = "jar_with_target_label_and_manifest_sections",
331+
testonly = 1,
332+
outs = ["jar-with-target-label-and-manifest-sections.jar"],
333+
cmd = "$(location :GenJarWithManifestSections) $@ //not:this",
334+
tools = [":GenJarWithManifestSections"],
335+
)
336+
295337
java_test(
296338
name = "IjarTests",
297339
size = "small",
@@ -305,6 +347,7 @@ java_test(
305347
"UseRestrictedAnnotation.java",
306348
"jar-with-manifest.jar",
307349
"jar-with-manifest-and-target-label.jar",
350+
"jar-with-manifest-sections.jar",
308351
"jar-without-manifest.jar",
309352
"package-info.java",
310353
":empty_with_target_label",
@@ -314,6 +357,8 @@ java_test(
314357
":interface_ijar_testlib_with_target_label",
315358
":jar_with_manifest_and_target_label_nostrip",
316359
":jar_with_manifest_nostrip",
360+
":jar_with_manifest_sections_nostrip",
361+
":jar_with_target_label_and_manifest_sections_nostrip",
317362
":jar_without_manifest_nostrip",
318363
":jar_without_manifest_nostrip_idempotence",
319364
":kotlin_module-interface.jar",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2021 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import com.google.common.io.ByteStreams;
16+
import java.io.IOException;
17+
import java.nio.file.Files;
18+
import java.nio.file.Paths;
19+
import java.util.Map;
20+
import java.util.jar.Attributes;
21+
import java.util.jar.JarOutputStream;
22+
import java.util.jar.Manifest;
23+
import java.util.zip.ZipEntry;
24+
25+
/** Writes a jar file with manifest and optionally a Target-Label attribute. */
26+
public final class GenJarWithManifestSections {
27+
28+
public static void main(String[] args) throws IOException {
29+
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(Paths.get(args[0])))) {
30+
addEntry(jos, "META-INF/MANIFEST.MF");
31+
Manifest manifest = new Manifest();
32+
Attributes mainAttributes = manifest.getMainAttributes();
33+
mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
34+
35+
if (args.length > 1) {
36+
String targetLabel = args[1];
37+
mainAttributes.put(new Attributes.Name("Target-Label"), targetLabel);
38+
}
39+
40+
Map<String, Attributes> entries = manifest.getEntries();
41+
42+
Attributes foo = new Attributes();
43+
foo.put(new Attributes.Name("Foo"), "bar");
44+
entries.put("foo", foo);
45+
46+
Attributes baz = new Attributes();
47+
baz.put(new Attributes.Name("Another"), "bar");
48+
entries.put("baz", baz);
49+
50+
manifest.write(jos);
51+
52+
addEntry(jos, "java/lang/String.class");
53+
ByteStreams.copy(String.class.getResourceAsStream("/java/lang/String.class"), jos);
54+
}
55+
}
56+
57+
private static void addEntry(JarOutputStream jos, String name) throws IOException {
58+
ZipEntry ze = new ZipEntry(name);
59+
ze.setTime(0);
60+
jos.putNextEntry(ze);
61+
}
62+
63+
private GenJarWithManifestSections() {}
64+
}

third_party/ijar/test/IjarTests.java

+51
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,57 @@ public void testNoStripJarWithoutManifest() throws Exception {
399399
}
400400
}
401401

402+
@Test
403+
public void testPreserveManifestSections() throws Exception {
404+
try (JarFile original =
405+
new JarFile(
406+
"third_party/ijar/test/jar-with-target-label-and-manifest-sections-nostrip.jar");
407+
JarFile stripped =
408+
new JarFile("third_party/ijar/test/jar-with-manifest-sections-nostrip.jar")) {
409+
ImmutableList<String> strippedEntries =
410+
stripped.stream().map(JarEntry::getName).collect(toImmutableList());
411+
412+
assertThat(strippedEntries.get(0)).isEqualTo("META-INF/");
413+
assertThat(strippedEntries.get(1)).isEqualTo("META-INF/MANIFEST.MF");
414+
Manifest manifest = stripped.getManifest();
415+
Attributes attributes = manifest.getMainAttributes();
416+
assertThat(attributes.getValue("Target-Label")).isEqualTo("//foo:foo");
417+
assertNonManifestFilesBitIdentical(original, stripped);
418+
419+
Attributes sectionAttributes1 = manifest.getAttributes("foo");
420+
assertThat(sectionAttributes1.getValue("Foo")).isEqualTo("bar");
421+
422+
Attributes sectionAttributes2 = manifest.getAttributes("baz");
423+
assertThat(sectionAttributes2.getValue("Another")).isEqualTo("bar");
424+
}
425+
}
426+
427+
@Test
428+
public void testPreserveManifestSectionsAndUpdateExistingTargetLabel() throws Exception {
429+
try (JarFile original =
430+
new JarFile(
431+
"third_party/ijar/test/jar-with-target-label-and-manifest-sections-nostrip.jar");
432+
JarFile stripped =
433+
new JarFile(
434+
"third_party/ijar/test/jar-with-target-label-and-manifest-sections-nostrip.jar")) {
435+
ImmutableList<String> strippedEntries =
436+
stripped.stream().map(JarEntry::getName).collect(toImmutableList());
437+
438+
assertThat(strippedEntries.get(0)).isEqualTo("META-INF/");
439+
assertThat(strippedEntries.get(1)).isEqualTo("META-INF/MANIFEST.MF");
440+
Manifest manifest = stripped.getManifest();
441+
Attributes attributes = manifest.getMainAttributes();
442+
assertThat(attributes.getValue("Target-Label")).isEqualTo("//foo:foo");
443+
assertNonManifestFilesBitIdentical(original, stripped);
444+
445+
Attributes sectionAttributes1 = manifest.getAttributes("foo");
446+
assertThat(sectionAttributes1.getValue("Foo")).isEqualTo("bar");
447+
448+
Attributes sectionAttributes2 = manifest.getAttributes("baz");
449+
assertThat(sectionAttributes2.getValue("Another")).isEqualTo("bar");
450+
}
451+
}
452+
402453
// Tests idempotence of --nostrip
403454
@Test
404455
public void testNoStripIdempotence() throws Exception {

0 commit comments

Comments
 (0)