Skip to content

Commit f19799a

Browse files
authored
prepend_services argument for java_export (#9)
* initial 'prepend services' implementation add tests, remove un-needed lines add comments * initial 'prepend services' implementation add tests, remove un-needed lines add comments * remove System.out.println from MergeJars * match indentation a bit better * match indentation a bit better in MergeJars * trigger ci
1 parent 981a795 commit f19799a

File tree

4 files changed

+109
-4
lines changed

4 files changed

+109
-4
lines changed

private/rules/java_export.bzl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def java_export(
1717
tags = [],
1818
testonly = None,
1919
classifier_artifacts = {},
20+
prepend_services = None,
2021
**kwargs):
2122
"""Extends `java_library` to allow maven artifacts to be uploaded.
2223
@@ -76,6 +77,7 @@ def java_export(
7677
Each label must correspond to a direct maven dependency of this target.
7778
Each exclusion is represented as a `group:artifact` string.
7879
classifier_artifacts: A dict of classifier -> artifact of additional artifacts to publish to Maven.
80+
prepend_services: A file whose contents will be prepended to the generated `META-INF/services` files in the -project jar.
7981
doc_deps: Other `javadoc` targets that are referenced by the generated `javadoc` target
8082
(if not using `tags = ["no-javadoc"]`)
8183
doc_url: The URL at which the generated `javadoc` will be hosted (if not using
@@ -116,6 +118,7 @@ def java_export(
116118
testonly = testonly,
117119
javadocopts = javadocopts,
118120
classifier_artifacts = classifier_artifacts,
121+
prepend_services = prepend_services,
119122
doc_deps = doc_deps,
120123
doc_url = doc_url,
121124
toolchains = toolchains,
@@ -135,6 +138,7 @@ def maven_export(
135138
testonly = False,
136139
javadocopts = [],
137140
classifier_artifacts = {},
141+
prepend_services = None,
138142
*,
139143
doc_deps = [],
140144
doc_url = "",
@@ -195,6 +199,7 @@ def maven_export(
195199
exclusions: Mapping of target labels to a list of exclusions to be added to the POM file.
196200
Each label must correspond to a direct maven dependency of this target.
197201
Each exclusion is represented as a `group:artifact` string.
202+
prepend_services: A file whose contents will be prepended to the generated `META-INF/services` files in the -project jar.
198203
doc_deps: Other `javadoc` targets that are referenced by the generated `javadoc` target
199204
(if not using `tags = ["no-javadoc"]`)
200205
doc_url: The URL at which the generated `javadoc` will be hosted (if not using
@@ -227,6 +232,7 @@ def maven_export(
227232
deploy_env = deploy_env,
228233
excluded_workspaces = excluded_workspaces.keys(),
229234
additional_dependencies = additional_dependencies,
235+
prepend_services = prepend_services,
230236
visibility = visibility,
231237
tags = tags + maven_coordinates_tags,
232238
testonly = testonly,

private/rules/maven_project_jar.bzl

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,21 @@ def _strip_excluded_workspace_jars(jar_files, excluded_workspaces):
3131

3232
return to_return
3333

34-
def _combine_jars(ctx, merge_jars, inputs, excludes, output):
34+
def _combine_jars(ctx, merge_jars, inputs, excludes, output, prepend_services = None):
3535
args = ctx.actions.args()
3636
args.add("--output", output)
3737
args.add_all(inputs, before_each = "--sources")
3838
args.add_all(excludes, before_each = "--exclude")
39+
deps = [inputs, excludes]
40+
41+
if prepend_services:
42+
prepend_services = prepend_services.files.to_list()[0]
43+
args.add("--prepend_services", prepend_services)
44+
deps.append(depset([prepend_services]))
3945

4046
ctx.actions.run(
4147
mnemonic = "MergeJars",
42-
inputs = depset(transitive = [inputs, excludes]),
48+
inputs = depset(transitive = deps),
4349
outputs = [output],
4450
executable = merge_jars,
4551
arguments = [args],
@@ -76,6 +82,7 @@ def _maven_project_jar_impl(ctx):
7682
[ji.transitive_runtime_jars for ji in info.dep_infos.to_list()] +
7783
[jar[JavaInfo].transitive_runtime_jars for jar in ctx.attr.deploy_env]),
7884
intermediate_jar,
85+
prepend_services = ctx.attr.prepend_services,
7986
)
8087

8188
# Add manifest lines if necessary
@@ -123,6 +130,7 @@ def _maven_project_jar_impl(ctx):
123130
[ji.transitive_source_jars for ji in info.dep_infos.to_list()] +
124131
[jar[JavaInfo].transitive_source_jars for jar in ctx.attr.deploy_env]),
125132
src_jar,
133+
prepend_services = ctx.attr.prepend_services,
126134
)
127135

128136
java_toolchain = ctx.attr._java_toolchain[java_common.JavaToolchainInfo]
@@ -212,6 +220,11 @@ single artifact that other teams can download and use.
212220
[JavaInfo],
213221
],
214222
),
223+
"prepend_services": attr.label(
224+
doc = "A file whose contents will be prepended to the generated `META-INF/services` files in the -project jar.",
225+
default = None,
226+
allow_single_file = True,
227+
),
215228
"_add_jar_manifest_entry": attr.label(
216229
executable = True,
217230
cfg = "exec",

private/tools/java/com/github/bazelbuild/rules_jvm_external/jar/MergeJars.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
import java.nio.file.Paths;
3434
import java.security.MessageDigest;
3535
import java.security.NoSuchAlgorithmException;
36+
import java.util.ArrayList;
3637
import java.util.Arrays;
3738
import java.util.HashMap;
3839
import java.util.HashSet;
3940
import java.util.LinkedHashSet;
41+
import java.util.List;
4042
import java.util.Map;
4143
import java.util.Objects;
4244
import java.util.Set;
@@ -45,6 +47,7 @@
4547
import java.util.jar.Attributes;
4648
import java.util.jar.JarOutputStream;
4749
import java.util.jar.Manifest;
50+
import java.util.stream.Collectors;
4851
import java.util.zip.ZipEntry;
4952
import java.util.zip.ZipFile;
5053
import java.util.zip.ZipInputStream;
@@ -53,6 +56,7 @@ public class MergeJars {
5356

5457
public static void main(String[] args) throws IOException {
5558
Path out = null;
59+
Path prependServices = null;
5660
// Insertion order may matter
5761
Set<Path> sources = new LinkedHashSet<>();
5862
Set<Path> excludes = new HashSet<>();
@@ -81,6 +85,11 @@ public static void main(String[] args) throws IOException {
8185
sources.add(isValid(Paths.get(args[++i])));
8286
break;
8387

88+
case "--prepend_services":
89+
isValid(Paths.get(args[++i]));
90+
prependServices = Paths.get(args[i]);
91+
break;
92+
8493
default:
8594
throw new IllegalArgumentException(
8695
"Unable to parse command line: " + Arrays.toString(args));
@@ -142,7 +151,12 @@ public static void main(String[] args) throws IOException {
142151
Set<String> services =
143152
allServices.computeIfAbsent(servicesName, key -> new TreeSet<>());
144153
String content = new String(ByteStreams.toByteArray(zis));
145-
services.addAll(Arrays.asList(content.split("\n")));
154+
List<String> commentsRemoved = Arrays
155+
.stream(content.split("\n"))
156+
.filter(l -> !l.trim().startsWith("#"))
157+
.filter(l -> !l.isEmpty())
158+
.collect(Collectors.toList());
159+
services.addAll(commentsRemoved);
146160
continue;
147161
}
148162

@@ -207,7 +221,17 @@ public static void main(String[] args) throws IOException {
207221
for (Map.Entry<String, Set<String>> kv : allServices.entrySet()) {
208222
entry = new StableZipEntry("META-INF/services/" + kv.getKey());
209223
bos = new ByteArrayOutputStream();
210-
bos.write(String.join("\n", kv.getValue()).getBytes());
224+
List<String> toWrite = new ArrayList<>();
225+
226+
if (prependServices != null) {
227+
String prepend = Files.readString(prependServices);
228+
toWrite.addAll(Arrays.asList(prepend.split("\n")));
229+
toWrite.add("");
230+
}
231+
232+
toWrite.addAll(kv.getValue());
233+
bos.write(String.join("\n", toWrite).getBytes());
234+
bos.write("\n".getBytes());
211235
entry.setSize(bos.size());
212236
jos.putNextEntry(entry);
213237
jos.write(bos.toByteArray());

tests/com/github/bazelbuild/rules_jvm_external/jar/MergeJarsTest.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,68 @@ public void mergedJarManifestSpecialAttributesAreHandled() throws IOException {
553553
}
554554
}
555555

556+
@Test
557+
public void mergedJarServiceProviderFileRemovesCommentLines() throws IOException {
558+
Path inputOne = temp.newFile("one.jar").toPath();
559+
createJar(
560+
inputOne,
561+
ImmutableMap.of("META-INF/services/com.example.ServiceProvider", "# This is a comment")
562+
);
563+
564+
Path inputTwo = temp.newFile("two.jar").toPath();
565+
createJar(
566+
inputTwo,
567+
ImmutableMap.of("META-INF/services/com.example.ServiceProvider", "com.example.Foo")
568+
);
569+
570+
Path outputJar = temp.newFile("out.jar").toPath();
571+
572+
MergeJars.main(
573+
new String[] {
574+
"--output", outputJar.toAbsolutePath().toString(),
575+
"--sources", inputOne.toAbsolutePath().toString(),
576+
"--sources", inputTwo.toAbsolutePath().toString(),
577+
});
578+
579+
Map<String, String> contents = readJar(outputJar);
580+
581+
assertEquals("com.example.Foo\n", contents.get("META-INF/services/com.example.ServiceProvider"));
582+
}
583+
584+
@Test
585+
public void mergedJarServiceProviderFilePrependsLines() throws IOException {
586+
Path inputOne = temp.newFile("one.jar").toPath();
587+
createJar(
588+
inputOne,
589+
ImmutableMap.of("META-INF/services/com.example.ServiceProvider", "# This is a comment")
590+
);
591+
592+
Path inputTwo = temp.newFile("two.jar").toPath();
593+
createJar(
594+
inputTwo,
595+
ImmutableMap.of("META-INF/services/com.example.ServiceProvider", "com.example.Foo")
596+
);
597+
598+
String prepend = "# This is a LICENSE\n # It should be kept\n";
599+
Path inputThree = temp.newFile("LICENSE").toPath();
600+
Files.write(inputThree, prepend.getBytes(UTF_8));
601+
602+
Path outputJar = temp.newFile("out.jar").toPath();
603+
604+
MergeJars.main(
605+
new String[] {
606+
"--output", outputJar.toAbsolutePath().toString(),
607+
"--sources", inputOne.toAbsolutePath().toString(),
608+
"--sources", inputTwo.toAbsolutePath().toString(),
609+
"--prepend_services", inputThree.toAbsolutePath().toString(),
610+
}
611+
);
612+
613+
Map<String, String> contents = readJar(outputJar);
614+
615+
assertEquals(prepend + "\ncom.example.Foo\n", contents.get("META-INF/services/com.example.ServiceProvider"));
616+
}
617+
556618
private void createJar(Path outputTo, Map<String, String> pathToContents) throws IOException {
557619
try (OutputStream os = Files.newOutputStream(outputTo);
558620
ZipOutputStream zos = new ZipOutputStream(os)) {

0 commit comments

Comments
 (0)