From 249062d1d193bfece8acb419259a7d56ea14936f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Tue, 21 Nov 2017 09:04:18 -0800 Subject: [PATCH 01/14] introduce gradle plugin for henson --- henson-plugin/build.gradle | 9 +++++++ henson-plugin/gradle.properties | 3 +++ .../src/main/groovy/HensonPlugin.java | 25 +++++++++++++++++++ .../main/groovy/HensonPluginExtension.java | 4 +++ .../java/CompileNavigationSourceTree.java | 2 ++ .../main/java/JarNavigationSourceTree.java | 2 ++ settings.gradle | 1 + 7 files changed, 46 insertions(+) create mode 100644 henson-plugin/build.gradle create mode 100644 henson-plugin/gradle.properties create mode 100644 henson-plugin/src/main/groovy/HensonPlugin.java create mode 100644 henson-plugin/src/main/groovy/HensonPluginExtension.java create mode 100644 henson-plugin/src/main/java/CompileNavigationSourceTree.java create mode 100644 henson-plugin/src/main/java/JarNavigationSourceTree.java diff --git a/henson-plugin/build.gradle b/henson-plugin/build.gradle new file mode 100644 index 00000000..9fd04ae1 --- /dev/null +++ b/henson-plugin/build.gradle @@ -0,0 +1,9 @@ +apply plugin: 'groovy' + +dependencies { + compile gradleApi() + compile localGroovy() +} + +//TODO : Does the release work ? +apply from: rootProject.file('gradle/gradle-mvn-push.gradle') \ No newline at end of file diff --git a/henson-plugin/gradle.properties b/henson-plugin/gradle.properties new file mode 100644 index 00000000..f9011324 --- /dev/null +++ b/henson-plugin/gradle.properties @@ -0,0 +1,3 @@ +POM_ARTIFACT_ID=henson-plugin +POM_NAME=Henson Gradle Plugin +POM_PACKAGING=jar \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/HensonPlugin.java b/henson-plugin/src/main/groovy/HensonPlugin.java new file mode 100644 index 00000000..5f4f61ec --- /dev/null +++ b/henson-plugin/src/main/groovy/HensonPlugin.java @@ -0,0 +1,25 @@ +import org.gradle.api.Plugin; +import org.gradle.api.Project; + +class HensonPlugin implements Plugin { + public void apply(Project project) { + + //create extension + + //create source sets + + //create configurations + //create dependencies + //create tasks: compile and jar + //create artifacts + + +/* + def extension = project.extensions.create('greeting', GreetingPluginExtension, project) + project.tasks.create('hello', Greeting) { + message = extension.message + outputFiles = extension.outputFiles + } +*/ + } +} \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/HensonPluginExtension.java b/henson-plugin/src/main/groovy/HensonPluginExtension.java new file mode 100644 index 00000000..67051bf9 --- /dev/null +++ b/henson-plugin/src/main/groovy/HensonPluginExtension.java @@ -0,0 +1,4 @@ +class HensonPluginExtension { + HensonPluginExtension(Project project) { + } +} \ No newline at end of file diff --git a/henson-plugin/src/main/java/CompileNavigationSourceTree.java b/henson-plugin/src/main/java/CompileNavigationSourceTree.java new file mode 100644 index 00000000..61bd347d --- /dev/null +++ b/henson-plugin/src/main/java/CompileNavigationSourceTree.java @@ -0,0 +1,2 @@ +class CompileNavigationSourceTree extends DefaultTask { +} \ No newline at end of file diff --git a/henson-plugin/src/main/java/JarNavigationSourceTree.java b/henson-plugin/src/main/java/JarNavigationSourceTree.java new file mode 100644 index 00000000..61bd347d --- /dev/null +++ b/henson-plugin/src/main/java/JarNavigationSourceTree.java @@ -0,0 +1,2 @@ +class CompileNavigationSourceTree extends DefaultTask { +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 2c09b94f..eb5099aa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,7 @@ include 'dart' include 'dart-processor' include 'henson' include 'henson-processor' +include 'henson-plugin' //TODO make it self contained, not a child //android apps break with a build task From 95144d191e36a3097dcdf5e00645b471730931aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Tue, 21 Nov 2017 15:54:56 -0800 Subject: [PATCH 02/14] first tests almost passing using spock. --- henson-plugin/build.gradle | 44 +++++++++- .../plugin/HensonPluginFunctionalTest.groovy | 80 +++++++++++++++++++ .../src/main/groovy/HensonPlugin.java | 25 ------ .../dart/henson/plugin/HensonPlugin.groovy | 64 +++++++++++++++ .../plugin/HensonPluginExtension.groovy} | 4 + .../java/CompileNavigationSourceTree.java | 2 - .../main/java/JarNavigationSourceTree.java | 2 - .../plugin/CompileNavigationSourceTree.java | 6 ++ .../plugin/JarNavigationSourceTree.java | 6 ++ 9 files changed, 203 insertions(+), 30 deletions(-) create mode 100644 henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy delete mode 100644 henson-plugin/src/main/groovy/HensonPlugin.java create mode 100644 henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy rename henson-plugin/src/main/groovy/{HensonPluginExtension.java => dart/henson/plugin/HensonPluginExtension.groovy} (58%) delete mode 100644 henson-plugin/src/main/java/CompileNavigationSourceTree.java delete mode 100644 henson-plugin/src/main/java/JarNavigationSourceTree.java create mode 100644 henson-plugin/src/main/java/dart/henson/plugin/CompileNavigationSourceTree.java create mode 100644 henson-plugin/src/main/java/dart/henson/plugin/JarNavigationSourceTree.java diff --git a/henson-plugin/build.gradle b/henson-plugin/build.gradle index 9fd04ae1..1d81c79e 100644 --- a/henson-plugin/build.gradle +++ b/henson-plugin/build.gradle @@ -1,8 +1,50 @@ apply plugin: 'groovy' +apply plugin: 'java-gradle-plugin' + + +sourceSets { + functionalTest { + groovy.srcDir file('src/functTest/groovy') + resources.srcDir file('src/functTest/resources') + compileClasspath += sourceSets.main.output + configurations.testRuntime + runtimeClasspath += output + compileClasspath + } +} + +gradlePlugin { + plugins { + hensonPlugin { + id = 'dart.henson-plugin' + implementationClass = 'dart.henson.plugin.HensonPlugin' + } + } + testSourceSets sourceSets.functionalTest +} + +task functionalTest(type: Test) { + description = 'Runs the functional tests.' + group = 'verification' + testClassesDirs = sourceSets.functionalTest.output.classesDirs + classpath = sourceSets.functionalTest.runtimeClasspath + mustRunAfter test +} + +check.dependsOn functionalTest + +repositories { + jcenter() + google() + mavenLocal() +} dependencies { - compile gradleApi() compile localGroovy() + implementation 'com.android.tools.build:gradle:3.0.0' + + functionalTestCompile('org.spockframework:spock-core:1.1-groovy-2.4') { + exclude group: 'org.codehaus.groovy' + } + functionalTestCompile gradleTestKit() } //TODO : Does the release work ? diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy new file mode 100644 index 00000000..0c9b46cd --- /dev/null +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -0,0 +1,80 @@ +package dart.henson.plugin + +import org.gradle.testkit.runner.GradleRunner +import org.junit.Rule +import org.junit.rules.TemporaryFolder + +import spock.lang.Specification + +class HensonPluginFunctionalTest extends Specification { + @Rule TemporaryFolder testProjectDir = new TemporaryFolder() + File buildFile + + def setup() { + buildFile = testProjectDir.newFile('build.gradle') + } + + def "fails on non android projects"() { + buildFile << """ + plugins { + id 'java-library' + id 'dart.henson-plugin' + } + """ + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments('build') + .withPluginClasspath() + .build() + + then: + org.gradle.testkit.runner.UnexpectedBuildFailure ex = thrown() + ex.message.contains("'android' or 'android-library' plugin required.") + } + + def "applies to android projects"() { + buildFile << """ + buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.0.1' + } + } + + plugins { + //the order matters here + id 'com.android.application' + id 'dart.henson-plugin' + } + + android { + compileSdkVersion 26 + defaultConfig { + applicationId 'test' + minSdkVersion 26 + targetSdkVersion 26 + versionCode 1 + versionName '1.0.0' + } + } + """ + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments('--no-build-cache', 'assembleDebug', '-d', '-s') + .withPluginClasspath() + .build() + + then: + result.output.contains("debug") + result.output.contains("release") + result.task(":assembleDebug").outcome == SUCCESS + } +} \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/HensonPlugin.java b/henson-plugin/src/main/groovy/HensonPlugin.java deleted file mode 100644 index 5f4f61ec..00000000 --- a/henson-plugin/src/main/groovy/HensonPlugin.java +++ /dev/null @@ -1,25 +0,0 @@ -import org.gradle.api.Plugin; -import org.gradle.api.Project; - -class HensonPlugin implements Plugin { - public void apply(Project project) { - - //create extension - - //create source sets - - //create configurations - //create dependencies - //create tasks: compile and jar - //create artifacts - - -/* - def extension = project.extensions.create('greeting', GreetingPluginExtension, project) - project.tasks.create('hello', Greeting) { - message = extension.message - outputFiles = extension.outputFiles - } -*/ - } -} \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy new file mode 100644 index 00000000..8db33e58 --- /dev/null +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -0,0 +1,64 @@ +package dart.henson.plugin + +import com.android.build.gradle.api.BaseVariant +import org.gradle.api.Plugin +import org.gradle.api.Project +import com.android.build.gradle.AppPlugin +import com.android.build.gradle.LibraryPlugin +import org.gradle.api.plugins.PluginCollection + +class HensonPlugin implements Plugin { + void apply(Project project) { + final def log = project.logger + final String LOG_TAG = "HENSON" + + //check project + def hasAppPlugin = project.plugins.withType(AppPlugin) + def hasLibPlugin = project.plugins.withType(LibraryPlugin) + checkProject(hasAppPlugin, hasLibPlugin) + + //get Variants + def variants = getVariants(project, hasAppPlugin) + + //create extension + createExtension(project) + + //create source sets + variants.all { variant -> + println variants.name + } + + //create configurations + //create dependencies + //create tasks: compile and jar + //create artifacts + + +/* + def extension = project.extensions.create('greeting', GreetingPluginExtension, project) + project.tasks.create('hello', Greeting) { + message = extension.message + outputFiles = extension.outputFiles + } +*/ + } + + private boolean checkProject(PluginCollection hasApp, + PluginCollection hasLib) { + if (!hasApp && !hasLib) { + throw new IllegalStateException("'android' or 'android-library' plugin required.") + } + return !hasApp + } + + private Collection getVariants(Project project, PluginCollection hasApp) { + if (hasApp) { + project.android.applicationVariants + } else { + project.android.libraryVariants + } + } + private void createExtension(Project project) { + project.extensions.create('henson', HensonPluginExtension, project) + } +} \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/HensonPluginExtension.java b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy similarity index 58% rename from henson-plugin/src/main/groovy/HensonPluginExtension.java rename to henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy index 67051bf9..6c965237 100644 --- a/henson-plugin/src/main/groovy/HensonPluginExtension.java +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy @@ -1,3 +1,7 @@ +package dart.henson.plugin + +import org.gradle.api.Project + class HensonPluginExtension { HensonPluginExtension(Project project) { } diff --git a/henson-plugin/src/main/java/CompileNavigationSourceTree.java b/henson-plugin/src/main/java/CompileNavigationSourceTree.java deleted file mode 100644 index 61bd347d..00000000 --- a/henson-plugin/src/main/java/CompileNavigationSourceTree.java +++ /dev/null @@ -1,2 +0,0 @@ -class CompileNavigationSourceTree extends DefaultTask { -} \ No newline at end of file diff --git a/henson-plugin/src/main/java/JarNavigationSourceTree.java b/henson-plugin/src/main/java/JarNavigationSourceTree.java deleted file mode 100644 index 61bd347d..00000000 --- a/henson-plugin/src/main/java/JarNavigationSourceTree.java +++ /dev/null @@ -1,2 +0,0 @@ -class CompileNavigationSourceTree extends DefaultTask { -} \ No newline at end of file diff --git a/henson-plugin/src/main/java/dart/henson/plugin/CompileNavigationSourceTree.java b/henson-plugin/src/main/java/dart/henson/plugin/CompileNavigationSourceTree.java new file mode 100644 index 00000000..d1e1edb7 --- /dev/null +++ b/henson-plugin/src/main/java/dart/henson/plugin/CompileNavigationSourceTree.java @@ -0,0 +1,6 @@ +package dart.henson.plugin; + +import org.gradle.api.DefaultTask; + +class CompileNavigationSourceTree extends DefaultTask { +} \ No newline at end of file diff --git a/henson-plugin/src/main/java/dart/henson/plugin/JarNavigationSourceTree.java b/henson-plugin/src/main/java/dart/henson/plugin/JarNavigationSourceTree.java new file mode 100644 index 00000000..3727bd20 --- /dev/null +++ b/henson-plugin/src/main/java/dart/henson/plugin/JarNavigationSourceTree.java @@ -0,0 +1,6 @@ +package dart.henson.plugin; + +import org.gradle.api.DefaultTask; + +class JarNavigationSourceTree extends DefaultTask { +} \ No newline at end of file From db1b3278745ea8c1c96007b0817107ff709c2ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Wed, 22 Nov 2017 06:04:34 -0800 Subject: [PATCH 03/14] test pass. I can test an android project's plugin application --- .../plugin/HensonPluginFunctionalTest.groovy | 22 +++++++++++++++---- .../dart/henson/plugin/HensonPlugin.groovy | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index 0c9b46cd..98c36aa3 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -5,13 +5,17 @@ import org.junit.Rule import org.junit.rules.TemporaryFolder import spock.lang.Specification +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class HensonPluginFunctionalTest extends Specification { @Rule TemporaryFolder testProjectDir = new TemporaryFolder() File buildFile + File manifestFile def setup() { buildFile = testProjectDir.newFile('build.gradle') + testProjectDir.newFolder('src','main') + manifestFile = testProjectDir.newFile('src/main/AndroidManifest.xml') } def "fails on non android projects"() { @@ -35,6 +39,16 @@ class HensonPluginFunctionalTest extends Specification { } def "applies to android projects"() { + manifestFile << """ + + + + + """ + buildFile << """ buildscript { repositories { @@ -68,13 +82,13 @@ class HensonPluginFunctionalTest extends Specification { when: def result = GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments('--no-build-cache', 'assembleDebug', '-d', '-s') + .withArguments('--no-build-cache', 'assemble', '-d', '-s') .withPluginClasspath() .build() then: - result.output.contains("debug") - result.output.contains("release") - result.task(":assembleDebug").outcome == SUCCESS + result.output.contains("Variant name: debug") + result.output.contains("Variant name: release") + result.task(":assemble").outcome == SUCCESS } } \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index 8db33e58..57d3eb16 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -25,7 +25,7 @@ class HensonPlugin implements Plugin { //create source sets variants.all { variant -> - println variants.name + println "Variant name: ${variant.name}" } //create configurations From fda7e63fa013f5e3c1a63f97c982f42128735bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Wed, 22 Nov 2017 10:04:53 -0800 Subject: [PATCH 04/14] Create source sets for main, build types, flavors and variants --- .../plugin/HensonPluginFunctionalTest.groovy | 12 ++++++ .../dart/henson/plugin/HensonPlugin.groovy | 43 +++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index 98c36aa3..0ea14016 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -76,6 +76,18 @@ class HensonPluginFunctionalTest extends Specification { versionCode 1 versionName '1.0.0' } + flavorDimensions "brand" + + productFlavors { + groupon { + applicationId "com.groupon" + dimension "brand" + } + livingsocial { + applicationId "com.livingsocial.www" + dimension "brand" + } + } } """ diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index 57d3eb16..dea30b32 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -18,14 +18,39 @@ class HensonPlugin implements Plugin { checkProject(hasAppPlugin, hasLibPlugin) //get Variants - def variants = getVariants(project, hasAppPlugin) + //def variants = getVariants(project, hasAppPlugin) //create extension createExtension(project) //create source sets - variants.all { variant -> - println "Variant name: ${variant.name}" + //the main source set + def sourceSetName = "main" + def newSourceSetName = "navigation" + def newSourceSetPath = "src/navigation/" + createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + + project.android.buildTypes.all { buildType -> + sourceSetName = "${buildType.name}" + newSourceSetName = "navigation${buildType.name.capitalize()}" + newSourceSetPath = "src/navigation/${buildType.name}" + createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + } + + project.android.productFlavors.all { productFlavor -> + sourceSetName = "${productFlavor.name}" + newSourceSetName = "navigation${productFlavor.name.capitalize()}" + newSourceSetPath = "src/navigation/${productFlavor.name}" + createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + } + + project.android.buildTypes.all { buildType -> + project.android.productFlavors.all { productFlavor -> + sourceSetName = "${productFlavor.name}${buildType.name.capitalize()}" + newSourceSetName = "navigation${productFlavor.name.capitalize()}${buildType.name.capitalize()}" + newSourceSetPath = "src/navigation/${productFlavor.name}/${buildType.name}" + createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + } } //create configurations @@ -43,6 +68,18 @@ class HensonPlugin implements Plugin { */ } + private void createNavigationSourceSet(Project project, sourceSetName, newSourceSetName, newSourceSetPath) { + println "Creating sourceSet: ${sourceSetName}->${newSourceSetName} with root in '${newSourceSetPath}'" + project.android.sourceSets { + "${newSourceSetName}" { + setRoot "${newSourceSetPath}" + } + "${sourceSetName}" { + java.srcDirs = project.android.sourceSets["${sourceSetName}"].java.srcDirs.collect() << "${newSourceSetPath}/java" + } + } + } + private boolean checkProject(PluginCollection hasApp, PluginCollection hasLib) { if (!hasApp && !hasLib) { From f7250f7d3f957a194867f5f3e21b5e0e91c8d33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Wed, 22 Nov 2017 15:10:45 -0800 Subject: [PATCH 05/14] the plugin should work --- henson-plugin/build.gradle | 14 ++ .../dart/henson/plugin/HensonPlugin.groovy | 124 ++++++++++++++++-- .../src/main/resources/build.properties | 2 + 3 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 henson-plugin/src/main/resources/build.properties diff --git a/henson-plugin/build.gradle b/henson-plugin/build.gradle index 1d81c79e..8612eb7b 100644 --- a/henson-plugin/build.gradle +++ b/henson-plugin/build.gradle @@ -31,6 +31,20 @@ task functionalTest(type: Test) { check.dependsOn functionalTest +project.afterEvaluate { + tasks.getByName('compileGroovy').doFirst { + //we create a file in the plugin project containing the current project version + //it will be used later by the plugin to add the proper version of + //dependencies to the project that uses the plugin + def prop = new Properties() + def propFile = new File("${project.rootDir}/henson-plugin/src/main/resources/build.properties") + propFile.parentFile.mkdirs() + prop.setProperty("dart.version", "$version") + propFile.createNewFile() + prop.store(propFile.newWriter(), null) + } +} + repositories { jcenter() google() diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index dea30b32..0fd37c2b 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -1,11 +1,15 @@ package dart.henson.plugin import com.android.build.gradle.api.BaseVariant +import org.gradle.api.JavaVersion import org.gradle.api.Plugin import org.gradle.api.Project import com.android.build.gradle.AppPlugin import com.android.build.gradle.LibraryPlugin +import org.gradle.api.Task import org.gradle.api.plugins.PluginCollection +import org.gradle.api.tasks.bundling.Jar +import org.gradle.api.tasks.compile.JavaCompile class HensonPlugin implements Plugin { void apply(Project project) { @@ -17,24 +21,50 @@ class HensonPlugin implements Plugin { def hasLibPlugin = project.plugins.withType(LibraryPlugin) checkProject(hasAppPlugin, hasLibPlugin) + //we use the file build.properties that contains the version of + //the extension to use. This avoids all problems related to using version x.y.+ + def versionName = getVersionName() + //get Variants //def variants = getVariants(project, hasAppPlugin) //create extension createExtension(project) - //create source sets + //we do the following for all sourcesets, of all build types, of all flavors, and all variants + // create source sets + // create configurations + // create dependencies + // create tasks: compile and jar + // create artifacts + //the main source set def sourceSetName = "main" def newSourceSetName = "navigation" def newSourceSetPath = "src/navigation/" createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + def newArtifactName = "intentBuilder" + def newConfigurationName = "navigation" + createNavigationConfiguration(project, newArtifactName, newConfigurationName, versionName) + + def intentBuilderCompileTask = createIntentBuilderCompileTask(project, "", "main/", "navigation", "navigation") + def intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompileTask, "") + addArtifact(project,"") + project.android.buildTypes.all { buildType -> sourceSetName = "${buildType.name}" newSourceSetName = "navigation${buildType.name.capitalize()}" newSourceSetPath = "src/navigation/${buildType.name}" createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + + newArtifactName = "intentBuilder${buildType.name.capitalize()}" + newConfigurationName = "navigation${buildType.name.capitalize()}" + createNavigationConfiguration(project, newArtifactName, newConfigurationName, versionName) + + intentBuilderCompileTask = createIntentBuilderCompileTask(project, "${buildType.name.capitalize()}", "${buildType.name}/", "navigation${buildType.name.capitalize()}", "navigation${buildType.name.capitalize()}") + intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompileTask, "${buildType.name.capitalize()}") + addArtifact(project,"${buildType.name.capitalize()}") } project.android.productFlavors.all { productFlavor -> @@ -42,6 +72,14 @@ class HensonPlugin implements Plugin { newSourceSetName = "navigation${productFlavor.name.capitalize()}" newSourceSetPath = "src/navigation/${productFlavor.name}" createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + + newArtifactName = "intentBuilder${productFlavor.name.capitalize()}" + newConfigurationName = "navigation${productFlavor.name.capitalize()}" + createNavigationConfiguration(project, newArtifactName, newConfigurationName, versionName) + + intentBuilderCompileTask = createIntentBuilderCompileTask(project, "${productFlavor.name.capitalize()}", "${productFlavor.name}/", "navigation${productFlavor.name.capitalize()}", "navigation${productFlavor.name.capitalize()}") + intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompileTask, "${productFlavor.name.capitalize()}") + addArtifact(project,"${productFlavor.name.capitalize()}") } project.android.buildTypes.all { buildType -> @@ -50,22 +88,86 @@ class HensonPlugin implements Plugin { newSourceSetName = "navigation${productFlavor.name.capitalize()}${buildType.name.capitalize()}" newSourceSetPath = "src/navigation/${productFlavor.name}/${buildType.name}" createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + + newArtifactName = "intentBuilder${productFlavor.name.capitalize()}${buildType.name.capitalize()}" + newConfigurationName = "navigation${productFlavor.name.capitalize()}${buildType.name.capitalize()}" + createNavigationConfiguration(project, newArtifactName, newConfigurationName, versionName) + + intentBuilderCompileTask = createIntentBuilderCompileTask(project, "${productFlavor.name.capitalize()}${buildType.name.capitalize()}", "${productFlavor.name}/${buildType.name}/", "${newSourceSetName}", "${newConfigurationName}") + intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompileTask, "${productFlavor.name.capitalize()}${buildType.name.capitalize()}") + addArtifact(project,"${productFlavor.name.capitalize()}${buildType.name.capitalize()}") + } + } + } + + private Object getVersionName() { + Properties properties = new Properties() + properties.load(getClass().getClassLoader().getResourceAsStream("build.properties")) + properties.get("dart.version") + } + + private Task createIntentBuilderCompileTask(Project project, taskSuffix, path, sourceSetName, configurationName) { + def newDestinationDirName = "${project.buildDir}/navigation/classes/java/${path}" + def newGeneratedDirName = "${project.buildDir}/generated/source/apt/navigation/${path}" + project.tasks.create("intentBuilderCompile${taskSuffix}", JavaCompile) { + setSource(project.android.sourceSets["${sourceSetName}"].java.sourceFiles) + setDestinationDir(project.file("${newDestinationDirName}")) + classpath = project.configurations["${configurationName}Api"] + options.compilerArgs = ["-s", "${newGeneratedDirName}"] + options.annotationProcessorPath = project.configurations["${configurationName}AnnotationProcessor"] + targetCompatibility = JavaVersion.VERSION_1_7 + sourceCompatibility = JavaVersion.VERSION_1_7 + doFirst { + project.file("${newGeneratedDirName}").mkdirs() + project.file("${newDestinationDirName}").mkdirs() } } + } + + private Task createIntentBuilderJarTask(Project project, intentBuilderCompileTask, taskSuffix) { + def task = project.tasks.create("intentBuilderJar${taskSuffix}", Jar) { + baseName = "${project.name}-intentBuilder${taskSuffix}" + from intentBuilderCompileTask.destinationDir + include('**/**__IntentBuilder*.class', '**/Henson*.class') + } + task.dependsOn(intentBuilderCompileTask) + task + } + + private void addArtifact(Project project, taskSuffix) { + println project.configurations.getByName("intentBuilder") + project.artifacts.add("intentBuilder${taskSuffix}", project.tasks["intentBuilderJar${taskSuffix}"]) + } + + private void addDependenciesToConfiguration(Project project, configurationName, versionName) { + project.dependencies { + "${configurationName}Api" "com.f2prateek.dart:dart-annotations:${versionName}" + "${configurationName}Api" "com.f2prateek.dart:dart:${versionName}" + "${configurationName}Api" "com.f2prateek.dart:henson:${versionName}" + "${configurationName}CompileOnly" "com.google.android:android:4.1.1.4" + "${configurationName}AnnotationProcessor" "com.f2prateek.dart:henson-processor:${versionName}" + } + } - //create configurations - //create dependencies - //create tasks: compile and jar - //create artifacts + private void createNavigationConfiguration(Project project, newArtifactName, newConfigurationName, versionName) { + println "Creating configuration: ${newArtifactName}" + project.configurations { + //the name of the artifact + "${newArtifactName}" { + canBeResolved true + } + //the api scope: is there any convention ? apiElements? + "${newConfigurationName}Api" { + canBeResolved true + } -/* - def extension = project.extensions.create('greeting', GreetingPluginExtension, project) - project.tasks.create('hello', Greeting) { - message = extension.message - outputFiles = extension.outputFiles + //the ap scope + "${newConfigurationName}AnnotationProcessor" { + canBeResolved true + } } -*/ + addDependenciesToConfiguration(project, newConfigurationName, versionName) } private void createNavigationSourceSet(Project project, sourceSetName, newSourceSetName, newSourceSetPath) { diff --git a/henson-plugin/src/main/resources/build.properties b/henson-plugin/src/main/resources/build.properties new file mode 100644 index 00000000..9bb389ee --- /dev/null +++ b/henson-plugin/src/main/resources/build.properties @@ -0,0 +1,2 @@ +#Wed Nov 22 15:10:02 PST 2017 +dart.version=3.0.0-RC1-SNAPSHOT From 9140b462a27255482cdfa5a7658c44511800e00e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Wed, 22 Nov 2017 20:00:12 -0800 Subject: [PATCH 06/14] plugin seems to work. We got 'some kind of tests' --- .../plugin/HensonPluginFunctionalTest.groovy | 22 ++++++++++--------- .../src/main/resources/build.properties | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index 0ea14016..9455125f 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -76,16 +76,16 @@ class HensonPluginFunctionalTest extends Specification { versionCode 1 versionName '1.0.0' } - flavorDimensions "brand" + flavorDimensions "color" productFlavors { - groupon { - applicationId "com.groupon" - dimension "brand" + red { + applicationId "com.blue" + dimension "color" } - livingsocial { - applicationId "com.livingsocial.www" - dimension "brand" + blue { + applicationId "com.red" + dimension "color" } } } @@ -94,13 +94,15 @@ class HensonPluginFunctionalTest extends Specification { when: def result = GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments('--no-build-cache', 'assemble', '-d', '-s') + .withArguments('--no-build-cache', 'assemble', 'intentBuilderJar', 'intentBuilderJarRed', 'intentBuilderJarRelease', 'intentBuilderJarBlueDebug', '-d', '-s') .withPluginClasspath() .build() then: - result.output.contains("Variant name: debug") - result.output.contains("Variant name: release") result.task(":assemble").outcome == SUCCESS + result.task(":intentBuilderJar").outcome == SUCCESS + result.task(":intentBuilderJarRed").outcome == SUCCESS + result.task(":intentBuilderJarRelease").outcome == SUCCESS + result.task(":intentBuilderJarBlueDebug").outcome == SUCCESS } } \ No newline at end of file diff --git a/henson-plugin/src/main/resources/build.properties b/henson-plugin/src/main/resources/build.properties index 9bb389ee..a36b332c 100644 --- a/henson-plugin/src/main/resources/build.properties +++ b/henson-plugin/src/main/resources/build.properties @@ -1,2 +1,2 @@ -#Wed Nov 22 15:10:02 PST 2017 +#Wed Nov 22 19:58:08 PST 2017 dart.version=3.0.0-RC1-SNAPSHOT From 1a6e6566ca610f331b47cc4e9b1bcc630ebf5c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Wed, 29 Nov 2017 20:30:35 -0800 Subject: [PATCH 07/14] all works. We can now define navigation sources per build type, flavors, variants + add custom dependencies to each configuration. The navigation api is compiled correctly, jared correctly, it contains the model, the intent builder and henson (for now). The main source set itself dependsn on the api. All artifacts related to dart and henson are handled automatically --- .../plugin/HensonPluginFunctionalTest.groovy | 89 ++++++- .../dart/henson/plugin/HensonPlugin.groovy | 223 ++++++++++++------ .../henson/plugin/NavigationVariant.groovy | 14 ++ .../plugin/CompileNavigationSourceTree.java | 6 - .../plugin/JarNavigationSourceTree.java | 6 - .../src/main/resources/build.properties | 2 +- 6 files changed, 247 insertions(+), 93 deletions(-) create mode 100644 henson-plugin/src/main/groovy/dart/henson/plugin/NavigationVariant.groovy delete mode 100644 henson-plugin/src/main/java/dart/henson/plugin/CompileNavigationSourceTree.java delete mode 100644 henson-plugin/src/main/java/dart/henson/plugin/JarNavigationSourceTree.java diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index 9455125f..bab8e52f 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -5,17 +5,29 @@ import org.junit.Rule import org.junit.rules.TemporaryFolder import spock.lang.Specification -import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +import java.util.zip.ZipFile + +import static org.gradle.testkit.runner.TaskOutcome.FAILED +import static groovy.io.FileType.FILES class HensonPluginFunctionalTest extends Specification { @Rule TemporaryFolder testProjectDir = new TemporaryFolder() + File settingsFile File buildFile File manifestFile + File srcMain + File srcNavigationMain def setup() { + settingsFile = testProjectDir.newFile('settings.gradle') buildFile = testProjectDir.newFile('build.gradle') testProjectDir.newFolder('src','main') manifestFile = testProjectDir.newFile('src/main/AndroidManifest.xml') + testProjectDir.newFolder('src','main', 'java', 'test') + srcMain = testProjectDir.newFile('src/main/java/test/FooActivity.java') + testProjectDir.newFolder('src','navigation', 'main', 'java', 'test') + srcNavigationMain = testProjectDir.newFile('src/navigation/main/java/test/Foo.java') } def "fails on non android projects"() { @@ -48,12 +60,46 @@ class HensonPluginFunctionalTest extends Specification { android:name=".Test"/> """ + srcMain << """ + package test; + + import android.app.Activity; + import android.os.Bundle; + + class FooActivity extends Activity { + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + Foo foo = new Foo(); + } + } + """ + srcNavigationMain << """ + package test; + + import dart.BindExtra; + import dart.DartModel; + + @DartModel("test.TestActivity") + class Foo { + @BindExtra String s; + } + """ + + settingsFile << """ + rootProject.name = "test-project" + """ buildFile << """ buildscript { repositories { google() jcenter() + mavenLocal() + maven { + url 'https://oss.sonatype.org/content/repositories/snapshots' + } } dependencies { @@ -89,20 +135,45 @@ class HensonPluginFunctionalTest extends Specification { } } } + + repositories { + google() + jcenter() + mavenLocal() + maven { + url 'https://oss.sonatype.org/content/repositories/snapshots' + } + } """ when: - def result = GradleRunner.create() + def runner = GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments('--no-build-cache', 'assemble', 'intentBuilderJar', 'intentBuilderJarRed', 'intentBuilderJarRelease', 'intentBuilderJarBlueDebug', '-d', '-s') + //.withArguments('--no-build-cache', 'assemble', 'tasks', '--all', '-d', '-s') + .withArguments('--no-build-cache', 'clean', 'assemble', 'intentBuilderJar', 'intentBuilderJarRed', 'intentBuilderJarRelease', 'intentBuilderJarBlueDebug', '-d', '-s') .withPluginClasspath() - .build() + + def projectDir = runner.projectDir + def result = runner.build() then: - result.task(":assemble").outcome == SUCCESS - result.task(":intentBuilderJar").outcome == SUCCESS - result.task(":intentBuilderJarRed").outcome == SUCCESS - result.task(":intentBuilderJarRelease").outcome == SUCCESS - result.task(":intentBuilderJarBlueDebug").outcome == SUCCESS + println result.output + result.task(":assemble").outcome != FAILED + //result.task(":tasks").outcome == SUCCESS + result.task(":intentBuilderJar").outcome != FAILED + result.task(":intentBuilderJarRed").outcome != FAILED + result.task(":intentBuilderJarRelease").outcome != FAILED + result.task(":intentBuilderJarBlueDebug").outcome != FAILED + println new File(projectDir, "/build").eachFileRecurse(FILES) { + println it + } + println new File(projectDir, "/build/libs").eachFileRecurse(FILES) { + if(it.name.endsWith('.jar')) { + def zip = new ZipFile(it) + zip.entries().each { entry -> + println entry.name + } + } + } } } \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index 0fd37c2b..350f70ee 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -7,11 +7,18 @@ import org.gradle.api.Project import com.android.build.gradle.AppPlugin import com.android.build.gradle.LibraryPlugin import org.gradle.api.Task +import org.gradle.api.artifacts.ModuleDependency +import org.gradle.api.file.FileCollection +import org.gradle.api.internal.file.UnionFileCollection import org.gradle.api.plugins.PluginCollection import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.compile.JavaCompile class HensonPlugin implements Plugin { + + public static final String INTENT_BUILDER_COMPILE_TASK_PREFIX = 'intentBuilderCompile' + public static final String INTENT_BUILDER_JAR_TASK_PREFIX = 'intentBuilderJar' + void apply(Project project) { final def log = project.logger final String LOG_TAG = "HENSON" @@ -23,7 +30,7 @@ class HensonPlugin implements Plugin { //we use the file build.properties that contains the version of //the extension to use. This avoids all problems related to using version x.y.+ - def versionName = getVersionName() + def dartVersionName = getVersionName() //get Variants //def variants = getVariants(project, hasAppPlugin) @@ -39,82 +46,142 @@ class HensonPlugin implements Plugin { // create artifacts //the main source set + def suffix = "" + def pathSuffix = "main/" def sourceSetName = "main" - def newSourceSetName = "navigation" - def newSourceSetPath = "src/navigation/" - createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) - def newArtifactName = "intentBuilder" - def newConfigurationName = "navigation" - createNavigationConfiguration(project, newArtifactName, newConfigurationName, versionName) + createSourceSetAndConfiguration(project, sourceSetName, suffix, pathSuffix, dartVersionName) - def intentBuilderCompileTask = createIntentBuilderCompileTask(project, "", "main/", "navigation", "navigation") - def intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompileTask, "") - addArtifact(project,"") + createEmptyIntentBuilderCompileTask(project, suffix) + createEmptyIntentBuilderJarTask(project, suffix) project.android.buildTypes.all { buildType -> - sourceSetName = "${buildType.name}" - newSourceSetName = "navigation${buildType.name.capitalize()}" - newSourceSetPath = "src/navigation/${buildType.name}" - createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) - - newArtifactName = "intentBuilder${buildType.name.capitalize()}" - newConfigurationName = "navigation${buildType.name.capitalize()}" - createNavigationConfiguration(project, newArtifactName, newConfigurationName, versionName) - - intentBuilderCompileTask = createIntentBuilderCompileTask(project, "${buildType.name.capitalize()}", "${buildType.name}/", "navigation${buildType.name.capitalize()}", "navigation${buildType.name.capitalize()}") - intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompileTask, "${buildType.name.capitalize()}") - addArtifact(project,"${buildType.name.capitalize()}") + println "Processing buildType: ${buildType.name}" + processFlavorOrBuildType(project, buildType, dartVersionName) } project.android.productFlavors.all { productFlavor -> - sourceSetName = "${productFlavor.name}" - newSourceSetName = "navigation${productFlavor.name.capitalize()}" - newSourceSetPath = "src/navigation/${productFlavor.name}" - createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) - - newArtifactName = "intentBuilder${productFlavor.name.capitalize()}" - newConfigurationName = "navigation${productFlavor.name.capitalize()}" - createNavigationConfiguration(project, newArtifactName, newConfigurationName, versionName) - - intentBuilderCompileTask = createIntentBuilderCompileTask(project, "${productFlavor.name.capitalize()}", "${productFlavor.name}/", "navigation${productFlavor.name.capitalize()}", "navigation${productFlavor.name.capitalize()}") - intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompileTask, "${productFlavor.name.capitalize()}") - addArtifact(project,"${productFlavor.name.capitalize()}") + println "Processing flavor: ${productFlavor.name}" + processFlavorOrBuildType(project, productFlavor, dartVersionName) } - project.android.buildTypes.all { buildType -> - project.android.productFlavors.all { productFlavor -> - sourceSetName = "${productFlavor.name}${buildType.name.capitalize()}" - newSourceSetName = "navigation${productFlavor.name.capitalize()}${buildType.name.capitalize()}" - newSourceSetPath = "src/navigation/${productFlavor.name}/${buildType.name}" - createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) - - newArtifactName = "intentBuilder${productFlavor.name.capitalize()}${buildType.name.capitalize()}" - newConfigurationName = "navigation${productFlavor.name.capitalize()}${buildType.name.capitalize()}" - createNavigationConfiguration(project, newArtifactName, newConfigurationName, versionName) - - intentBuilderCompileTask = createIntentBuilderCompileTask(project, "${productFlavor.name.capitalize()}${buildType.name.capitalize()}", "${productFlavor.name}/${buildType.name}/", "${newSourceSetName}", "${newConfigurationName}") - intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompileTask, "${productFlavor.name.capitalize()}${buildType.name.capitalize()}") - addArtifact(project,"${productFlavor.name.capitalize()}${buildType.name.capitalize()}") + project.android.with { + buildTypes.all { buildType -> + productFlavors.all { productFlavor -> + println "Processing variant: ${productFlavor.name}${buildType.name.capitalize()}" + processVariant(project, productFlavor, buildType, dartVersionName) + } } } } + private void processVariant(Project project, productFlavor, buildType, dartVersionName) { + def variantName = "${productFlavor.name}${buildType.name.capitalize()}" + def suffix = "${productFlavor.name.capitalize()}${buildType.name.capitalize()}" + def pathSuffix = "${productFlavor.name}/${buildType.name.capitalize()}/" + createSourceSetAndConfiguration(project, variantName, suffix, pathSuffix, dartVersionName) + + def navigationVariant = createNavigationVariant(project, productFlavor, buildType) + def intentBuilderCompiler = createIntentBuilderCompileTask(project, suffix, pathSuffix, navigationVariant) + def mainCompiler = project.tasks.getByName(INTENT_BUILDER_COMPILE_TASK_PREFIX) + def productFlavorCompiler = project.tasks.getByName(INTENT_BUILDER_COMPILE_TASK_PREFIX + String.valueOf(productFlavor.name.capitalize())) + def buildTypeCompiler = project.tasks.getByName(INTENT_BUILDER_COMPILE_TASK_PREFIX + String.valueOf(buildType.name.capitalize())) + intentBuilderCompiler.dependsOn(mainCompiler, productFlavorCompiler, buildTypeCompiler) + + def intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompiler, suffix) + def mainIntentBuilderJarTask = project.tasks.getByName(INTENT_BUILDER_JAR_TASK_PREFIX) + def productFlavorIntentBuilderJarTask = project.tasks.getByName(INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(productFlavor.name.capitalize())) + def buildTypeIntentBuilderJarTask = project.tasks.getByName(INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(buildType.name.capitalize())) + intentBuilderJarTask.dependsOn(mainIntentBuilderJarTask, productFlavorIntentBuilderJarTask, buildTypeIntentBuilderJarTask) + + addArtifact(project, suffix, suffix) + addNavigationArtifactToDependencies(project, suffix, variantName) + } + + private void processFlavorOrBuildType(Project project, productFlavorOrBuildType, dartVersionName) { + def sourceSetName = "${productFlavorOrBuildType.name}" + def suffix = "${productFlavorOrBuildType.name.capitalize()}" + def pathSuffix = "${productFlavorOrBuildType.name}/" + + createSourceSetAndConfiguration(project, sourceSetName, suffix, pathSuffix, dartVersionName) + + createEmptyIntentBuilderCompileTask(project, suffix) + createEmptyIntentBuilderJarTask(project, suffix) + } + + private void createSourceSetAndConfiguration(Project project, String sourceSetName, String suffix, String pathSuffix, dartVersionName) { + def newSourceSetName = "navigation" + suffix + def newSourceSetPath = "src/navigation/" + pathSuffix + createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) + + def newArtifactName = "intentBuilder" + suffix + createNavigationConfiguration(project, newArtifactName, suffix, dartVersionName) + } + private Object getVersionName() { Properties properties = new Properties() properties.load(getClass().getClassLoader().getResourceAsStream("build.properties")) properties.get("dart.version") } - private Task createIntentBuilderCompileTask(Project project, taskSuffix, path, sourceSetName, configurationName) { - def newDestinationDirName = "${project.buildDir}/navigation/classes/java/${path}" - def newGeneratedDirName = "${project.buildDir}/generated/source/apt/navigation/${path}" + private NavigationVariant createNavigationVariant(Project project, productFlavor, buildType) { + def navigationVariant = new NavigationVariant() + navigationVariant.flavorName = productFlavor.name + navigationVariant.buildTypeName = buildType.name + navigationVariant.sourceSets = [project.android.sourceSets["navigation"] \ + , project.android.sourceSets["navigation${navigationVariant.buildTypeName.capitalize()}"] \ + , project.android.sourceSets["navigation${navigationVariant.flavorName.capitalize()}"] \ + , project.android.sourceSets["navigation${navigationVariant.flavorName.capitalize()}${navigationVariant.buildTypeName.capitalize()}"] + ] + navigationVariant.apiConfigurations = [project.configurations["navigationApi"] \ + , project.configurations["navigation${navigationVariant.buildTypeName.capitalize()}Api"] \ + , project.configurations["navigation${navigationVariant.flavorName.capitalize()}Api"] \ + , project.configurations["navigation${navigationVariant.flavorName.capitalize()}${navigationVariant.buildTypeName.capitalize()}Api"] + ] + navigationVariant.implementationConfigurations = [project.configurations["navigationImplementation"] \ + , project.configurations["navigation${navigationVariant.buildTypeName.capitalize()}Implementation"] \ + , project.configurations["navigation${navigationVariant.flavorName.capitalize()}Implementation"] \ + , project.configurations["navigation${navigationVariant.flavorName.capitalize()}${navigationVariant.buildTypeName.capitalize()}Implementation"] + ] + navigationVariant.compileOnlyConfigurations = [project.configurations["navigationCompileOnly"] \ + , project.configurations["navigation${navigationVariant.buildTypeName.capitalize()}CompileOnly"] \ + , project.configurations["navigation${navigationVariant.flavorName.capitalize()}CompileOnly"] \ + , project.configurations["navigation${navigationVariant.flavorName.capitalize()}${navigationVariant.buildTypeName.capitalize()}CompileOnly"] + ] + navigationVariant.annotationProcessorConfigurations = [project.configurations["navigationAnnotationProcessor"] \ + , project.configurations["navigation${navigationVariant.buildTypeName.capitalize()}AnnotationProcessor"] \ + , project.configurations["navigation${navigationVariant.flavorName.capitalize()}AnnotationProcessor"] \ + , project.configurations["navigation${navigationVariant.flavorName.capitalize()}${navigationVariant.buildTypeName.capitalize()}AnnotationProcessor"] + ] + navigationVariant + } + + private Task createEmptyIntentBuilderCompileTask(Project project, taskSuffix) { + project.tasks.create(INTENT_BUILDER_COMPILE_TASK_PREFIX + String.valueOf(taskSuffix)) + } + + private Task createEmptyIntentBuilderJarTask(Project project, taskSuffix) { + project.tasks.create(INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(taskSuffix)) + } + + private Task createIntentBuilderCompileTask(Project project, taskSuffix, destinationPath, navigationVariant) { + def newDestinationDirName = "${project.buildDir}/navigation/classes/java/${destinationPath}" + def newGeneratedDirName = "${project.buildDir}/generated/source/apt/navigation/${destinationPath}" + + FileCollection effectiveClasspath = new UnionFileCollection() + navigationVariant.apiConfigurations.each { effectiveClasspath.add(it) } + navigationVariant.implementationConfigurations.each { effectiveClasspath.add(it) } + navigationVariant.compileOnlyConfigurations.each { effectiveClasspath.add(it) } + + FileCollection effectiveAnnotationProcessorPath = new UnionFileCollection() + navigationVariant.annotationProcessorConfigurations.each { effectiveAnnotationProcessorPath.add(it) } + project.tasks.create("intentBuilderCompile${taskSuffix}", JavaCompile) { - setSource(project.android.sourceSets["${sourceSetName}"].java.sourceFiles) + setSource(navigationVariant.sourceSets.collect { sourceSet -> sourceSet.java.sourceFiles }) setDestinationDir(project.file("${newDestinationDirName}")) - classpath = project.configurations["${configurationName}Api"] + classpath = effectiveClasspath options.compilerArgs = ["-s", "${newGeneratedDirName}"] - options.annotationProcessorPath = project.configurations["${configurationName}AnnotationProcessor"] + options.annotationProcessorPath = effectiveAnnotationProcessorPath targetCompatibility = JavaVersion.VERSION_1_7 sourceCompatibility = JavaVersion.VERSION_1_7 doFirst { @@ -125,31 +192,40 @@ class HensonPlugin implements Plugin { } private Task createIntentBuilderJarTask(Project project, intentBuilderCompileTask, taskSuffix) { - def task = project.tasks.create("intentBuilderJar${taskSuffix}", Jar) { + def task = project.tasks.create(INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(taskSuffix), Jar) { baseName = "${project.name}-intentBuilder${taskSuffix}" from intentBuilderCompileTask.destinationDir - include('**/**__IntentBuilder*.class', '**/Henson*.class') } task.dependsOn(intentBuilderCompileTask) task } - private void addArtifact(Project project, taskSuffix) { + private void addArtifact(Project project, artifactSuffix, taskSuffix) { println project.configurations.getByName("intentBuilder") - project.artifacts.add("intentBuilder${taskSuffix}", project.tasks["intentBuilderJar${taskSuffix}"]) + project.artifacts.add("intentBuilder${artifactSuffix}", project.tasks[INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(taskSuffix)]) + } + + private void addNavigationArtifactToDependencies(Project project, artifactSuffix, configurationPrefix) { + //the project main source itself will depend on the navigation + //we must wait until the variant created the proper configurations to add the dependency. + project.afterEvaluate { + //we use the api configuration to make sure the resulting apk will contain the classes of the navigation jar. + project.dependencies.add("${configurationPrefix}Api", project.dependencies.project(path: "${project.path}", configuration: "intentBuilder${artifactSuffix}")) + } } - private void addDependenciesToConfiguration(Project project, configurationName, versionName) { + private void addDependenciesToConfiguration(Project project, configurationSuffix, dartVersionName) { project.dependencies { - "${configurationName}Api" "com.f2prateek.dart:dart-annotations:${versionName}" - "${configurationName}Api" "com.f2prateek.dart:dart:${versionName}" - "${configurationName}Api" "com.f2prateek.dart:henson:${versionName}" - "${configurationName}CompileOnly" "com.google.android:android:4.1.1.4" - "${configurationName}AnnotationProcessor" "com.f2prateek.dart:henson-processor:${versionName}" + "navigation${configurationSuffix}CompileOnly" "com.google.android:android:4.1.1.4" + "navigation${configurationSuffix}CompileOnly" "com.f2prateek.dart:dart:${dartVersionName}" + "navigation${configurationSuffix}CompileOnly" "com.f2prateek.dart:henson:${dartVersionName}" + "navigation${configurationSuffix}Api" "com.f2prateek.dart:dart-annotations:${dartVersionName}" + "navigation${configurationSuffix}AnnotationProcessor" "com.f2prateek.dart:henson-processor:${dartVersionName}" + "navigation${configurationSuffix}AnnotationProcessor" "com.f2prateek.dart:dart-processor:${dartVersionName}" } } - private void createNavigationConfiguration(Project project, newArtifactName, newConfigurationName, versionName) { + private void createNavigationConfiguration(Project project, newArtifactName, newConfigurationSuffix, dartVersionName) { println "Creating configuration: ${newArtifactName}" project.configurations { //the name of the artifact @@ -158,16 +234,24 @@ class HensonPlugin implements Plugin { } //the api scope: is there any convention ? apiElements? - "${newConfigurationName}Api" { + "navigation${newConfigurationSuffix}Api" { + canBeResolved true + } + + "navigation${newConfigurationSuffix}Implementation" { + canBeResolved true + } + + "navigation${newConfigurationSuffix}CompileOnly" { canBeResolved true } //the ap scope - "${newConfigurationName}AnnotationProcessor" { + "navigation${newConfigurationSuffix}AnnotationProcessor" { canBeResolved true } } - addDependenciesToConfiguration(project, newConfigurationName, versionName) + addDependenciesToConfiguration(project, newConfigurationSuffix, dartVersionName) } private void createNavigationSourceSet(Project project, sourceSetName, newSourceSetName, newSourceSetPath) { @@ -176,9 +260,6 @@ class HensonPlugin implements Plugin { "${newSourceSetName}" { setRoot "${newSourceSetPath}" } - "${sourceSetName}" { - java.srcDirs = project.android.sourceSets["${sourceSetName}"].java.srcDirs.collect() << "${newSourceSetPath}/java" - } } } diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/NavigationVariant.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/NavigationVariant.groovy new file mode 100644 index 00000000..aa7d4cb7 --- /dev/null +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/NavigationVariant.groovy @@ -0,0 +1,14 @@ +package dart.henson.plugin + +import com.android.build.gradle.api.AndroidSourceSet + +class NavigationVariant { + + def buildTypeName + def flavorName + List sourceSets + def apiConfigurations + def implementationConfigurations + def compileOnlyConfigurations + def annotationProcessorConfigurations +} \ No newline at end of file diff --git a/henson-plugin/src/main/java/dart/henson/plugin/CompileNavigationSourceTree.java b/henson-plugin/src/main/java/dart/henson/plugin/CompileNavigationSourceTree.java deleted file mode 100644 index d1e1edb7..00000000 --- a/henson-plugin/src/main/java/dart/henson/plugin/CompileNavigationSourceTree.java +++ /dev/null @@ -1,6 +0,0 @@ -package dart.henson.plugin; - -import org.gradle.api.DefaultTask; - -class CompileNavigationSourceTree extends DefaultTask { -} \ No newline at end of file diff --git a/henson-plugin/src/main/java/dart/henson/plugin/JarNavigationSourceTree.java b/henson-plugin/src/main/java/dart/henson/plugin/JarNavigationSourceTree.java deleted file mode 100644 index 3727bd20..00000000 --- a/henson-plugin/src/main/java/dart/henson/plugin/JarNavigationSourceTree.java +++ /dev/null @@ -1,6 +0,0 @@ -package dart.henson.plugin; - -import org.gradle.api.DefaultTask; - -class JarNavigationSourceTree extends DefaultTask { -} \ No newline at end of file diff --git a/henson-plugin/src/main/resources/build.properties b/henson-plugin/src/main/resources/build.properties index a36b332c..c5075823 100644 --- a/henson-plugin/src/main/resources/build.properties +++ b/henson-plugin/src/main/resources/build.properties @@ -1,2 +1,2 @@ -#Wed Nov 22 19:58:08 PST 2017 +#Wed Nov 29 20:24:50 PST 2017 dart.version=3.0.0-RC1-SNAPSHOT From ac145a2191cfaf8e86fd92a164a2f756647d18ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Thu, 30 Nov 2017 12:23:30 -0800 Subject: [PATCH 08/14] better tests. We know test the content of all jars created by the plugin --- .../plugin/HensonPluginFunctionalTest.groovy | 44 +++++++---- .../dart/henson/plugin/HensonPlugin.groovy | 75 ++++++++----------- .../src/main/resources/build.properties | 2 +- 3 files changed, 64 insertions(+), 57 deletions(-) diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index bab8e52f..dc74cb4a 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -150,7 +150,7 @@ class HensonPluginFunctionalTest extends Specification { def runner = GradleRunner.create() .withProjectDir(testProjectDir.root) //.withArguments('--no-build-cache', 'assemble', 'tasks', '--all', '-d', '-s') - .withArguments('--no-build-cache', 'clean', 'assemble', 'intentBuilderJar', 'intentBuilderJarRed', 'intentBuilderJarRelease', 'intentBuilderJarBlueDebug', '-d', '-s') + .withArguments('--no-build-cache', 'clean', 'assemble', 'navigationApiJar', 'navigationApiJarRed', 'navigationApiJarRelease', 'navigationApiJarBlueDebug', '-d', '-s') .withPluginClasspath() def projectDir = runner.projectDir @@ -160,20 +160,38 @@ class HensonPluginFunctionalTest extends Specification { println result.output result.task(":assemble").outcome != FAILED //result.task(":tasks").outcome == SUCCESS - result.task(":intentBuilderJar").outcome != FAILED - result.task(":intentBuilderJarRed").outcome != FAILED - result.task(":intentBuilderJarRelease").outcome != FAILED - result.task(":intentBuilderJarBlueDebug").outcome != FAILED - println new File(projectDir, "/build").eachFileRecurse(FILES) { - println it + result.task(":navigationApiJar").outcome != FAILED + result.task(":navigationApiJarRed").outcome != FAILED + result.task(":navigationApiJarRelease").outcome != FAILED + result.task(":navigationApiJarBlueDebug").outcome != FAILED + + new File(projectDir, "/build/libs").eachFileRecurse(FILES) { file -> + if(file.name.endsWith('.jar')) { + println "Testing jar: ${file.name}" + def content = getJarContent(file) + assert content.contains("META-INF/") + assert content.contains("META-INF/MANIFEST.MF") + assert content.contains("test/") + assert content.contains("test/Foo.class") + assert content.contains("test/Foo__ExtraBinder.class") + assert content.contains("test/Henson\$1.class") + assert content.contains("test/Henson\$WithContextSetState.class") + assert content.contains("test/Henson.class") + assert content.contains("test/TestActivity__IntentBuilder\$AllSet.class") + assert content.contains("test/TestActivity__IntentBuilder.class") + } } - println new File(projectDir, "/build/libs").eachFileRecurse(FILES) { - if(it.name.endsWith('.jar')) { - def zip = new ZipFile(it) - zip.entries().each { entry -> - println entry.name - } + } + + List getJarContent(file) { + def List result + if(file.name.endsWith('.jar')) { + result = new ArrayList<>() + def zip = new ZipFile(file) + zip.entries().each { entry -> + result.add(entry.name) } } + result } } \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index 350f70ee..7110fca9 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -7,7 +7,6 @@ import org.gradle.api.Project import com.android.build.gradle.AppPlugin import com.android.build.gradle.LibraryPlugin import org.gradle.api.Task -import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.file.FileCollection import org.gradle.api.internal.file.UnionFileCollection import org.gradle.api.plugins.PluginCollection @@ -16,8 +15,8 @@ import org.gradle.api.tasks.compile.JavaCompile class HensonPlugin implements Plugin { - public static final String INTENT_BUILDER_COMPILE_TASK_PREFIX = 'intentBuilderCompile' - public static final String INTENT_BUILDER_JAR_TASK_PREFIX = 'intentBuilderJar' + public static final String NAVIGATION_API_COMPILE_TASK_PREFIX = 'navigationApiCompile' + public static final String NAVIGATION_API_JAR_TASK_PREFIX = 'navigationApiJar' void apply(Project project) { final def log = project.logger @@ -32,9 +31,6 @@ class HensonPlugin implements Plugin { //the extension to use. This avoids all problems related to using version x.y.+ def dartVersionName = getVersionName() - //get Variants - //def variants = getVariants(project, hasAppPlugin) - //create extension createExtension(project) @@ -52,8 +48,8 @@ class HensonPlugin implements Plugin { createSourceSetAndConfiguration(project, sourceSetName, suffix, pathSuffix, dartVersionName) - createEmptyIntentBuilderCompileTask(project, suffix) - createEmptyIntentBuilderJarTask(project, suffix) + createEmptyNavigationApiCompileTask(project, suffix) + createEmptyNavigationApiJarTask(project, suffix) project.android.buildTypes.all { buildType -> println "Processing buildType: ${buildType.name}" @@ -82,17 +78,17 @@ class HensonPlugin implements Plugin { createSourceSetAndConfiguration(project, variantName, suffix, pathSuffix, dartVersionName) def navigationVariant = createNavigationVariant(project, productFlavor, buildType) - def intentBuilderCompiler = createIntentBuilderCompileTask(project, suffix, pathSuffix, navigationVariant) - def mainCompiler = project.tasks.getByName(INTENT_BUILDER_COMPILE_TASK_PREFIX) - def productFlavorCompiler = project.tasks.getByName(INTENT_BUILDER_COMPILE_TASK_PREFIX + String.valueOf(productFlavor.name.capitalize())) - def buildTypeCompiler = project.tasks.getByName(INTENT_BUILDER_COMPILE_TASK_PREFIX + String.valueOf(buildType.name.capitalize())) - intentBuilderCompiler.dependsOn(mainCompiler, productFlavorCompiler, buildTypeCompiler) - - def intentBuilderJarTask = createIntentBuilderJarTask(project, intentBuilderCompiler, suffix) - def mainIntentBuilderJarTask = project.tasks.getByName(INTENT_BUILDER_JAR_TASK_PREFIX) - def productFlavorIntentBuilderJarTask = project.tasks.getByName(INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(productFlavor.name.capitalize())) - def buildTypeIntentBuilderJarTask = project.tasks.getByName(INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(buildType.name.capitalize())) - intentBuilderJarTask.dependsOn(mainIntentBuilderJarTask, productFlavorIntentBuilderJarTask, buildTypeIntentBuilderJarTask) + def navigationApiCompiler = createNavigationApiCompileTask(project, suffix, pathSuffix, navigationVariant) + def mainCompiler = project.tasks.getByName(NAVIGATION_API_COMPILE_TASK_PREFIX) + def productFlavorCompiler = project.tasks.getByName(NAVIGATION_API_COMPILE_TASK_PREFIX + String.valueOf(productFlavor.name.capitalize())) + def buildTypeCompiler = project.tasks.getByName(NAVIGATION_API_COMPILE_TASK_PREFIX + String.valueOf(buildType.name.capitalize())) + navigationApiCompiler.dependsOn(mainCompiler, productFlavorCompiler, buildTypeCompiler) + + def navigationApiJarTask = createNavigationApiJarTask(project, navigationApiCompiler, suffix) + def mainNavigationApiJarTask = project.tasks.getByName(NAVIGATION_API_JAR_TASK_PREFIX) + def productFlavorNavigationApiJarTask = project.tasks.getByName(NAVIGATION_API_JAR_TASK_PREFIX + String.valueOf(productFlavor.name.capitalize())) + def buildTypeNavigationApiJarTask = project.tasks.getByName(NAVIGATION_API_JAR_TASK_PREFIX + String.valueOf(buildType.name.capitalize())) + navigationApiJarTask.dependsOn(mainNavigationApiJarTask, productFlavorNavigationApiJarTask, buildTypeNavigationApiJarTask) addArtifact(project, suffix, suffix) addNavigationArtifactToDependencies(project, suffix, variantName) @@ -105,8 +101,8 @@ class HensonPlugin implements Plugin { createSourceSetAndConfiguration(project, sourceSetName, suffix, pathSuffix, dartVersionName) - createEmptyIntentBuilderCompileTask(project, suffix) - createEmptyIntentBuilderJarTask(project, suffix) + createEmptyNavigationApiCompileTask(project, suffix) + createEmptyNavigationApiJarTask(project, suffix) } private void createSourceSetAndConfiguration(Project project, String sourceSetName, String suffix, String pathSuffix, dartVersionName) { @@ -114,7 +110,7 @@ class HensonPlugin implements Plugin { def newSourceSetPath = "src/navigation/" + pathSuffix createNavigationSourceSet(project, sourceSetName, newSourceSetName, newSourceSetPath) - def newArtifactName = "intentBuilder" + suffix + def newArtifactName = "navigationApi" + suffix createNavigationConfiguration(project, newArtifactName, suffix, dartVersionName) } @@ -156,15 +152,15 @@ class HensonPlugin implements Plugin { navigationVariant } - private Task createEmptyIntentBuilderCompileTask(Project project, taskSuffix) { - project.tasks.create(INTENT_BUILDER_COMPILE_TASK_PREFIX + String.valueOf(taskSuffix)) + private Task createEmptyNavigationApiCompileTask(Project project, taskSuffix) { + project.tasks.create(NAVIGATION_API_COMPILE_TASK_PREFIX + String.valueOf(taskSuffix)) } - private Task createEmptyIntentBuilderJarTask(Project project, taskSuffix) { - project.tasks.create(INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(taskSuffix)) + private Task createEmptyNavigationApiJarTask(Project project, taskSuffix) { + project.tasks.create(NAVIGATION_API_JAR_TASK_PREFIX + String.valueOf(taskSuffix)) } - private Task createIntentBuilderCompileTask(Project project, taskSuffix, destinationPath, navigationVariant) { + private Task createNavigationApiCompileTask(Project project, taskSuffix, destinationPath, navigationVariant) { def newDestinationDirName = "${project.buildDir}/navigation/classes/java/${destinationPath}" def newGeneratedDirName = "${project.buildDir}/generated/source/apt/navigation/${destinationPath}" @@ -176,7 +172,7 @@ class HensonPlugin implements Plugin { FileCollection effectiveAnnotationProcessorPath = new UnionFileCollection() navigationVariant.annotationProcessorConfigurations.each { effectiveAnnotationProcessorPath.add(it) } - project.tasks.create("intentBuilderCompile${taskSuffix}", JavaCompile) { + project.tasks.create("navigationApiCompile${taskSuffix}", JavaCompile) { setSource(navigationVariant.sourceSets.collect { sourceSet -> sourceSet.java.sourceFiles }) setDestinationDir(project.file("${newDestinationDirName}")) classpath = effectiveClasspath @@ -191,18 +187,18 @@ class HensonPlugin implements Plugin { } } - private Task createIntentBuilderJarTask(Project project, intentBuilderCompileTask, taskSuffix) { - def task = project.tasks.create(INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(taskSuffix), Jar) { - baseName = "${project.name}-intentBuilder${taskSuffix}" - from intentBuilderCompileTask.destinationDir + private Task createNavigationApiJarTask(Project project, navigationApiCompileTask, taskSuffix) { + def task = project.tasks.create(NAVIGATION_API_JAR_TASK_PREFIX + String.valueOf(taskSuffix), Jar) { + baseName = "${project.name}-navigationApi${taskSuffix}" + from navigationApiCompileTask.destinationDir } - task.dependsOn(intentBuilderCompileTask) + task.dependsOn(navigationApiCompileTask) task } private void addArtifact(Project project, artifactSuffix, taskSuffix) { - println project.configurations.getByName("intentBuilder") - project.artifacts.add("intentBuilder${artifactSuffix}", project.tasks[INTENT_BUILDER_JAR_TASK_PREFIX + String.valueOf(taskSuffix)]) + println project.configurations.getByName("navigationApi") + project.artifacts.add("navigationApi${artifactSuffix}", project.tasks[NAVIGATION_API_JAR_TASK_PREFIX + String.valueOf(taskSuffix)]) } private void addNavigationArtifactToDependencies(Project project, artifactSuffix, configurationPrefix) { @@ -210,7 +206,7 @@ class HensonPlugin implements Plugin { //we must wait until the variant created the proper configurations to add the dependency. project.afterEvaluate { //we use the api configuration to make sure the resulting apk will contain the classes of the navigation jar. - project.dependencies.add("${configurationPrefix}Api", project.dependencies.project(path: "${project.path}", configuration: "intentBuilder${artifactSuffix}")) + project.dependencies.add("${configurationPrefix}Api", project.dependencies.project(path: "${project.path}", configuration: "navigationApi${artifactSuffix}")) } } @@ -271,13 +267,6 @@ class HensonPlugin implements Plugin { return !hasApp } - private Collection getVariants(Project project, PluginCollection hasApp) { - if (hasApp) { - project.android.applicationVariants - } else { - project.android.libraryVariants - } - } private void createExtension(Project project) { project.extensions.create('henson', HensonPluginExtension, project) } diff --git a/henson-plugin/src/main/resources/build.properties b/henson-plugin/src/main/resources/build.properties index c5075823..3d161850 100644 --- a/henson-plugin/src/main/resources/build.properties +++ b/henson-plugin/src/main/resources/build.properties @@ -1,2 +1,2 @@ -#Wed Nov 29 20:24:50 PST 2017 +#Thu Nov 30 12:22:32 PST 2017 dart.version=3.0.0-RC1-SNAPSHOT From c6a0f36c02909613e464e2e6038fe9733e69669c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Thu, 30 Nov 2017 12:40:35 -0800 Subject: [PATCH 09/14] test task creation --- .../plugin/HensonPluginFunctionalTest.groovy | 38 +++++++++++++++++-- .../dart/henson/plugin/HensonPlugin.groovy | 4 +- .../src/main/resources/build.properties | 2 +- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index dc74cb4a..3d3ce6a2 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -146,15 +146,42 @@ class HensonPluginFunctionalTest extends Specification { } """ + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments('--no-build-cache', 'tasks', '--all', '-d', '-s') + .withPluginClasspath() + .build() + + then: + result.output.contains("navigationApiCompileJava") + result.output.contains("navigationApiCompileJavaRed") + result.output.contains("navigationApiCompileJavaBlue") + result.output.contains("navigationApiCompileJavaRelease") + result.output.contains("navigationApiCompileJavaDebug") + result.output.contains("navigationApiCompileJavaBlueRelease") + result.output.contains("navigationApiCompileJavaBlueDebug") + result.output.contains("navigationApiCompileJavaRedRelease") + result.output.contains("navigationApiCompileJavaRedDebug") + + result.output.contains("navigationApiJar") + result.output.contains("navigationApiJarRed") + result.output.contains("navigationApiJarBlue") + result.output.contains("navigationApiJarRelease") + result.output.contains("navigationApiJarDebug") + result.output.contains("navigationApiJarBlueRelease") + result.output.contains("navigationApiJarBlueDebug") + result.output.contains("navigationApiJarRedRelease") + result.output.contains("navigationApiJarRedDebug") + when: def runner = GradleRunner.create() .withProjectDir(testProjectDir.root) - //.withArguments('--no-build-cache', 'assemble', 'tasks', '--all', '-d', '-s') .withArguments('--no-build-cache', 'clean', 'assemble', 'navigationApiJar', 'navigationApiJarRed', 'navigationApiJarRelease', 'navigationApiJarBlueDebug', '-d', '-s') .withPluginClasspath() def projectDir = runner.projectDir - def result = runner.build() + result = runner.build() then: println result.output @@ -165,8 +192,12 @@ class HensonPluginFunctionalTest extends Specification { result.task(":navigationApiJarRelease").outcome != FAILED result.task(":navigationApiJarBlueDebug").outcome != FAILED + testJarsContent(projectDir) + } + + boolean testJarsContent(projectDir) { new File(projectDir, "/build/libs").eachFileRecurse(FILES) { file -> - if(file.name.endsWith('.jar')) { + if (file.name.endsWith('.jar')) { println "Testing jar: ${file.name}" def content = getJarContent(file) assert content.contains("META-INF/") @@ -181,6 +212,7 @@ class HensonPluginFunctionalTest extends Specification { assert content.contains("test/TestActivity__IntentBuilder.class") } } + true } List getJarContent(file) { diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index 7110fca9..f0710907 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -15,7 +15,7 @@ import org.gradle.api.tasks.compile.JavaCompile class HensonPlugin implements Plugin { - public static final String NAVIGATION_API_COMPILE_TASK_PREFIX = 'navigationApiCompile' + public static final String NAVIGATION_API_COMPILE_TASK_PREFIX = 'navigationApiCompileJava' public static final String NAVIGATION_API_JAR_TASK_PREFIX = 'navigationApiJar' void apply(Project project) { @@ -172,7 +172,7 @@ class HensonPlugin implements Plugin { FileCollection effectiveAnnotationProcessorPath = new UnionFileCollection() navigationVariant.annotationProcessorConfigurations.each { effectiveAnnotationProcessorPath.add(it) } - project.tasks.create("navigationApiCompile${taskSuffix}", JavaCompile) { + project.tasks.create("${NAVIGATION_API_COMPILE_TASK_PREFIX}${taskSuffix}", JavaCompile) { setSource(navigationVariant.sourceSets.collect { sourceSet -> sourceSet.java.sourceFiles }) setDestinationDir(project.file("${newDestinationDirName}")) classpath = effectiveClasspath diff --git a/henson-plugin/src/main/resources/build.properties b/henson-plugin/src/main/resources/build.properties index 3d161850..f32df3a5 100644 --- a/henson-plugin/src/main/resources/build.properties +++ b/henson-plugin/src/main/resources/build.properties @@ -1,2 +1,2 @@ -#Thu Nov 30 12:22:32 PST 2017 +#Thu Nov 30 12:39:20 PST 2017 dart.version=3.0.0-RC1-SNAPSHOT From 81237667b1a9b146fe6e2f46ef2f08c361fb0b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Thu, 30 Nov 2017 14:15:33 -0800 Subject: [PATCH 10/14] fix travis --- .travis.yml | 33 ++++++++++++++++--- .../dart/henson/plugin/HensonPlugin.groovy | 17 +++++----- .../plugin/HensonPluginExtension.groovy | 4 +++ .../src/main/resources/build.properties | 2 +- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1a788c90..b430d45e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,38 @@ -language: java +language: android android: + components: + # Update tools and then platform-tools explicitly so lint gets an updated database. Can be removed once 3.0 is out. + - tools + - platform-tools + jdk: - oraclejdk8 -after_success: - - .buildscript/deploy_snapshot.sh - env: global: - secure: "S2ANsF5glMuPrjilyE6+JqVp/t9bEQgkLXNHN1quLebTaJcveNFgyCPCvcevKJLiHCb4USY0cteZYj1U0QOvVR3zi/chr6Pxuo1kwgrfKpdBCWa1oxzLt0ipkVgH60VwxQNWjoUQCleOhu3F16X7IvCx32Wu7OqpmenJ6FJZYUw=" - secure: "ZetM/udS7DJMVdsFlSTCf88D6J4zQPS6hY3qc/f0BfYJP6qpOkHMBuxfIJMxkyQ9Rwi45RAX5kFFHJg/4wYiCQhlCSKy1gZaf4PORbhxTQR+rJCRtUi5dfHz2S2og/qWZm8KgaCalKW1s+f6/shFIBLcHvw8gnQmKvcIv7BHNaQ=" +before_install: + # Install SDK license so Android Gradle plugin can install deps. + - mkdir "$ANDROID_HOME/licenses" || true + - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" + # Install the rest of tools (e.g., avdmanager) + #- sdkmanager tools + # Install the system image + #- sdkmanager "android-26" + +script: + - ./gradlew check -s + + +after_success: + - .buildscript/deploy_snapshot.sh + +after_failure: + - cat /home/travis/build/f2prateek/dart/henson-plugin/build/reports/tests/functionalTest/classes/dart.henson.plugin.HensonPluginFunctionalTest.html + branches: except: - gh-pages @@ -23,4 +44,6 @@ sudo: false cache: directories: - - $HOME/.m2 + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + - $HOME/.android/build-cache diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index f0710907..f8e6b6a3 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -1,6 +1,5 @@ package dart.henson.plugin -import com.android.build.gradle.api.BaseVariant import org.gradle.api.JavaVersion import org.gradle.api.Plugin import org.gradle.api.Project @@ -27,12 +26,17 @@ class HensonPlugin implements Plugin { def hasLibPlugin = project.plugins.withType(LibraryPlugin) checkProject(hasAppPlugin, hasLibPlugin) + //create extension + def extension = project.extensions.create('henson', HensonPluginExtension, project) + //we use the file build.properties that contains the version of //the extension to use. This avoids all problems related to using version x.y.+ - def dartVersionName = getVersionName() - - //create extension - createExtension(project) + def dartVersionName + if(extension!=null && extension.dartVersion!=null) { + dartVersionName= extension.dartVersion + } else{ + dartVersionName= getVersionName() + } //we do the following for all sourcesets, of all build types, of all flavors, and all variants // create source sets @@ -267,7 +271,4 @@ class HensonPlugin implements Plugin { return !hasApp } - private void createExtension(Project project) { - project.extensions.create('henson', HensonPluginExtension, project) - } } \ No newline at end of file diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy index 6c965237..d0677776 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy @@ -3,6 +3,10 @@ package dart.henson.plugin import org.gradle.api.Project class HensonPluginExtension { + String dartVersion + private Project project + HensonPluginExtension(Project project) { + this.project = project } } \ No newline at end of file diff --git a/henson-plugin/src/main/resources/build.properties b/henson-plugin/src/main/resources/build.properties index f32df3a5..365911db 100644 --- a/henson-plugin/src/main/resources/build.properties +++ b/henson-plugin/src/main/resources/build.properties @@ -1,2 +1,2 @@ -#Thu Nov 30 12:39:20 PST 2017 +#Thu Nov 30 14:32:48 PST 2017 dart.version=3.0.0-RC1-SNAPSHOT From 84e869ab6b0b2cf8270cf240b22422e1a7fd08ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Thu, 30 Nov 2017 21:52:22 -0800 Subject: [PATCH 11/14] the principle woks. I can detect the navigation api dependencies and generate a henson navigator class. Some details need to be enhanced like the generated file location, the variant. But it works. Do we need a third source set to generate into ? --- .../plugin/HensonPluginFunctionalTest.groovy | 7 +- .../dart/henson/plugin/HensonPlugin.groovy | 118 ++++++++++++++++-- .../src/main/resources/build.properties | 2 +- 3 files changed, 113 insertions(+), 14 deletions(-) diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index 3d3ce6a2..b7b09cf4 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -65,13 +65,18 @@ class HensonPluginFunctionalTest extends Specification { import android.app.Activity; import android.os.Bundle; + import test.HensonNavigator; + import android.content.Intent; class FooActivity extends Activity { @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); - Foo foo = new Foo(); + Foo foo = new Foo(); + Intent intent = HensonNavigator.gotoTestActivity(this) + .s("s") + .build(); } } """ diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index f8e6b6a3..6bd45786 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -6,12 +6,15 @@ import org.gradle.api.Project import com.android.build.gradle.AppPlugin import com.android.build.gradle.LibraryPlugin import org.gradle.api.Task +import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.file.FileCollection import org.gradle.api.internal.file.UnionFileCollection import org.gradle.api.plugins.PluginCollection import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.compile.JavaCompile +import java.util.zip.ZipFile + class HensonPlugin implements Plugin { public static final String NAVIGATION_API_COMPILE_TASK_PREFIX = 'navigationApiCompileJava' @@ -45,26 +48,91 @@ class HensonPlugin implements Plugin { // create tasks: compile and jar // create artifacts - //the main source set + processMain(project, dartVersionName) + processBuildTypes(project, dartVersionName) + processProductFlavors(project, dartVersionName) + processVariants(project, dartVersionName) + + detectNavigationApiDependencies(project) + } + + private void detectNavigationApiDependencies(Project project) { + project.afterEvaluate { + project.android.applicationVariants.all { variant -> + def taskDetectModules = project.tasks.create("detectModule${variant.name.capitalize()}") { + doFirst { + variant.compileConfiguration.resolve() + variant.compileConfiguration.each { dependency -> + println "Detected dependency: ${dependency.properties}" + List targetActivities = new ArrayList() + if (dependency.name.matches(".*-navigationApi.*.jar")) { + println "Detected navigation API dependency: ${dependency.name}" + println "Detected navigation API dependency: ${dependency.name}" + def file = dependency.absoluteFile + def entries = getJarContent(file) + entries.each { entry -> + if(entry.matches(".*__IntentBuilder.class")) { + println "Detected intent builder: ${entry}" + def targetActivityFQN = entry.substring(0, entry.length() - "__IntentBuilder.class".length()).replace('/', '.') + targetActivities.add(targetActivityFQN) + } + } + } + def targetPackageName = "test" + String hensonNavigator = generateHensonNavigatorClass(targetActivities, targetPackageName) + def folder = new File(project.projectDir, "src/main/java/") + folder.mkdirs() + File generatedFolder = new File(folder, targetPackageName.replace('.', '/').concat("/")) + generatedFolder.mkdirs() + def generatedFile = new File(generatedFolder, "HensonNavigator.java") + generatedFile.withPrintWriter { out -> + out.println(hensonNavigator) + } + } + } + } + taskDetectModules.dependsOn = variant.javaCompiler.dependsOn + variant.javaCompiler.dependsOn(taskDetectModules) + } + } + } + + private String generateHensonNavigatorClass(List targetActivities, packageName) { + String packageStatement = "package ${packageName};\n" + String importStatement = "import android.content.Context;\n" + targetActivities.each { targetActivity -> + importStatement += "import ${targetActivity}__IntentBuilder;\n" + } + String classStartStatement = "public class HensonNavigator {\n" + String methodStatement = "" + targetActivities.each { targetActivity -> + String targetActivitySimpleName = targetActivity.substring(1+targetActivity.lastIndexOf('.'), targetActivity.length()) + methodStatement += "public static ${targetActivitySimpleName.capitalize()}__IntentBuilder goto${targetActivitySimpleName.capitalize()}(Context context) {\n" + methodStatement += " return new ${targetActivitySimpleName}__IntentBuilder(context);\n" + methodStatement += "}" + methodStatement += "\n" + } + String classEndStatement = "}" + new StringBuilder() + .append(packageStatement) + .append(importStatement) + .append(classStartStatement) + .append(methodStatement) + .append(classEndStatement) + .toString() + } + + private void processMain(Project project, dartVersionName) { def suffix = "" def pathSuffix = "main/" def sourceSetName = "main" createSourceSetAndConfiguration(project, sourceSetName, suffix, pathSuffix, dartVersionName) - createEmptyNavigationApiCompileTask(project, suffix) createEmptyNavigationApiJarTask(project, suffix) + } - project.android.buildTypes.all { buildType -> - println "Processing buildType: ${buildType.name}" - processFlavorOrBuildType(project, buildType, dartVersionName) - } - - project.android.productFlavors.all { productFlavor -> - println "Processing flavor: ${productFlavor.name}" - processFlavorOrBuildType(project, productFlavor, dartVersionName) - } - + private Object processVariants(Project project, dartVersionName) { project.android.with { buildTypes.all { buildType -> productFlavors.all { productFlavor -> @@ -75,6 +143,20 @@ class HensonPlugin implements Plugin { } } + private void processProductFlavors(Project project, dartVersionName) { + project.android.productFlavors.all { productFlavor -> + println "Processing flavor: ${productFlavor.name}" + processFlavorOrBuildType(project, productFlavor, dartVersionName) + } + } + + private void processBuildTypes(Project project, dartVersionName) { + project.android.buildTypes.all { buildType -> + println "Processing buildType: ${buildType.name}" + processFlavorOrBuildType(project, buildType, dartVersionName) + } + } + private void processVariant(Project project, productFlavor, buildType, dartVersionName) { def variantName = "${productFlavor.name}${buildType.name.capitalize()}" def suffix = "${productFlavor.name.capitalize()}${buildType.name.capitalize()}" @@ -271,4 +353,16 @@ class HensonPlugin implements Plugin { return !hasApp } + + List getJarContent(file) { + def List result + if(file.name.endsWith('.jar')) { + result = new ArrayList<>() + def zip = new ZipFile(file) + zip.entries().each { entry -> + result.add(entry.name) + } + } + result + } } \ No newline at end of file diff --git a/henson-plugin/src/main/resources/build.properties b/henson-plugin/src/main/resources/build.properties index 365911db..c6e2a47f 100644 --- a/henson-plugin/src/main/resources/build.properties +++ b/henson-plugin/src/main/resources/build.properties @@ -1,2 +1,2 @@ -#Thu Nov 30 14:32:48 PST 2017 +#Thu Nov 30 21:35:26 PST 2017 dart.version=3.0.0-RC1-SNAPSHOT From 27f875dc40473358580646e40150ba26bbd3f8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Fri, 1 Dec 2017 09:30:19 -0800 Subject: [PATCH 12/14] good polish of extension usage, remove allAfterEvaluate blocks. Much better than before --- .../plugin/HensonPluginFunctionalTest.groovy | 5 + .../dart/henson/plugin/HensonPlugin.groovy | 103 ++++++++++-------- .../plugin/HensonPluginExtension.groovy | 9 +- .../src/main/resources/build.properties | 2 +- 4 files changed, 62 insertions(+), 57 deletions(-) diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index b7b09cf4..3202d1b1 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -118,6 +118,10 @@ class HensonPluginFunctionalTest extends Specification { id 'dart.henson-plugin' } + henson { + navigatorPackageName = "test" + } + android { compileSdkVersion 26 defaultConfig { @@ -149,6 +153,7 @@ class HensonPluginFunctionalTest extends Specification { url 'https://oss.sonatype.org/content/repositories/snapshots' } } + """ when: diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index 6bd45786..94b2d541 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -6,13 +6,13 @@ import org.gradle.api.Project import com.android.build.gradle.AppPlugin import com.android.build.gradle.LibraryPlugin import org.gradle.api.Task -import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.file.FileCollection import org.gradle.api.internal.file.UnionFileCollection import org.gradle.api.plugins.PluginCollection import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.compile.JavaCompile +import java.security.InvalidParameterException import java.util.zip.ZipFile class HensonPlugin implements Plugin { @@ -29,17 +29,13 @@ class HensonPlugin implements Plugin { def hasLibPlugin = project.plugins.withType(LibraryPlugin) checkProject(hasAppPlugin, hasLibPlugin) - //create extension - def extension = project.extensions.create('henson', HensonPluginExtension, project) - //we use the file build.properties that contains the version of - //the extension to use. This avoids all problems related to using version x.y.+ - def dartVersionName - if(extension!=null && extension.dartVersion!=null) { - dartVersionName= extension.dartVersion - } else{ - dartVersionName= getVersionName() - } + //the dart & henson version to use. This avoids all problems related to using version x.y.+ + def dartVersionName = getVersionName() + + //the extension is created but will be read only during execution time + //(it's not available before) + project.extensions.create('henson', HensonPluginExtension) //we do the following for all sourcesets, of all build types, of all flavors, and all variants // create source sets @@ -53,47 +49,57 @@ class HensonPlugin implements Plugin { processProductFlavors(project, dartVersionName) processVariants(project, dartVersionName) - detectNavigationApiDependencies(project) + //add the artifact of navigation for the variant to the variant configuration + addNavigationArtifactsToVariantConfigurations(project) + + //create the task for generating the henson navigator + detectNavigationApiDependenciesAndGenerateHensonNavigator(project) } - private void detectNavigationApiDependencies(Project project) { - project.afterEvaluate { - project.android.applicationVariants.all { variant -> - def taskDetectModules = project.tasks.create("detectModule${variant.name.capitalize()}") { - doFirst { - variant.compileConfiguration.resolve() - variant.compileConfiguration.each { dependency -> - println "Detected dependency: ${dependency.properties}" - List targetActivities = new ArrayList() - if (dependency.name.matches(".*-navigationApi.*.jar")) { - println "Detected navigation API dependency: ${dependency.name}" - println "Detected navigation API dependency: ${dependency.name}" - def file = dependency.absoluteFile - def entries = getJarContent(file) - entries.each { entry -> - if(entry.matches(".*__IntentBuilder.class")) { - println "Detected intent builder: ${entry}" - def targetActivityFQN = entry.substring(0, entry.length() - "__IntentBuilder.class".length()).replace('/', '.') - targetActivities.add(targetActivityFQN) - } + private void detectNavigationApiDependenciesAndGenerateHensonNavigator(Project project) { + project.android.applicationVariants.all { variant -> + def taskDetectModules = project.tasks.create("detectModule${variant.name.capitalize()}") { + doFirst { + //create hensonExtension + def hensonExtension = project.extensions.getByName('henson') + if(hensonExtension==null || hensonExtension.navigatorPackageName == null) { + throw new InvalidParameterException("The property 'henson.navigatorPackageName' must be defined in your build.gradle") + } + def hensonNavigatorPackageName = hensonExtension.navigatorPackageName + + variant.compileConfiguration.resolve() + variant.compileConfiguration.each { dependency -> + println "Detected dependency: ${dependency.properties}" + List targetActivities = new ArrayList() + if (dependency.name.matches(".*-navigationApi.*.jar")) { + println "Detected navigation API dependency: ${dependency.name}" + println "Detected navigation API dependency: ${dependency.name}" + def file = dependency.absoluteFile + def entries = getJarContent(file) + entries.each { entry -> + if(entry.matches(".*__IntentBuilder.class")) { + println "Detected intent builder: ${entry}" + def targetActivityFQN = entry.substring(0, entry.length() - "__IntentBuilder.class".length()).replace('/', '.') + targetActivities.add(targetActivityFQN) } } - def targetPackageName = "test" - String hensonNavigator = generateHensonNavigatorClass(targetActivities, targetPackageName) - def folder = new File(project.projectDir, "src/main/java/") - folder.mkdirs() - File generatedFolder = new File(folder, targetPackageName.replace('.', '/').concat("/")) - generatedFolder.mkdirs() - def generatedFile = new File(generatedFolder, "HensonNavigator.java") - generatedFile.withPrintWriter { out -> - out.println(hensonNavigator) - } + } + def variantSrcFolderName = new File(project.projectDir, "src/${variant.name}/java/") + String hensonNavigator = generateHensonNavigatorClass(targetActivities, hensonNavigatorPackageName) + variantSrcFolderName.mkdirs() + File generatedFolder = new File(variantSrcFolderName, hensonNavigatorPackageName.replace('.', '/').concat('/')) + generatedFolder.mkdirs() + def generatedFile = new File(generatedFolder, "HensonNavigator.java") + generatedFile.withPrintWriter { out -> + out.println(hensonNavigator) } } } - taskDetectModules.dependsOn = variant.javaCompiler.dependsOn - variant.javaCompiler.dependsOn(taskDetectModules) } + //we put the task right before compilation so that all dependencies are resolved + // when the task is executed + taskDetectModules.dependsOn = variant.javaCompiler.dependsOn + variant.javaCompiler.dependsOn(taskDetectModules) } } @@ -177,7 +183,6 @@ class HensonPlugin implements Plugin { navigationApiJarTask.dependsOn(mainNavigationApiJarTask, productFlavorNavigationApiJarTask, buildTypeNavigationApiJarTask) addArtifact(project, suffix, suffix) - addNavigationArtifactToDependencies(project, suffix, variantName) } private void processFlavorOrBuildType(Project project, productFlavorOrBuildType, dartVersionName) { @@ -287,11 +292,13 @@ class HensonPlugin implements Plugin { project.artifacts.add("navigationApi${artifactSuffix}", project.tasks[NAVIGATION_API_JAR_TASK_PREFIX + String.valueOf(taskSuffix)]) } - private void addNavigationArtifactToDependencies(Project project, artifactSuffix, configurationPrefix) { + private void addNavigationArtifactsToVariantConfigurations(Project project) { //the project main source itself will depend on the navigation //we must wait until the variant created the proper configurations to add the dependency. - project.afterEvaluate { + project.android.applicationVariants.all { variant -> //we use the api configuration to make sure the resulting apk will contain the classes of the navigation jar. + def configurationPrefix = variant.name + def artifactSuffix = variant.name.capitalize() project.dependencies.add("${configurationPrefix}Api", project.dependencies.project(path: "${project.path}", configuration: "navigationApi${artifactSuffix}")) } } @@ -354,7 +361,7 @@ class HensonPlugin implements Plugin { } - List getJarContent(file) { + private List getJarContent(file) { def List result if(file.name.endsWith('.jar')) { result = new ArrayList<>() diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy index d0677776..53d6cd3b 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy @@ -1,12 +1,5 @@ package dart.henson.plugin -import org.gradle.api.Project - class HensonPluginExtension { - String dartVersion - private Project project - - HensonPluginExtension(Project project) { - this.project = project - } + String navigatorPackageName } \ No newline at end of file diff --git a/henson-plugin/src/main/resources/build.properties b/henson-plugin/src/main/resources/build.properties index c6e2a47f..b4624f18 100644 --- a/henson-plugin/src/main/resources/build.properties +++ b/henson-plugin/src/main/resources/build.properties @@ -1,2 +1,2 @@ -#Thu Nov 30 21:35:26 PST 2017 +#Fri Dec 01 09:28:50 PST 2017 dart.version=3.0.0-RC1-SNAPSHOT From 7a6860bdad9afa5d9f08ebd241564338442f3a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Fri, 1 Dec 2017 10:15:38 -0800 Subject: [PATCH 13/14] fix navigation source set path for variants --- .../src/main/groovy/dart/henson/plugin/HensonPlugin.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index f8e6b6a3..44db46e1 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -78,7 +78,7 @@ class HensonPlugin implements Plugin { private void processVariant(Project project, productFlavor, buildType, dartVersionName) { def variantName = "${productFlavor.name}${buildType.name.capitalize()}" def suffix = "${productFlavor.name.capitalize()}${buildType.name.capitalize()}" - def pathSuffix = "${productFlavor.name}/${buildType.name.capitalize()}/" + def pathSuffix = "${productFlavor.name}${buildType.name.capitalize()}/" createSourceSetAndConfiguration(project, variantName, suffix, pathSuffix, dartVersionName) def navigationVariant = createNavigationVariant(project, productFlavor, buildType) From bac32a6017d99020b413e671f1fdb7fb88cd67fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolas?= Date: Fri, 1 Dec 2017 16:51:39 -0800 Subject: [PATCH 14/14] add trailing lines --- .../groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy | 2 +- .../src/main/groovy/dart/henson/plugin/HensonPlugin.groovy | 2 +- .../main/groovy/dart/henson/plugin/HensonPluginExtension.groovy | 2 +- .../src/main/groovy/dart/henson/plugin/NavigationVariant.groovy | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy index 3202d1b1..3793d6f0 100644 --- a/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy +++ b/henson-plugin/src/functTest/groovy/dart/henson/plugin/HensonPluginFunctionalTest.groovy @@ -236,4 +236,4 @@ class HensonPluginFunctionalTest extends Specification { } result } -} \ No newline at end of file +} diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy index af82c480..6502cd59 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPlugin.groovy @@ -372,4 +372,4 @@ class HensonPlugin implements Plugin { } result } -} \ No newline at end of file +} diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy index 53d6cd3b..5cca0c69 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/HensonPluginExtension.groovy @@ -2,4 +2,4 @@ package dart.henson.plugin class HensonPluginExtension { String navigatorPackageName -} \ No newline at end of file +} diff --git a/henson-plugin/src/main/groovy/dart/henson/plugin/NavigationVariant.groovy b/henson-plugin/src/main/groovy/dart/henson/plugin/NavigationVariant.groovy index aa7d4cb7..c3c735d5 100644 --- a/henson-plugin/src/main/groovy/dart/henson/plugin/NavigationVariant.groovy +++ b/henson-plugin/src/main/groovy/dart/henson/plugin/NavigationVariant.groovy @@ -11,4 +11,4 @@ class NavigationVariant { def implementationConfigurations def compileOnlyConfigurations def annotationProcessorConfigurations -} \ No newline at end of file +}