Skip to content

Commit

Permalink
Merge pull request #11 from gradle/lptr/fix-for-AndroidJavaCompile-da…
Browse files Browse the repository at this point in the history
…taBindingDependencyArtifacts

Fix AndroidJavaCompile.dataBindingDependencyArtifacts relocatability
  • Loading branch information
lptr authored Dec 14, 2017
2 parents 451f0fe + 6407f6c commit 551ea97
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 55 deletions.
149 changes: 121 additions & 28 deletions src/main/groovy/org/gradle/android/AndroidCacheFixPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ import groovy.transform.CompileStatic
import groovy.transform.TypeCheckingMode
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.util.PatternFilterable
import org.gradle.internal.Factory
import org.gradle.util.DeprecationLogger
import org.gradle.util.GradleVersion
import org.gradle.util.VersionNumber
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import static org.gradle.android.CompilerArgsProcessor.AnnotationProcessorOverride
import static org.gradle.android.CompilerArgsProcessor.Skip
import static org.gradle.android.CompilerArgsProcessor.SkipNext
import static org.gradle.android.Versions.android

@CompileStatic
Expand All @@ -32,6 +37,7 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
new AndroidJavaCompile_BootClasspath_Workaround(),
new AndroidJavaCompile_AnnotationProcessorSource_Workaround(),
new AndroidJavaCompile_ProcessorListFile_Workaround(),
new DataBindingDependencyArtifacts_Workaround(),
new ExtractAnnotations_Source_Workaround(),
new CombinedInput_Workaround(),
new ProcessAndroidResources_MergeBlameLogFolder_Workaround(),
Expand All @@ -52,9 +58,11 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
}
}

def context = new WorkaroundContext(project, new CompilerArgsProcessor(project))

getWorkaroundsToApply(currentAndroidVersion).each { Workaround workaround ->
LOGGER.debug("Applying Android workaround {} to {}", workaround.getClass().simpleName, project)
workaround.apply(project)
workaround.apply(context)
}
}

Expand Down Expand Up @@ -82,11 +90,14 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
*/
@AndroidIssue(introducedIn = "3.0.0", link = "https://issuetracker.google.com/issues/68392933")
static class AndroidJavaCompile_BootClasspath_Workaround implements Workaround {
@Override
@CompileStatic(TypeCheckingMode.SKIP)
void apply(Project project) {
@Override
void apply(WorkaroundContext context) {
def project = context.project
project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
task.inputs.property "options.bootClasspath", ""
// Override workaround introduced in 3.1.0-alpha02
task.inputs.property "options.bootClasspath.filtered", ""
task.inputs.files({
DeprecationLogger.whileDisabled({
//noinspection GrDeprecatedAPIUsage
Expand All @@ -105,27 +116,9 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
*/
@AndroidIssue(introducedIn = "3.0.0", link = "https://issuetracker.google.com/issues/68391973")
static class AndroidJavaCompile_AnnotationProcessorSource_Workaround implements Workaround {
@CompileStatic(TypeCheckingMode.SKIP)
@Override
void apply(Project project) {
project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
task.inputs.property "options.compilerArgs", ""
task.inputs.property "options.compilerArgs.workaround", {
def filteredArgs = []
def iCompilerArgs = task.options.compilerArgs.iterator()
while (iCompilerArgs.hasNext()) {
def compilerArg = iCompilerArgs.next()
if (compilerArg == "-s") {
if (iCompilerArgs.hasNext()) {
iCompilerArgs.next()
}
} else {
filteredArgs += compilerArg
}
}
return filteredArgs
}
}
void apply(WorkaroundContext context) {
context.compilerArgsProcessor.addRule(SkipNext.matching("-s"))
}
}

Expand All @@ -136,7 +129,8 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
static class AndroidJavaCompile_ProcessorListFile_Workaround implements Workaround {
@CompileStatic(TypeCheckingMode.SKIP)
@Override
void apply(Project project) {
void apply(WorkaroundContext context) {
def project = context.project
project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
def originalValue

Expand All @@ -157,14 +151,110 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
}
}

/**
* Override path sensitivity for {@link AndroidJavaCompile#getDataBindingDependencyArtifacts()} to {@link PathSensitivity#RELATIVE}.
*/
@AndroidIssue(introducedIn = "3.0.0", link = "https://issuetracker.google.com/issues/68759178")
static class DataBindingDependencyArtifacts_Workaround implements Workaround {
@Override
void apply(WorkaroundContext context) {
def project = context.project
def compilerArgsProcessor = context.compilerArgsProcessor
compilerArgsProcessor.addRule(Skip.matching("-Aandroid.databinding.sdkDir=.*"))
compilerArgsProcessor.addRule(Skip.matching("-Aandroid.databinding.bindingBuildFolder=.*"))
compilerArgsProcessor.addRule(Skip.matching("-Aandroid.databinding.xmlOutDir=.*"))

def outputRules = [
AnnotationProcessorOverride.of("android.databinding.generationalFileOutDir") { Task task, String path ->
task.outputs.dir(path)
.withPropertyName("android.databinding.generationalFileOutDir.workaround")
},
AnnotationProcessorOverride.of("android.databinding.exportClassListTo") { Task task, String path ->
task.outputs.file(path)
.withPropertyName("android.databinding.exportClassListTo")
}
]
outputRules.each {
compilerArgsProcessor.addRule it
}

project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
reconfigurePathSensitivityForDataBindingDependencyArtifacts(project, task)
filterDataBindingInfoFromSource(project, task)
configureAdditionalOutputs(project, task, outputRules)
}
}

@CompileStatic(TypeCheckingMode.SKIP)
private
static void reconfigurePathSensitivityForDataBindingDependencyArtifacts(Project project, AndroidJavaCompile task) {
def originalValue

project.gradle.taskGraph.beforeTask {
if (task == it) {
originalValue = task.dataBindingDependencyArtifacts
if (originalValue != null) {
task.dataBindingDependencyArtifacts = project.files()
task.inputs.files(originalValue)
.withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("dataBindingDependencyArtifacts.workaround")
}
}
}

task.doFirst {
task.dataBindingDependencyArtifacts = originalValue
}
}

@CompileStatic(TypeCheckingMode.SKIP)
private static void filterDataBindingInfoFromSource(Project project, AndroidJavaCompile task) {
def originalValue

project.gradle.taskGraph.beforeTask {
if (task == it) {
originalValue = task.source
if (originalValue != null) {
task.source = project.files()
def filteredSources = originalValue.matching { PatternFilterable filter ->
filter.exclude("android/databinding/layouts/DataBindingInfo.java")
}
task.inputs.files(filteredSources)
.withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("source.workaround")
.skipWhenEmpty()
}
}
}

task.doFirst {
task.source = originalValue
}
}


@CompileStatic(TypeCheckingMode.SKIP)
private static void configureAdditionalOutputs(Project project, AndroidJavaCompile task, List<AnnotationProcessorOverride> overrides) {
def configTask = project.tasks.create("configure" + task.name.capitalize()) { configTask ->
configTask.doFirst {
overrides.each {
it.configureAndroidJavaCompile(task)
}
}
}
task.dependsOn configTask
}
}

/**
* Override path sensitivity for {@link ExtractAnnotations#getSource()} to {@link PathSensitivity#RELATIVE}.
*/
@AndroidIssue(introducedIn = "3.0.0", fixedIn = "3.1.0-alpha01", link = "https://issuetracker.google.com/issues/68759476")
static class ExtractAnnotations_Source_Workaround implements Workaround {
@CompileStatic(TypeCheckingMode.SKIP)
@Override
void apply(Project project) {
void apply(WorkaroundContext context) {
def project = context.project
project.tasks.withType(ExtractAnnotations) { ExtractAnnotations task ->
def originalValue

Expand Down Expand Up @@ -193,7 +283,8 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
static class CombinedInput_Workaround implements Workaround {
@CompileStatic(TypeCheckingMode.SKIP)
@Override
void apply(Project project) {
void apply(WorkaroundContext context) {
def project = context.project
project.tasks.withType(IncrementalTask) { IncrementalTask task ->
task.inputs.property "combinedInput", ""
task.inputs.property "combinedInput.workaround", {
Expand Down Expand Up @@ -224,7 +315,8 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
static class ProcessAndroidResources_MergeBlameLogFolder_Workaround implements Workaround {
@CompileStatic(TypeCheckingMode.SKIP)
@Override
void apply(Project project) {
void apply(WorkaroundContext context) {
def project = context.project
project.tasks.withType(ProcessAndroidResources) { ProcessAndroidResources task ->
task.inputs.property "mergeBlameLogFolder", ""
}
Expand All @@ -238,7 +330,8 @@ class AndroidCacheFixPlugin implements Plugin<Project> {
static class CheckManifest_Manifest_Workaround implements Workaround {
@CompileStatic(TypeCheckingMode.SKIP)
@Override
void apply(Project project) {
void apply(WorkaroundContext context) {
def project = context.project
project.tasks.withType(CheckManifest) { CheckManifest task ->
task.inputs.property "manifest", ""
}
Expand Down
151 changes: 151 additions & 0 deletions src/main/groovy/org/gradle/android/CompilerArgsProcessor.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package org.gradle.android

import com.android.build.gradle.tasks.factory.AndroidJavaCompile
import groovy.transform.CompileStatic
import groovy.transform.TypeCheckingMode
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.internal.BiAction

import java.util.regex.Matcher
import java.util.regex.Pattern

@CompileStatic
class CompilerArgsProcessor {
private final List<Rule> rules
private final Project project
private boolean applied

CompilerArgsProcessor(Project project) {
this.project = project
this.rules = [new Rule(Pattern.compile(".*")) {
@Override
void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs) {
processedArgs.add(match.group())
}
}] as List<Rule>
}

void addRule(Rule rule) {
ensureApplied()
rules.add(0, rule)
}

@CompileStatic(TypeCheckingMode.SKIP)
private void ensureApplied() {
if (applied) {
return
}
applied = true

project.tasks.withType(AndroidJavaCompile) { AndroidJavaCompile task ->
project.gradle.taskGraph.beforeTask {
if (task == it) {
def processedArgs = processArgs(task.options.compilerArgs)
overrideProperty(task, processedArgs)
}
}
}
}

List<String> processArgs(List<String> args) {
def processedArgs = []
def remainingArgs = args.iterator()
while (remainingArgs.hasNext()) {
def arg = remainingArgs.next()
for (Rule rule : rules) {
def matcher = rule.pattern.matcher(arg)
if (matcher.matches()) {
rule.process(matcher, processedArgs, remainingArgs)
break
}
}
}
return processedArgs
}

@CompileStatic(TypeCheckingMode.SKIP)
private static void overrideProperty(AndroidJavaCompile task, List processedArgs) {
task.inputs.property "options.compilerArgs", ""
task.inputs.property "options.compilerArgs.filtered", ""
task.inputs.property "options.compilerArgs.workaround", processedArgs
}

static class AnnotationProcessorOverride extends Rule {
private final BiAction<? super Task, String> action

AnnotationProcessorOverride(String property, BiAction<? super Task, String> action) {
super(Pattern.compile("-A${Pattern.quote(property)}=(.*)"))
this.action = action
}

static AnnotationProcessorOverride of(String property, BiAction<? super Task, String> action) {
return new AnnotationProcessorOverride(property, action)
}

void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs) {
// Skip the arg
}

void configureAndroidJavaCompile(AndroidJavaCompile task) {
configureTask(task, task.options.compilerArgs)
}

void configureTask(Task task, List<String> args) {
for (String arg : (args)) {
def matcher = pattern.matcher(arg)
if (matcher.matches()) {
def path = matcher.group(1)
action.execute(task, path)
break
}
}
}
}

static class Skip extends Rule {
Skip(Pattern pattern) {
super(pattern)
}

static Skip matching(String pattern) {
return new Skip(Pattern.compile(pattern))
}

@Override
void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs) {
}
}

static class SkipNext extends Rule {
SkipNext(Pattern pattern) {
super(pattern)
}

static SkipNext matching(String pattern) {
return new SkipNext(Pattern.compile(pattern))
}

@Override
void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs) {
if (remainingArgs.hasNext()) {
remainingArgs.next()
}
}
}

static abstract class Rule {
final Pattern pattern

Rule(Pattern pattern) {
this.pattern = pattern
}

abstract void process(Matcher match, Collection<String> processedArgs, Iterator<String> remainingArgs)

@Override
String toString() {
return "${getClass().simpleName}[${pattern.pattern()}]"
}
}
}
Loading

0 comments on commit 551ea97

Please sign in to comment.