Skip to content

Commit 551ea97

Browse files
authored
Merge pull request #11 from gradle/lptr/fix-for-AndroidJavaCompile-dataBindingDependencyArtifacts
Fix AndroidJavaCompile.dataBindingDependencyArtifacts relocatability
2 parents 451f0fe + 6407f6c commit 551ea97

File tree

8 files changed

+365
-55
lines changed

8 files changed

+365
-55
lines changed

src/main/groovy/org/gradle/android/AndroidCacheFixPlugin.groovy

Lines changed: 121 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ import groovy.transform.CompileStatic
1212
import groovy.transform.TypeCheckingMode
1313
import org.gradle.api.Plugin
1414
import org.gradle.api.Project
15+
import org.gradle.api.Task
1516
import org.gradle.api.tasks.PathSensitivity
17+
import org.gradle.api.tasks.util.PatternFilterable
1618
import org.gradle.internal.Factory
1719
import org.gradle.util.DeprecationLogger
1820
import org.gradle.util.GradleVersion
1921
import org.gradle.util.VersionNumber
2022
import org.slf4j.Logger
2123
import org.slf4j.LoggerFactory
2224

25+
import static org.gradle.android.CompilerArgsProcessor.AnnotationProcessorOverride
26+
import static org.gradle.android.CompilerArgsProcessor.Skip
27+
import static org.gradle.android.CompilerArgsProcessor.SkipNext
2328
import static org.gradle.android.Versions.android
2429

2530
@CompileStatic
@@ -32,6 +37,7 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
3237
new AndroidJavaCompile_BootClasspath_Workaround(),
3338
new AndroidJavaCompile_AnnotationProcessorSource_Workaround(),
3439
new AndroidJavaCompile_ProcessorListFile_Workaround(),
40+
new DataBindingDependencyArtifacts_Workaround(),
3541
new ExtractAnnotations_Source_Workaround(),
3642
new CombinedInput_Workaround(),
3743
new ProcessAndroidResources_MergeBlameLogFolder_Workaround(),
@@ -52,9 +58,11 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
5258
}
5359
}
5460

61+
def context = new WorkaroundContext(project, new CompilerArgsProcessor(project))
62+
5563
getWorkaroundsToApply(currentAndroidVersion).each { Workaround workaround ->
5664
LOGGER.debug("Applying Android workaround {} to {}", workaround.getClass().simpleName, project)
57-
workaround.apply(project)
65+
workaround.apply(context)
5866
}
5967
}
6068

@@ -82,11 +90,14 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
8290
*/
8391
@AndroidIssue(introducedIn = "3.0.0", link = "https://issuetracker.google.com/issues/68392933")
8492
static class AndroidJavaCompile_BootClasspath_Workaround implements Workaround {
85-
@Override
8693
@CompileStatic(TypeCheckingMode.SKIP)
87-
void apply(Project project) {
94+
@Override
95+
void apply(WorkaroundContext context) {
96+
def project = context.project
8897
project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
8998
task.inputs.property "options.bootClasspath", ""
99+
// Override workaround introduced in 3.1.0-alpha02
100+
task.inputs.property "options.bootClasspath.filtered", ""
90101
task.inputs.files({
91102
DeprecationLogger.whileDisabled({
92103
//noinspection GrDeprecatedAPIUsage
@@ -105,27 +116,9 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
105116
*/
106117
@AndroidIssue(introducedIn = "3.0.0", link = "https://issuetracker.google.com/issues/68391973")
107118
static class AndroidJavaCompile_AnnotationProcessorSource_Workaround implements Workaround {
108-
@CompileStatic(TypeCheckingMode.SKIP)
109119
@Override
110-
void apply(Project project) {
111-
project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
112-
task.inputs.property "options.compilerArgs", ""
113-
task.inputs.property "options.compilerArgs.workaround", {
114-
def filteredArgs = []
115-
def iCompilerArgs = task.options.compilerArgs.iterator()
116-
while (iCompilerArgs.hasNext()) {
117-
def compilerArg = iCompilerArgs.next()
118-
if (compilerArg == "-s") {
119-
if (iCompilerArgs.hasNext()) {
120-
iCompilerArgs.next()
121-
}
122-
} else {
123-
filteredArgs += compilerArg
124-
}
125-
}
126-
return filteredArgs
127-
}
128-
}
120+
void apply(WorkaroundContext context) {
121+
context.compilerArgsProcessor.addRule(SkipNext.matching("-s"))
129122
}
130123
}
131124

@@ -136,7 +129,8 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
136129
static class AndroidJavaCompile_ProcessorListFile_Workaround implements Workaround {
137130
@CompileStatic(TypeCheckingMode.SKIP)
138131
@Override
139-
void apply(Project project) {
132+
void apply(WorkaroundContext context) {
133+
def project = context.project
140134
project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
141135
def originalValue
142136

@@ -157,14 +151,110 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
157151
}
158152
}
159153

154+
/**
155+
* Override path sensitivity for {@link AndroidJavaCompile#getDataBindingDependencyArtifacts()} to {@link PathSensitivity#RELATIVE}.
156+
*/
157+
@AndroidIssue(introducedIn = "3.0.0", link = "https://issuetracker.google.com/issues/68759178")
158+
static class DataBindingDependencyArtifacts_Workaround implements Workaround {
159+
@Override
160+
void apply(WorkaroundContext context) {
161+
def project = context.project
162+
def compilerArgsProcessor = context.compilerArgsProcessor
163+
compilerArgsProcessor.addRule(Skip.matching("-Aandroid.databinding.sdkDir=.*"))
164+
compilerArgsProcessor.addRule(Skip.matching("-Aandroid.databinding.bindingBuildFolder=.*"))
165+
compilerArgsProcessor.addRule(Skip.matching("-Aandroid.databinding.xmlOutDir=.*"))
166+
167+
def outputRules = [
168+
AnnotationProcessorOverride.of("android.databinding.generationalFileOutDir") { Task task, String path ->
169+
task.outputs.dir(path)
170+
.withPropertyName("android.databinding.generationalFileOutDir.workaround")
171+
},
172+
AnnotationProcessorOverride.of("android.databinding.exportClassListTo") { Task task, String path ->
173+
task.outputs.file(path)
174+
.withPropertyName("android.databinding.exportClassListTo")
175+
}
176+
]
177+
outputRules.each {
178+
compilerArgsProcessor.addRule it
179+
}
180+
181+
project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
182+
reconfigurePathSensitivityForDataBindingDependencyArtifacts(project, task)
183+
filterDataBindingInfoFromSource(project, task)
184+
configureAdditionalOutputs(project, task, outputRules)
185+
}
186+
}
187+
188+
@CompileStatic(TypeCheckingMode.SKIP)
189+
private
190+
static void reconfigurePathSensitivityForDataBindingDependencyArtifacts(Project project, AndroidJavaCompile task) {
191+
def originalValue
192+
193+
project.gradle.taskGraph.beforeTask {
194+
if (task == it) {
195+
originalValue = task.dataBindingDependencyArtifacts
196+
if (originalValue != null) {
197+
task.dataBindingDependencyArtifacts = project.files()
198+
task.inputs.files(originalValue)
199+
.withPathSensitivity(PathSensitivity.RELATIVE)
200+
.withPropertyName("dataBindingDependencyArtifacts.workaround")
201+
}
202+
}
203+
}
204+
205+
task.doFirst {
206+
task.dataBindingDependencyArtifacts = originalValue
207+
}
208+
}
209+
210+
@CompileStatic(TypeCheckingMode.SKIP)
211+
private static void filterDataBindingInfoFromSource(Project project, AndroidJavaCompile task) {
212+
def originalValue
213+
214+
project.gradle.taskGraph.beforeTask {
215+
if (task == it) {
216+
originalValue = task.source
217+
if (originalValue != null) {
218+
task.source = project.files()
219+
def filteredSources = originalValue.matching { PatternFilterable filter ->
220+
filter.exclude("android/databinding/layouts/DataBindingInfo.java")
221+
}
222+
task.inputs.files(filteredSources)
223+
.withPathSensitivity(PathSensitivity.RELATIVE)
224+
.withPropertyName("source.workaround")
225+
.skipWhenEmpty()
226+
}
227+
}
228+
}
229+
230+
task.doFirst {
231+
task.source = originalValue
232+
}
233+
}
234+
235+
236+
@CompileStatic(TypeCheckingMode.SKIP)
237+
private static void configureAdditionalOutputs(Project project, AndroidJavaCompile task, List<AnnotationProcessorOverride> overrides) {
238+
def configTask = project.tasks.create("configure" + task.name.capitalize()) { configTask ->
239+
configTask.doFirst {
240+
overrides.each {
241+
it.configureAndroidJavaCompile(task)
242+
}
243+
}
244+
}
245+
task.dependsOn configTask
246+
}
247+
}
248+
160249
/**
161250
* Override path sensitivity for {@link ExtractAnnotations#getSource()} to {@link PathSensitivity#RELATIVE}.
162251
*/
163252
@AndroidIssue(introducedIn = "3.0.0", fixedIn = "3.1.0-alpha01", link = "https://issuetracker.google.com/issues/68759476")
164253
static class ExtractAnnotations_Source_Workaround implements Workaround {
165254
@CompileStatic(TypeCheckingMode.SKIP)
166255
@Override
167-
void apply(Project project) {
256+
void apply(WorkaroundContext context) {
257+
def project = context.project
168258
project.tasks.withType(ExtractAnnotations) { ExtractAnnotations task ->
169259
def originalValue
170260

@@ -193,7 +283,8 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
193283
static class CombinedInput_Workaround implements Workaround {
194284
@CompileStatic(TypeCheckingMode.SKIP)
195285
@Override
196-
void apply(Project project) {
286+
void apply(WorkaroundContext context) {
287+
def project = context.project
197288
project.tasks.withType(IncrementalTask) { IncrementalTask task ->
198289
task.inputs.property "combinedInput", ""
199290
task.inputs.property "combinedInput.workaround", {
@@ -224,7 +315,8 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
224315
static class ProcessAndroidResources_MergeBlameLogFolder_Workaround implements Workaround {
225316
@CompileStatic(TypeCheckingMode.SKIP)
226317
@Override
227-
void apply(Project project) {
318+
void apply(WorkaroundContext context) {
319+
def project = context.project
228320
project.tasks.withType(ProcessAndroidResources) { ProcessAndroidResources task ->
229321
task.inputs.property "mergeBlameLogFolder", ""
230322
}
@@ -238,7 +330,8 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
238330
static class CheckManifest_Manifest_Workaround implements Workaround {
239331
@CompileStatic(TypeCheckingMode.SKIP)
240332
@Override
241-
void apply(Project project) {
333+
void apply(WorkaroundContext context) {
334+
def project = context.project
242335
project.tasks.withType(CheckManifest) { CheckManifest task ->
243336
task.inputs.property "manifest", ""
244337
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package org.gradle.android
2+
3+
import com.android.build.gradle.tasks.factory.AndroidJavaCompile
4+
import groovy.transform.CompileStatic
5+
import groovy.transform.TypeCheckingMode
6+
import org.gradle.api.Project
7+
import org.gradle.api.Task
8+
import org.gradle.internal.BiAction
9+
10+
import java.util.regex.Matcher
11+
import java.util.regex.Pattern
12+
13+
@CompileStatic
14+
class CompilerArgsProcessor {
15+
private final List<Rule> rules
16+
private final Project project
17+
private boolean applied
18+
19+
CompilerArgsProcessor(Project project) {
20+
this.project = project
21+
this.rules = [new Rule(Pattern.compile(".*")) {
22+
@Override
23+
void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs) {
24+
processedArgs.add(match.group())
25+
}
26+
}] as List<Rule>
27+
}
28+
29+
void addRule(Rule rule) {
30+
ensureApplied()
31+
rules.add(0, rule)
32+
}
33+
34+
@CompileStatic(TypeCheckingMode.SKIP)
35+
private void ensureApplied() {
36+
if (applied) {
37+
return
38+
}
39+
applied = true
40+
41+
project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
42+
project.gradle.taskGraph.beforeTask {
43+
if (task == it) {
44+
def processedArgs = processArgs(task.options.compilerArgs)
45+
overrideProperty(task, processedArgs)
46+
}
47+
}
48+
}
49+
}
50+
51+
List<String> processArgs(List<String> args) {
52+
def processedArgs = []
53+
def remainingArgs = args.iterator()
54+
while (remainingArgs.hasNext()) {
55+
def arg = remainingArgs.next()
56+
for (Rule rule : rules) {
57+
def matcher = rule.pattern.matcher(arg)
58+
if (matcher.matches()) {
59+
rule.process(matcher, processedArgs, remainingArgs)
60+
break
61+
}
62+
}
63+
}
64+
return processedArgs
65+
}
66+
67+
@CompileStatic(TypeCheckingMode.SKIP)
68+
private static void overrideProperty(AndroidJavaCompile task, List processedArgs) {
69+
task.inputs.property "options.compilerArgs", ""
70+
task.inputs.property "options.compilerArgs.filtered", ""
71+
task.inputs.property "options.compilerArgs.workaround", processedArgs
72+
}
73+
74+
static class AnnotationProcessorOverride extends Rule {
75+
private final BiAction<? super Task, String> action
76+
77+
AnnotationProcessorOverride(String property, BiAction<? super Task, String> action) {
78+
super(Pattern.compile("-A${Pattern.quote(property)}=(.*)"))
79+
this.action = action
80+
}
81+
82+
static AnnotationProcessorOverride of(String property, BiAction<? super Task, String> action) {
83+
return new AnnotationProcessorOverride(property, action)
84+
}
85+
86+
void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs) {
87+
// Skip the arg
88+
}
89+
90+
void configureAndroidJavaCompile(AndroidJavaCompile task) {
91+
configureTask(task, task.options.compilerArgs)
92+
}
93+
94+
void configureTask(Task task, List<String> args) {
95+
for (String arg : (args)) {
96+
def matcher = pattern.matcher(arg)
97+
if (matcher.matches()) {
98+
def path = matcher.group(1)
99+
action.execute(task, path)
100+
break
101+
}
102+
}
103+
}
104+
}
105+
106+
static class Skip extends Rule {
107+
Skip(Pattern pattern) {
108+
super(pattern)
109+
}
110+
111+
static Skip matching(String pattern) {
112+
return new Skip(Pattern.compile(pattern))
113+
}
114+
115+
@Override
116+
void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs) {
117+
}
118+
}
119+
120+
static class SkipNext extends Rule {
121+
SkipNext(Pattern pattern) {
122+
super(pattern)
123+
}
124+
125+
static SkipNext matching(String pattern) {
126+
return new SkipNext(Pattern.compile(pattern))
127+
}
128+
129+
@Override
130+
void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs) {
131+
if (remainingArgs.hasNext()) {
132+
remainingArgs.next()
133+
}
134+
}
135+
}
136+
137+
static abstract class Rule {
138+
final Pattern pattern
139+
140+
Rule(Pattern pattern) {
141+
this.pattern = pattern
142+
}
143+
144+
abstract void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs)
145+
146+
@Override
147+
String toString() {
148+
return "${getClass().simpleName}[${pattern.pattern()}]"
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)