Skip to content

Commit

Permalink
Index service implementations as well as packages
Browse files Browse the repository at this point in the history
This can be useful for detecting things like annotation processors, and
knowing whether a target represents a java_plugin or just a
java_library.
  • Loading branch information
illicitonion committed Feb 29, 2024
1 parent f5706d4 commit b61cc1a
Show file tree
Hide file tree
Showing 15 changed files with 376 additions and 39 deletions.
21 changes: 21 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,14 @@ dev_maven.install(
],
)

dev_maven.install(
name = "service_indexing_testing",
artifacts = [
"org.projectlombok:lombok:1.18.22",
],
lock_file = "//tests/custom_maven_install:service_indexing_testing.json",
)

dev_maven.install(
name = "jvm_import_test",
artifacts = [
Expand Down Expand Up @@ -647,6 +655,10 @@ use_repo(
"json_artifacts_testing",
"unpinned_json_artifacts_testing",

# Pinned repo
"service_indexing_testing",
"unpinned_service_indexing_testing",

# Unpinned repo
"jvm_import_test",
"manifest_stamp_testing",
Expand Down Expand Up @@ -760,3 +772,12 @@ http_file(
"https://repo1.maven.org/maven2/com/google/apis/google-api-services-compute/v1-rev235-1.25.0/google-api-services-compute-v1-rev235-1.25.0-javadoc.jar",
],
)

http_file(
name = "lombok_for_test",
downloaded_file_path = "lombok-1.18.22.jar",
sha256 = "ecef1581411d7a82cc04281667ee0bac5d7c0a5aae74cfc38430396c91c31831",
urls = [
"https://repo1.maven.org/maven2/org/projectlombok/lombok/1.18.22/lombok-1.18.22.jar",
],
)
17 changes: 17 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,14 @@ maven_install(
],
)

maven_install(
name = "service_indexing_testing",
artifacts = [
"org.projectlombok.lombok:1.18.22",
],
lock_file = "//tests/custom_maven_install:service_indexing_testing.json"
)

maven_install(
name = "jvm_import_test",
artifacts = [
Expand Down Expand Up @@ -680,6 +688,15 @@ http_file(
],
)

http_file(
name = "lombok_for_test",
downloaded_file_path = "lombok-1.18.22.jar",
sha256 = "ecef1581411d7a82cc04281667ee0bac5d7c0a5aae74cfc38430396c91c31831",
urls = [
"https://repo1.maven.org/maven2/org/projectlombok/lombok/1.18.22/lombok-1.18.22.jar",
],
)

# End test dependencies

http_archive(
Expand Down
3 changes: 3 additions & 0 deletions coursier.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,9 @@ def _coursier_fetch_impl(repository_ctx):
continue
artifact.update({"sha256": shas[path]})
artifact.update({"packages": jars_to_index_results[path]["packages"]})
service_implementations = jars_to_index_results[path]["serviceImplementations"]
if service_implementations:
artifact.update({"services": service_implementations})

# Keep the original output from coursier for debugging
repository_ctx.file(
Expand Down
1 change: 1 addition & 0 deletions maven_install.json
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@
"org.objectweb.asm.signature"
]
},
"services": {},
"repositories": {
"https://repo1.maven.org/maven2/": [
"com.google.auto.value:auto-value-annotations",
Expand Down
1 change: 1 addition & 0 deletions private/rules/v2_lock_file.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ def _render_lock_file(lock_file_contents, input_hash):
if lock_file_contents.get("skipped"):
contents.append(" \"skipped\": %s," % json.encode_indent(lock_file_contents["skipped"], prefix = " ", indent = " "))
contents.append(" \"packages\": %s," % json.encode_indent(lock_file_contents["packages"], prefix = " ", indent = " "))
contents.append(" \"services\": %s," % json.encode_indent(lock_file_contents["services"], prefix = " ", indent = " "))
if lock_file_contents.get("m2local"):
contents.append(" \"m2local\": true,")
contents.append(" \"repositories\": {")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -165,14 +168,21 @@ public Set<DependencyInfo> getDependencies() {
packages = new TreeSet<>(depPackages);
}

SortedMap<String, SortedSet<String>> services = new TreeMap<>();
Object rawServices = coursierDep.get("services");
if (rawServices != null) {
services = new TreeMap<>((Map<String, SortedSet<String>>) rawServices);
}

toReturn.add(
new DependencyInfo(
coords,
repos,
file == null ? null : Paths.get(file),
(String) coursierDep.get("sha256"),
directDeps,
packages));
packages,
services));
}

return toReturn;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
Expand All @@ -27,6 +28,7 @@ public Map<String, Object> render(Set<DependencyInfo> infos, Map<String, Object>
Map<String, Map<String, Object>> artifacts = new TreeMap<>();
Map<String, Set<String>> deps = new TreeMap<>();
Map<String, Set<String>> packages = new TreeMap<>();
Map<String, Map<String, SortedSet<String>>> services = new TreeMap<>();
Map<String, Set<String>> repos = new LinkedHashMap<>();
repositories.forEach(r -> repos.put(stripAuthenticationInformation(r), new TreeSet<>()));

Expand Down Expand Up @@ -83,6 +85,7 @@ public Map<String, Object> render(Set<DependencyInfo> infos, Map<String, Object>
.map(Object::toString)
.collect(Collectors.toCollection(TreeSet::new)));
packages.put(key, info.getPackages());
services.put(key, info.getServices());

if (info.getPath() != null) {
// Regularise paths to UNIX format
Expand All @@ -94,6 +97,7 @@ public Map<String, Object> render(Set<DependencyInfo> infos, Map<String, Object>
lock.put("artifacts", artifacts);
lock.put("dependencies", removeEmptyItems(deps));
lock.put("packages", removeEmptyItems(packages));
lock.put("services", removeEmptyItemsMap(services));
if (isUsingM2Local) {
lock.put("m2local", true);
}
Expand Down Expand Up @@ -124,6 +128,20 @@ private <K, V extends Collection> Map<K, V> removeEmptyItems(Map<K, V> input) {
TreeMap::new));
}

private <K, VK, VV> Map<K, Map<VK, VV>> removeEmptyItemsMap(Map<K, Map<VK, VV>> input) {
return input.entrySet().stream()
.filter(e -> !e.getValue().isEmpty())
.collect(
Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(l, r) -> {
l.putAll(r);
return l;
},
TreeMap::new));
}

private String stripAuthenticationInformation(String possibleUri) {
try {
URI uri = new URI(possibleUri);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package com.github.bazelbuild.rules_jvm_external.jar;

import com.google.gson.Gson;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
Expand All @@ -18,23 +23,31 @@
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipFile;

public class IndexJar {

private static final Predicate<String> IS_NUMERIC_VERSION =
Pattern.compile("[1-9][0-9]*").asPredicate();

private static final String SERVICES_DIRECTORY_PREFIX = "META-INF/services/";

public static class PerJarIndexResults {
private final SortedSet<String> packages;
private final SortedMap<String, SortedSet<String>> serviceImplementations;

public PerJarIndexResults(SortedSet<String> packages) {
public PerJarIndexResults(SortedSet<String> packages, SortedMap<String, SortedSet<String>> serviceImplementations) {
this.packages = packages;
this.serviceImplementations = serviceImplementations;
}

public SortedSet<String> getPackages() {
return this.packages;
}

public SortedMap<String, SortedSet<String>> getServiceImplementations() {
return this.serviceImplementations;
}
}

public static void main(String[] args) throws IOException {
Expand Down Expand Up @@ -68,11 +81,26 @@ public static void main(String[] args) throws IOException {

public static PerJarIndexResults index(Path path) throws IOException {
SortedSet<String> packages = new TreeSet<>();
try (InputStream fis = new BufferedInputStream(Files.newInputStream(path));
ZipInputStream zis = new ZipInputStream(fis)) {
try {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
SortedMap<String, SortedSet<String>> serviceImplementations = new TreeMap<>();
try {
try (ZipFile zipFile = new ZipFile(path.toFile())) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (entry.getName().startsWith(SERVICES_DIRECTORY_PREFIX) && !SERVICES_DIRECTORY_PREFIX.equals(entry.getName())) {
String serviceInterface = entry.getName().substring(SERVICES_DIRECTORY_PREFIX.length());
SortedSet<String> implementingClasses = new TreeSet<>();
try (InputStream inputStream = zipFile.getInputStream(entry) ; BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream) ; BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream))) {
String implementingClass = bufferedReader.readLine();
while (implementingClass != null) {
if (!implementingClass.isEmpty() && !implementingClass.startsWith("#")) {
implementingClasses.add(implementingClass);
}
implementingClass = bufferedReader.readLine();
}
}
serviceImplementations.put(serviceInterface, implementingClasses);
}
if (!entry.getName().endsWith(".class")) {
continue;
}
Expand All @@ -82,11 +110,11 @@ public static PerJarIndexResults index(Path path) throws IOException {
}
packages.add(extractPackageName(entry.getName()));
}
} catch (ZipException e) {
System.err.printf("Caught ZipException: %s%n", e);
}
} catch (ZipException e) {
System.err.printf("Caught ZipException: %s%n", e);
}
return new PerJarIndexResults(packages);
return new PerJarIndexResults(packages, serviceImplementations);
}

private static String extractPackageName(String zipEntryName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import java.nio.file.Path;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeSet;

public class DependencyInfo {
Expand All @@ -16,21 +18,24 @@ public class DependencyInfo {
private final String sha256;
private final Set<Coordinates> dependencies;
private final Set<String> packages;
private final SortedMap<String, SortedSet<String>> services;

public DependencyInfo(
Coordinates coordinates,
Set<URI> repos,
Path path,
String sha256,
Set<Coordinates> dependencies,
Set<String> packages) {
Set<String> packages,
SortedMap<String, SortedSet<String>> services) {
this.coordinates = coordinates;
this.repos = ImmutableSet.copyOf(repos);
this.path = path;
this.sha256 = sha256;
this.dependencies = ImmutableSet.copyOf(new TreeSet<>(dependencies));

this.packages = ImmutableSet.copyOf(new TreeSet<>(packages));
this.services = services;
}

public Coordinates getCoordinates() {
Expand All @@ -53,6 +58,10 @@ public Set<String> getPackages() {
return packages;
}

public SortedMap<String, SortedSet<String>> getServices() {
return services;
}

public Path getPath() {
return path;
}
Expand All @@ -69,11 +78,12 @@ public boolean equals(Object o) {
return Objects.equals(coordinates, that.coordinates)
&& Objects.equals(sha256, that.sha256)
&& Objects.equals(dependencies, that.dependencies)
&& Objects.equals(packages, that.packages);
&& Objects.equals(packages, that.packages)
&& Objects.equals(services, that.services);
}

@Override
public int hashCode() {
return Objects.hash(coordinates, sha256, dependencies, packages);
return Objects.hash(coordinates, sha256, dependencies, packages, services);
}
}
Binary file modified private/tools/prebuilt/index_jar_deploy.jar
Binary file not shown.
Binary file modified private/tools/prebuilt/lock_file_converter_deploy.jar
Binary file not shown.
3 changes: 3 additions & 0 deletions tests/com/github/bazelbuild/rules_jvm_external/jar/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ java_test(
"@hamcrest_core_for_test//file",
"@hamcrest_core_srcs_for_test//file",
"@junit_platform_commons_for_test//file",
"@lombok_for_test//file",
"//tests/custom_maven_install:service_indexing_testing.json",
],
test_class = "com.github.bazelbuild.rules_jvm_external.jar.IndexJarTest",
deps = [
"//private/tools/java/com/github/bazelbuild/rules_jvm_external/jar:IndexJar-lib",
"@bazel_tools//tools/java/runfiles",
"@rules_jvm_external_deps//:com_google_code_gson_gson",
artifact(
"junit:junit",
repository_name = "regression_testing",
Expand Down
Loading

0 comments on commit b61cc1a

Please sign in to comment.