Skip to content

Commit 3f825ce

Browse files
authored
Error with duplicate classes on truetime android library (#222)
* Using gradle shadow to merge embedded dependencies * Creating shadowJar extension * Setting truetime shadow relocation * Updated changelog
1 parent 5199095 commit 3f825ce

File tree

7 files changed

+86
-93
lines changed

7 files changed

+86
-93
lines changed

CHANGELOG.asciidoc

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ ${next_release_notes}
3030
==== ${version} - ${release_date}
3131

3232
[float]
33-
===== Features
33+
===== Bug fixes
3434

35-
* New feature: {pull}000[#000]
35+
* Fix truetime duplicated classes: {pull}222[#222]
3636
////
3737
3838
[[release-notes-0.10.0]]

android-sdk/build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ licensesConfig {
3434
manualMappingFile = rootProject.file("manual_licenses_map.txt")
3535
}
3636

37+
shadowJar {
38+
relocate 'com.instacart.library.truetime', 'co.elastic.apm.android.truetime'
39+
}
40+
3741
dependencies {
3842
api "io.opentelemetry:opentelemetry-api:$openTelemetry_version"
3943
api "io.opentelemetry:opentelemetry-sdk:$openTelemetry_version"

build-tools/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies {
1919
implementation "org.jetbrains.dokka:dokka-gradle-plugin:1.9.0"
2020
implementation "io.github.gradle-nexus:publish-plugin:1.3.0"
2121
implementation 'com.gradle.publish:plugin-publish-plugin:1.2.1'
22+
implementation "gradle.plugin.com.github.johnrengelman:shadow:7.1.2"
2223
testImplementation "junit:junit:4.13.2"
2324
}
2425

build-tools/src/main/java/co/elastic/apm/compile/tools/embedding/EmbeddingDependenciesPlugin.java

+18-58
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,52 @@
22

33
import static co.elastic.apm.compile.tools.utils.Constants.ARTIFACT_TYPE_ATTR;
44

5-
import com.android.build.api.artifact.MultipleArtifact;
5+
import com.android.build.api.artifact.ScopedArtifact;
66
import com.android.build.api.variant.AndroidComponentsExtension;
7+
import com.android.build.api.variant.ScopedArtifacts;
78
import com.android.build.api.variant.Variant;
89

910
import org.gradle.api.Plugin;
1011
import org.gradle.api.Project;
1112
import org.gradle.api.artifacts.Configuration;
12-
import org.gradle.api.file.ConfigurableFileCollection;
13-
import org.gradle.api.file.Directory;
14-
import org.gradle.api.file.FileCollection;
15-
import org.gradle.api.file.FileTree;
16-
import org.gradle.api.provider.Provider;
17-
import org.gradle.api.tasks.Sync;
1813
import org.gradle.api.tasks.TaskProvider;
1914

20-
import java.io.File;
21-
import java.util.concurrent.Callable;
15+
import java.util.Collections;
2216

23-
import co.elastic.apm.compile.tools.embedding.tasks.EmbeddedClassesGathererTask;
17+
import co.elastic.apm.compile.tools.embedding.extensions.ShadowExtension;
18+
import co.elastic.apm.compile.tools.embedding.tasks.EmbeddedClassesMergerTask;
2419
import kotlin.Unit;
2520

2621
@SuppressWarnings("unchecked")
2722
public class EmbeddingDependenciesPlugin implements Plugin<Project> {
2823

2924
public static final String EMBEDDED_CLASSPATH_NAME = "embeddedClasspath";
25+
private static final String SHADOW_EXTENSION_NAME = "shadowJar";
26+
private ShadowExtension shadowExtension;
3027

3128
@Override
3229
public void apply(Project project) {
3330
AndroidComponentsExtension<?, ?, Variant> componentsExtension = project.getExtensions().getByType(AndroidComponentsExtension.class);
3431
Configuration embeddedClasspath = getEmbeddedClasspath(project);
35-
Provider<FileCollection> classesProvider = getClassesProvider(project, embeddedClasspath);
36-
String embeddedClassesTaskName = "embeddedClasses";
37-
Provider<Directory> classesDir = project.getLayout().getBuildDirectory().dir(embeddedClassesTaskName);
38-
TaskProvider<Sync> syncEmbeddedClassesTask = project.getTasks().register(embeddedClassesTaskName, Sync.class, sync -> {
39-
sync.from(classesProvider);
40-
sync.into(classesDir);
41-
});
32+
shadowExtension = project.getExtensions().create(SHADOW_EXTENSION_NAME, ShadowExtension.class);
4233

4334
componentsExtension.onVariants(componentsExtension.selector().all(), variant -> {
44-
TaskProvider<EmbeddedClassesGathererTask> taskProvider = getEmbeddedClassesGathererTaskProvider(project, classesDir, variant);
45-
taskProvider.configure(task -> task.dependsOn(syncEmbeddedClassesTask));
4635

47-
variant.getArtifacts().use(taskProvider)
48-
.wiredWith(EmbeddedClassesGathererTask::getOutputDir)
49-
.toAppendTo(MultipleArtifact.ALL_CLASSES_DIRS.INSTANCE);
36+
variant.getArtifacts().forScope(ScopedArtifacts.Scope.PROJECT).use(getEmbeddedClassesMergerTaskProvider(project, embeddedClasspath, variant))
37+
.toTransform(ScopedArtifact.CLASSES.INSTANCE, EmbeddedClassesMergerTask::getInputJars,
38+
EmbeddedClassesMergerTask::getLocalClassesDirs, EmbeddedClassesMergerTask::getOutputFile);
5039
return Unit.INSTANCE;
5140
});
5241
}
5342

54-
private TaskProvider<EmbeddedClassesGathererTask> getEmbeddedClassesGathererTaskProvider(Project project, Provider<Directory> classesDir, Variant variant) {
55-
TaskProvider<EmbeddedClassesGathererTask> taskProvider = project.getTasks().register(variant.getName() + "EmbeddedClassesGatherer", EmbeddedClassesGathererTask.class);
43+
private TaskProvider<EmbeddedClassesMergerTask> getEmbeddedClassesMergerTaskProvider(Project project, Configuration embedded, Variant variant) {
44+
TaskProvider<EmbeddedClassesMergerTask> taskProvider = project.getTasks().register(variant.getName() + "EmbeddedClassesMerger", EmbeddedClassesMergerTask.class);
5645
taskProvider.configure(task -> {
57-
task.getClassesDir().set(classesDir);
58-
task.getOutputDir().set(project.getLayout().getBuildDirectory().dir(task.getName()));
46+
task.from(task.getLocalClassesDirs());
47+
task.setConfigurations(Collections.singletonList(embedded));
48+
for (ShadowExtension.Relocation relocation : shadowExtension.getRelocations()) {
49+
task.relocate(relocation.getPattern().get(), relocation.getDestination().get());
50+
}
5951
});
6052
return taskProvider;
6153
}
@@ -76,36 +68,4 @@ private Configuration getEmbeddedClasspath(Project project) {
7668

7769
return classpath;
7870
}
79-
80-
private Provider<FileCollection> getClassesProvider(Project project, Configuration classpath) {
81-
return project.provider(new LazyFileCollectionProvider(project, classpath));
82-
}
83-
84-
private static class LazyFileCollectionProvider implements Callable<FileCollection> {
85-
private final Project project;
86-
private final Configuration classpath;
87-
private FileCollection cachedFileCollection;
88-
89-
private LazyFileCollectionProvider(Project project, Configuration classpath) {
90-
this.project = project;
91-
this.classpath = classpath;
92-
}
93-
94-
@Override
95-
public FileCollection call() {
96-
if (cachedFileCollection != null) {
97-
return cachedFileCollection;
98-
}
99-
ConfigurableFileCollection fileCollection = project.files();
100-
for (File file : classpath.getFiles()) {
101-
if (file.getName().endsWith(".jar")) {
102-
FileTree files = project.zipTree(file);
103-
fileCollection.from(files);
104-
}
105-
}
106-
107-
cachedFileCollection = fileCollection;
108-
return fileCollection;
109-
}
110-
}
11171
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package co.elastic.apm.compile.tools.embedding.extensions;
2+
3+
import org.gradle.api.model.ObjectFactory;
4+
import org.gradle.api.provider.Property;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
import javax.inject.Inject;
10+
11+
public class ShadowExtension {
12+
private final ObjectFactory objectFactory;
13+
14+
private final List<Relocation> relocations = new ArrayList<>();
15+
16+
@Inject
17+
public ShadowExtension(ObjectFactory objectFactory) {
18+
this.objectFactory = objectFactory;
19+
}
20+
21+
public List<Relocation> getRelocations() {
22+
return relocations;
23+
}
24+
25+
public void relocate(String pattern, String destination) {
26+
Relocation relocation = objectFactory.newInstance(Relocation.class);
27+
relocation.getPattern().set(pattern);
28+
relocation.getDestination().set(destination);
29+
relocations.add(relocation);
30+
}
31+
32+
public interface Relocation {
33+
Property<String> getPattern();
34+
35+
Property<String> getDestination();
36+
}
37+
}

build-tools/src/main/java/co/elastic/apm/compile/tools/embedding/tasks/EmbeddedClassesGathererTask.java

-33
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package co.elastic.apm.compile.tools.embedding.tasks;
2+
3+
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar;
4+
5+
import org.gradle.api.file.Directory;
6+
import org.gradle.api.file.RegularFile;
7+
import org.gradle.api.file.RegularFileProperty;
8+
import org.gradle.api.provider.ListProperty;
9+
import org.gradle.api.tasks.InputFiles;
10+
import org.gradle.api.tasks.Internal;
11+
12+
public abstract class EmbeddedClassesMergerTask extends ShadowJar {
13+
14+
@InputFiles
15+
public abstract ListProperty<RegularFile> getInputJars();
16+
17+
@InputFiles
18+
public abstract ListProperty<Directory> getLocalClassesDirs();
19+
20+
@Internal
21+
public RegularFileProperty getOutputFile() {
22+
return (RegularFileProperty) getArchiveFile();
23+
}
24+
}

0 commit comments

Comments
 (0)