Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

maven_export support for bundling AARs #1049

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
build --experimental_google_legacy_api

build --java_language_version=11
build --java_runtime_version=remotejdk_11

Expand Down
4 changes: 3 additions & 1 deletion private/rules/has_maven_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ _gathered = provider(
"artifact_infos",
"transitive_exports",
"dep_infos",
"artifact_coordinates",
],
)

Expand All @@ -104,7 +105,7 @@ def _extract_from(gathered, maven_info, dep, include_transitive_exports):
gathered.all_infos.append(maven_info)
gathered.label_to_javainfo.update(maven_info.label_to_javainfo)
if java_info:
if maven_info.coordinates:
if maven_info.coordinates and maven_info.coordinates != gathered.artifact_coordinates:
gathered.dep_infos.append(dep[JavaInfo])
else:
gathered.artifact_infos.append(dep[JavaInfo])
Expand All @@ -129,6 +130,7 @@ def _has_maven_deps_impl(target, ctx):
transitive_exports = [],
dep_infos = [],
label_to_javainfo = {target.label: target[JavaInfo]},
artifact_coordinates = coordinates,
)

for attr in _ASPECT_ATTRS:
Expand Down
9 changes: 7 additions & 2 deletions private/rules/maven_project_jar.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load(":has_maven_deps.bzl", "MavenInfo", "calculate_artifact_jars", "calculate_artifact_source_jars", "has_maven_deps")
load(":maven_utils.bzl", "determine_additional_dependencies")
load(":maven_utils.bzl", "determine_additional_dependencies", "unpack_coordinates")

DEFAULT_EXCLUDED_WORKSPACES = [
# Note: we choose to drop the dependency entirely because
Expand Down Expand Up @@ -64,7 +64,12 @@ def _maven_project_jar_impl(ctx):
)

# Merge together all the binary jars
bin_jar = ctx.actions.declare_file("%s.jar" % ctx.label.name)
packaging = unpack_coordinates(info.coordinates).type or "jar"
bin_jar = ctx.actions.declare_file("%s.%s" % (ctx.label.name, packaging))

if packaging == "aar" and AndroidLibraryAarInfo in target and target[AndroidLibraryAarInfo].aar:
artifact_jars = artifact_jars + [target[AndroidLibraryAarInfo].aar]

_combine_jars(
ctx,
ctx.executable._merge_jars,
Expand Down
1 change: 1 addition & 0 deletions private/templates/pom.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<groupId>{groupId}</groupId>
<artifactId>{artifactId}</artifactId>
<version>{version}</version>
<packaging>{type}</packaging>

<dependencies>
{dependencies}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
Expand All @@ -45,18 +48,27 @@
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

public class MergeJars {

private enum Packaging {
JAR, AAR;
}

public static void main(String[] args) throws IOException {
Path out = null;
// Insertion order may matter
Set<Path> sources = new LinkedHashSet<>();
Set<Path> excludes = new HashSet<>();
DuplicateEntryStrategy onDuplicate = LAST_IN_WINS;
Packaging packaging = Packaging.JAR;
PathMatcher aarMatcher = FileSystems.getDefault().getPathMatcher("glob:*.aar");
// AAR to build from
Path aarSource = null;

for (int i = 0; i < args.length; i++) {
switch (args[i]) {
Expand All @@ -75,6 +87,9 @@ public static void main(String[] args) throws IOException {

case "--output":
out = Paths.get(args[++i]);
if (aarMatcher.matches(out.getFileName())) {
packaging = Packaging.AAR;
}
break;

case "--sources":
Expand All @@ -87,6 +102,26 @@ public static void main(String[] args) throws IOException {
}
}

if (packaging == Packaging.AAR) {
aarSource = sources.stream()
.filter(source -> aarMatcher.matches(source.getFileName()))
.findFirst() // AAR is explicitly only added for top level distribution target, so we _should_ only ever have 1
.orElseThrow(() -> new IllegalArgumentException("For AAR packaging, we require a prebuilt AAR that already contains the Android resources that we'll add the transitive source closure to."));

sources.remove(aarSource);

// Pull out classes jar and add to source set
Path aarClassesJar = out.getParent().resolve("aar-classes.jar");
try (ZipFile aar = new ZipFile(aarSource.toFile())) {
ZipEntry classes = aar.getEntry("classes.jar");
try (InputStream is = aar.getInputStream(classes);
OutputStream fos = Files.newOutputStream(aarClassesJar)) {
ByteStreams.copy(is, fos);
}
}
sources.add(aarClassesJar);
}

Objects.requireNonNull(out, "Output path must be set.");
if (sources.isEmpty()) {
// Just write an empty jar and leave
Expand Down Expand Up @@ -144,6 +179,12 @@ public static void main(String[] args) throws IOException {
continue;
}

// TODO: Why do we need to do this?? Is there a better way?
Pattern rClassMatcher = Pattern.compile("^.*\\/R(\\$.*)?\\.(class|java)");
if (rClassMatcher.asMatchPredicate().test(entry.getName())) {
continue;
}

if (!entry.isDirectory()) {
// Duplicate files, however may not be. We need the hash to determine
// whether we should do anything.
Expand Down Expand Up @@ -171,6 +212,53 @@ public static void main(String[] args) throws IOException {
// jar and not useful for consumers.
manifest.getMainAttributes().remove(new Attributes.Name("Target-Label"));

switch (packaging) {
case JAR:
writeClassesJar(out, manifest, allServices, sources, fileToSourceJar);
break;
case AAR:
Path classesJar = out.getParent().resolve("classes.jar");
writeClassesJar(classesJar, manifest, allServices, sources, fileToSourceJar);
writeAar(out, aarSource, classesJar);
}
}

private static void writeAar(Path out, Path aarSource, Path classesJar) throws IOException {
try (OutputStream os = Files.newOutputStream(out);
JarOutputStream jos = new JarOutputStream(os)) {
ZipEntry je = new StableZipEntry(classesJar.toFile().getName());
jos.putNextEntry(je);

try (InputStream is = Files.newInputStream(classesJar)) {
ByteStreams.copy(is, jos);
}
jos.closeEntry();

try (ZipFile aar = new ZipFile(aarSource.toFile())) {
Enumeration<? extends ZipEntry> entries = aar.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();

// transitive class closure is captured in our classes.jar
if ("classes.jar".equals(entry.getName())) {
continue;
}

jos.putNextEntry(new ZipEntry(entry.getName()));
try (InputStream is = aar.getInputStream(entry)) {
ByteStreams.copy(is, jos);
}
jos.closeEntry();
}
}
}
}

private static void writeClassesJar(Path out,
Manifest manifest,
Map<String, Set<String>> allServices,
Set<Path> sources,
Map<String, Path> fileToSourceJar) throws IOException {
// Now create the output jar
Files.createDirectories(out.getParent());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,15 @@ public static void main(String[] args)

try {
List<CompletableFuture<Void>> futures = new ArrayList<>();
futures.add(upload(repo, credentials, coords, ".pom", pom, gpgSign));

if (mainArtifact != null) {
String ext =
com.google.common.io.Files.getFileExtension(mainArtifact.getFileName().toString());
futures.add(upload(repo, credentials, coords, "." + ext, mainArtifact, gpgSign));
}

futures.add(upload(repo, credentials, coords, ".pom", pom, gpgSign));
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relevant discussion for this change:
vaticle/bazel-distribution#318

Might break this out into a separate contribution since this is unrelated, yet necessary for publishing support for Artifactory repositories.


if (args.length > 3 && !args[3].isEmpty()) {
List<String> extraArtifactTuples = Splitter.onPattern(",").splitToList(args[3]);
for (String artifactTuple : extraArtifactTuples) {
Expand Down