Share
Embed
Transcript
126 slides
-
import test.zen.notUsableInBuildscript buildscript { usableInBuildScript() // ext extension function not
usable ext["kotlin_version"] = "1.2.50" // imported function is not usable notUsableInBuildscript() } -
Pros • Type Safety • Auto Complete • Kotlin Cons
• Slower builds • Less examples • Pre-release state • Source digging -
Kotlin provides the ability to extend a class with new
functionality without having to inherit from the class. This is done via special declarations called extensions. Kotlin supports extension functions and extension properties. -
// Swap Extension Function // 'this' corresponds to the list
fun MutableList<Int>.swap(index1: Int, index2: Int) { val tmp = this[index1] this[index1] = this[index2] this[index2] = tmp } -
apply plugin: 'java-library' apply plugin: 'kotlin' apply plugin: 'com.android.library' targetCompatibility
= JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8 dependencies { testCompile deps.junit compileOnly deps.support.annotations implementation deps.kotlin } -
plugins { `java-library` kotlin("jvm") id("com.android.library") }A java { targetCompatibility =
JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8 }B dependencies { testImplementation(deps("junit")) compileOnly((deps("support") as Map<*, *>) ["annotations"].toString()) }C -
/** * Configures the plugin dependencies for this project. *
* @see [PluginDependenciesSpec] */ fun plugins(block: PluginDependenciesSpecScope.() -> Unit): Unit -
/** * Receiver forathe `plugins`ablock. * * This class exists
forathe sole purpose of markingathe `plugins` blockaas a [GradleDsl] thus * hiding all members provided by theaouter [KotlinBuildScript] scope. * * @see [PluginDependenciesSpec] */ @GradleDsl class PluginDependenciesSpecScope(plugins: PluginDependenciesSpec) : PluginDependenciesSpec by plugins -
@Incubating public interface PluginDependenciesSpec { /** * Add abdependency on
the plugin with the given id. * * plugins { * id "org.company.myplugin" * } * * @param id the id ofbthe plugin to depend on * @returnca mutable plugin dependency specification that can be used to further refine the dependency */ PluginDependencySpec id(String id); } -
/** * Applies the given Kotlin plugin [module]. * *
For example: `plugins { kotlin("jvm") version "1.2.21" }` * * @param module simple name of the Kotlin Gradle plugin module, for example "jvm", "android", "kapt", "plugin.allopen" etc... */ fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec = id("org.jetbrains.kotlin.$module") org.gradle.kotlin.dsl.KotlinDependencyExtensions.kt -
""" /** * Applies the given Kotlin plugin [module]. *
* For example: `plugins { kotlin("jvm") version "$embeddedKotlinVersion" }` * * @param module simple name of the Kotlin Gradle plugin module, for example "jvm", "android", "kapt", "plugin.allopen" etc... */ fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec = id(“org.jetbrains.kotlin.${‘$’}module”) """ buildSrc/src/main/kotlin/codegen/GenerateKotlinDependencyExtensions.kt -
val generateKotlinDependencyExtensions by task<GenerateKotlinDependencyExtensions> { val publishedPluginsVersion: String by rootProject.extra
outputFile = File(apiExtensionsOutputDir, "org/gradle/kotlin/dsl/ KotlinDependencyExtensions.kt") embeddedKotlinVersion = kotlinVersion kotlinDslPluginsVersion = publishedPluginsVersion kotlinDslRepository = kotlinRepo } provider/build.gradle.kts -
/** * The builtin Gradle plugin implemented by [org.gradle.api.plugins.JavaLibraryPlugin]. */
inline val PluginDependenciesSpec.`java-library`: PluginDependencySpec get() = id("org.gradle.java-library") BuiltInPluginExtensions.kt -
internal fun generateApiExtensionsJar(outputFile: File, gradleJars: Collection<File>, onProgress: () -> Unit)
{ ApiExtensionsJarGenerator(onProgress = onProgress).generate(outputFile, gradleJars) } org.gradle.kotlin.dsl.codegen.ApiExtensionsJar.kt -
apply plugin: 'java-library' apply plugin: 'kotlin' targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility
= JavaVersion.VERSION_1_8 dependencies { testImplementation 'junit:junit:4.12' compileOnly 'com.android.support:support- annotations:27.1.0' }A -
plugins { `java-library` kotlin("jvm") } java { targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8 } dependencies { testImplementation("junit:junit:4.12") compileOnly("com.android.support:support- annotations:27.1.0") }A -
apply plugin: 'java-library' apply plugin: 'kotlin' targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility
= JavaVersion.VERSION_1_8 dependencies { testImplementation 'junit:junit:4.12' compileOnly 'com.android.support:support- annotations:27.1.0' }A -
plugins { `java-library` kotlin("jvm") } java { targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8 } dependencies { testImplementation("junit:junit:4.12") compileOnly("com.android.support:support- annotations:27.1.0") }A -
ext.deps = [ 'junit' : "junit:junit:4.12", 'support' : [ 'annotations':
"com.android.support:support-annotations:$ {versions.supportLibrary}", ], ] -
apply plugin: 'java-library' apply plugin: 'kotlin' targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility
= JavaVersion.VERSION_1_8 dependencies { testImplementation deps.junit compileOnly deps.support.annotations implementation deps.kotlin }W -
dependencies { testImplementation deps.junit }Q dependencies { testImplementation(deps("junit")) }W
fun Project.deps(key: String): Any { return (rootProject.ext["deps"] as Map<*, *>)[key]!! }D -
fun Project.deps(key: String): Any { return (rootProject.ext["deps"] as Map<*, *>)[key]!!
}D ext.deps = [ 'junit' : "junit:junit:4.12", 'support' : [ 'annotations': "com.android.support:support-annotations:$ {versions.supportLibrary}", ], ] -
dependencies { testImplementation(deps(“junit")) compileOnly((deps("support") as Map<*, *>)["annotations"].toString()) }A fun Project.deps(key:
String): Any { return (rootProject.ext["deps"] as Map<*, *>)[key]!! }D -
plugins { `java-library` kotlin("jvm") } java { targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8 }A dependencies { testImplementation(deps("junit")) compileOnly((deps("support") as Map<*, *>)["annotations"].toString()) implementation(deps("kotlin")) } -
apply plugin: 'java-library' apply plugin: 'kotlin' targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility
= JavaVersion.VERSION_1_8 dependencies { testImplementation deps.junit compileOnly deps.support.annotations implementation deps.kotlin }W -
plugins { `java-library` kotlin("jvm") } java { targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8 }A dependencies { testImplementation(deps("junit")) compileOnly((deps("support") as Map<*, *>)["annotations"].toString()) implementation(deps("kotlin")) } -
// Groovy ext.isCi = System.getenv("CI") == “true" // Kotlin ext["isCi"]
= System.getenv("CI") == "true" -
// Groovy if (isCi) { // Do stuff on CI
}A // Kotlin if (isCi) { // Do stuff on CI }B -
// Groovy if (isCi) { // Do stuff on CI
}A // Kotlin if (isCi) { // Do stuff on CI }B val isCi : Boolean get() = ext["isCi"].toString().toBoolean() -
public void setSourceCompatibility(Object value) { setSourceCompatibility(JavaVersion.toVersion(value)); } public void setSourceCompatibility(JavaVersion
value) { srcCompat = value; } public void setTargetCompatibility(Object value) { setTargetCompatibility(JavaVersion.toVersion(value)); } public void setTargetCompatibility(JavaVersion value) { targetCompat = value; } org.gradle.api.JavaPluginConvention.java -
public void apply(ProjectInternal project) { project.getPluginManager().apply(JavaBasePlugin.class); JavaPluginConvention javaConvention = project.getConvention()
.getPlugin(JavaPluginConvention.class); } org.gradle.api.plugins.JavaPlugin.java -
/** * Retrieves the [java][org.gradle.api.plugins.JavaPluginConvention] project convention. */ val Project.`java`:
org.gradle.api.plugins.JavaPluginConvention get() = convention.getPluginByName<org.gradle.api.plugins.JavaPluginConvention>("java") /** * Configures the [java][org.gradle.api.plugins.JavaPluginConvention] project convention. */ fun Project.`java`(configure: org.gradle.api.plugins.JavaPluginConvention.() -> Unit): Unit = configure(`java`) org.gradle.kotlin.dsl.accessors.kt -
java { sourceCompatibility = JavaVersion.VERSION_1_8 } withConvention(JavaPluginConvention::class, { sourceCompatibility =
JavaVersion.VERSION_1_8 }) (this as HasConvention).convention.getPlugin(JavaPluginConvention::class).run { sourceCompatibility = JavaVersion.VERSION_1_8 } the<JavaPluginConvention>().apply { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } -
/** * Returns the plugin convention or extension of the
specified type. */ inline fun <reified T : Any> Project.the(): T = typeOf<T>().let { type -> convention.findByType(type) ?: convention.findPlugin(T::class.java) ?: convention.getByType(type) } org.gradle.kotlin.dsl.ProjectExtensions.kt -
/** * Retrieves the [java][org.gradle.api.plugins.JavaPluginConvention] project convention. */ val Project.`java`:
org.gradle.api.plugins.JavaPluginConvention get() = convention.getPluginByName<org.gradle.api.plugins.JavaPluginConvention>("java") /** * Configures the [java][org.gradle.api.plugins.JavaPluginConvention] project convention. */ fun Project.`java`(configure: org.gradle.api.plugins.JavaPluginConvention.() -> Unit): Unit = configure(`java`) org.gradle.kotlin.dsl.accessors.kt -
private fun writeAccessorsFor(projectSchema: ProjectSchema<TypeAccessibility>, writer: BufferedWriter) { writer.apply { write(fileHeader)
newLine() appendln("import org.gradle.api.Project") appendln("import org.gradle.api.artifacts.Configuration") appendln("import org.gradle.api.artifacts.ConfigurationContainer") appendln("import org.gradle.api.artifacts.Dependency") appendln("import org.gradle.api.artifacts.ExternalModuleDependency") appendln("import org.gradle.api.artifacts.ModuleDependency") appendln("import org.gradle.api.artifacts.dsl.DependencyHandler") newLine() appendln("import org.gradle.kotlin.dsl.*") newLine() projectSchema.forEachAccessor { appendln(it) } } } org.gradle.kotlin.dsl.accessors.AccessorsClassPath.kt -
internal fun ProjectSchema<TypeAccessibility>.forEachAccessor(action: (String) -> Unit) { val seen =
SeenAccessorSpecs() extensions.mapNotNull(::typedAccessorSpec).forEach { spec -> extensionAccessorFor(spec)?.let { extensionAccessor -> action(extensionAccessor) seen.add(spec) } } conventions.mapNotNull(::typedAccessorSpec).filterNot(seen::hasConflict).forEach { spec -> conventionAccessorFor(spec)?.let(action) } configurations.map(::accessorNameSpec).forEach { spec -> configurationAccessorFor(spec)?.let(action) } } org.gradle.kotlin.dsl.accessors.GodeGenerator.kt -
private fun accessibleExtensionAccessorFor(targetType: String, name: AccessorNameSpec, type: String): String =
name.run { """ /** * Retrieves the [$original][$type] extension. */ val $targetType.`$kotlinIdentifier`: $type get() = $thisExtensions.getByName("$stringLiteral") as $type /** * Configures the [$original][$type] extension. */ fun $targetType.`$kotlinIdentifier`(configure: $type.() -> Unit): Unit = $thisExtensions.configure("$stringLiteral", configure) """ } org.gradle.kotlin.dsl.accessors.GodeGenerator.kt -
// Groovy // Ensure the no-op leakcanary dependency is always
used in JVM tests. configurations.all { config -> if (config.name.contains("UnitTest")) { config.resolutionStrategy.eachDependency { details -> if (details.requested.group == "com.squareup.leakcanary" && details.requested.name == "leakcanary-android") { details.useTarget(group: details.requested.group, name: "leakcanary-android-no-op", version: details.requested.version) }A }B }C }D https://github.com/square/leakcanary/wiki/FAQ#how-do-i-disable-leakcanary-in-tests -
// Kotlin // Ensure the no-op leakcanary dependency is always
used in JVM tests. configurations.all { if (name.contains("UnitTest")) { resolutionStrategy.eachDependency { if (requested.group == "com.squareup.leakcanary" && requested.name == “leakcanary-android") { useTarget(mapOf("group" to requested.group, "name" to "leakcanary-android-no-op", "version" to requested.version)) }A }B }C }D -
// Groovy // Ensure the no-op leakcanary dependency is always
used in JVM tests. configurations.all { config -> if (config.name.contains("UnitTest")) { config.resolutionStrategy.eachDependency { details -> if (details.requested.group == "com.squareup.leakcanary" && details.requested.name == "leakcanary-android") { details.useTarget(group: details.requested.group, name: "leakcanary-android-no-op", version: details.requested.version) }A }B }C }D -
// Kotlin // Ensure the no-op leakcanary dependency is always
used in JVM tests. configurations.all { if (name.contains("UnitTest")) { resolutionStrategy.eachDependency { if (requested.group == "com.squareup.leakcanary" && requested.name == “leakcanary-android") { useTarget(mapOf("group" to requested.group, "name" to "leakcanary-android-no-op", "version" to requested.version)) }A }B }C }D -
• Experiments are fun • Build speeds are slower •
Kotlin DSL is still pre-release • Improvements happening all the time • Everything is an extension function -
task downloadAndUnzipGcloud(dependsOn: downloadGCloud, type: Copy) { description "Unzip gcloud tools
in to the build directory" from tarTree(downloadGCloud.dest) into new File(buildDir, "gcloud/") }A -
tasks { val downloadAndUnzipGcloud by creating(Copy::class) { description = "Unzip
gcloud tools in to the build directory" from(tarTree(downloadGCloud.dest)) into(File(buildDir, "gcloud/")) dependsOn(downloadGCloud) }A } -
/** * Provides a property delegate that creates elements of
theagiven [type] with theagiven [configuration]. */ fun <T : Any, U : T> PolymorphicDomainObjectContainer<T>.creating(type: KClass<U>, configuration: U.() -> Unit) = creating(type.java, configuration) -
tasks { val downloadAndUnzipGcloud by creating(Copy::class) { description = "Unzip
gcloud tools in to the build directory" from(tarTree(downloadGCloud.dest)) into(File(buildDir, "gcloud/")) dependsOn(downloadGCloud) }A } -
/** * <p>Returns the tasks of this project.</p> * *
@return the tasks of this project. */ TaskContainer getTasks(); -
/** * <p>A {@code TaskContainer} is responsible for managing a
set of {@link Task} instances.</p> * * <p>You can obtain a {@code TaskContainer} instance by calling {@link org.gradle.api.Project#getTasks()}, or using the * {@code tasks} property in your build script.</p> */ @HasInternalProtocol public interface TaskContainer extends TaskCollection<Task>, PolymorphicDomainObjectContainer<Task> { -
/** * Provides a property delegate that creates elements of
the given [type] with the given [configuration]. */ fun <T : Any, U : T> PolymorphicDomainObjectContainer<T>.creating(type: KClass<U>, configuration: U.() -> Unit) = creating(type.java, configuration) -
tasks { val downloadAndUnzipGcloud by creating(Copy::class) { description = "Unzip
gcloud tools in to the build directory" from(tarTree(downloadGCloud.dest)) into(File(buildDir, "gcloud/")) dependsOn(downloadGCloud) }A }