Index: buildSrc/src/main/kotlin/plugins/kotlin-dsl-module.gradle.kts =================================================================== diff -u -N -r8badb804408b301284207e07bcb7907a5af33e68 -r071d76cf5c78736f00c22fd6240ed425df3acf51 --- buildSrc/src/main/kotlin/plugins/kotlin-dsl-module.gradle.kts (.../kotlin-dsl-module.gradle.kts) (revision 8badb804408b301284207e07bcb7907a5af33e68) +++ buildSrc/src/main/kotlin/plugins/kotlin-dsl-module.gradle.kts (.../kotlin-dsl-module.gradle.kts) (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -31,8 +31,7 @@ // including all sources val main by java.sourceSets afterEvaluate { - tasks.getByName("jar") { - this as Jar + tasks.getByName("jar") { from(main.allSource) manifest.attributes.apply { put("Implementation-Title", "Gradle Kotlin DSL (${project.name})") Index: integ-tests/.gitignore =================================================================== diff -u -N --- integ-tests/.gitignore (revision b549de7e15d654a9027fb9d1265e7ede4f652ec1) +++ integ-tests/.gitignore (revision 0) @@ -1,2 +0,0 @@ -/build -/out Index: integ-tests/build.gradle.kts =================================================================== diff -u -N --- integ-tests/build.gradle.kts (revision 8ef5967764c32fd388a836cdb7e44da6f17260fe) +++ integ-tests/build.gradle.kts (revision 0) @@ -1,60 +0,0 @@ -import build.* -import plugins.* - -plugins { - id("kotlin-library") -} - -dependencies { - compile(project(":test-fixtures")) -} - -val pluginBundles = listOf( - ":plugins", - ":plugins-experiments") - -pluginBundles.forEach { - evaluationDependsOn(it) -} - -val futurePluginVersionsTasks = - pluginBundles.map { - project(it).tasks["writeFuturePluginVersions"] as WriteProperties - } - -val customInstallation by rootProject.tasks - -tasks { - - "test" { - dependsOn(customInstallation) - pluginBundles.forEach { - dependsOn(":$it:publishPluginsToTestRepository") - } - } - - - val processTestResources by getting(ProcessResources::class) - - val writeFuturePluginVersions by creating { - - group = "build" - description = "Merges all future plugin bundle versions so they can all be tested at once" - - dependsOn(futurePluginVersionsTasks) - inputs.files(futurePluginVersionsTasks.map { it.outputFile }) - outputs.file(processTestResources.futurePluginVersionsFile) - - doLast { - outputs.files.singleFile.bufferedWriter().use { writer -> - inputs.files.forEach { input -> - writer.appendln(input.readText()) - } - } - } - } - - processTestResources.dependsOn(writeFuturePluginVersions) -} - -withParallelTests() Index: integ-tests/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginIntegrationTest.kt =================================================================== diff -u -N --- integ-tests/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginIntegrationTest.kt (revision b549de7e15d654a9027fb9d1265e7ede4f652ec1) +++ integ-tests/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginIntegrationTest.kt (revision 0) @@ -1,38 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest - -import org.junit.Test - - -class PrecompiledScriptPluginIntegrationTest : AbstractPluginTest() { - - @Test - fun `generated code follows kotlin-dsl coding conventions`() { - - withBuildScript(""" - plugins { - `kotlin-dsl` - `java-gradle-plugin` - id("org.gradle.kotlin.ktlint-convention") - } - - apply() - - repositories { jcenter() } - """) - - withFile("src/main/kotlin/plugin-without-package.gradle.kts") - withFile("src/main/kotlin/plugins/plugin-with-package.gradle.kts", """ - package plugins - """) - - build("generateScriptPluginAdapters") - build("ktlintC") - } - - override val testRepositoryPaths: List - get() = normalisedPathsOf( - "../plugins/build/repository", - "../plugins-experiments/build/repository") -} Index: plugins-experiments/.gitignore =================================================================== diff -u -N --- plugins-experiments/.gitignore (revision 48be3155fbdb0df08baf2290175d7899678494d4) +++ plugins-experiments/.gitignore (revision 0) @@ -1,2 +0,0 @@ -/build -/out Index: plugins-experiments/build.gradle.kts =================================================================== diff -u -N --- plugins-experiments/build.gradle.kts (revision 1ce7639bda12e7a3d2dd07e6c89c24ff9e841f79) +++ plugins-experiments/build.gradle.kts (revision 0) @@ -1,88 +0,0 @@ -import build.futureKotlin -import plugins.bundledGradlePlugin -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import org.gradle.internal.hash.Hashing - -plugins { - id("kotlin-dsl-plugin-bundle") - id("com.github.johnrengelman.shadow") version "2.0.2" apply false -} - -base { - archivesBaseName = "gradle-kotlin-dsl-plugins-experiments" -} - -repositories { - gradlePluginPortal() -} - -dependencies { - compileOnly(gradleKotlinDsl()) - - implementation("gradle.plugin.org.jlleitschuh.gradle:ktlint-gradle:3.3.0") - implementation(futureKotlin("stdlib-jdk8")) - - testImplementation(project(":test-fixtures")) -} - - -// plugins ------------------------------------------------------------ - -bundledGradlePlugin( - name = "ktlintConvention", - shortDescription = "Gradle Kotlin DSL ktlint convention plugin (experimental)", - pluginId = "org.gradle.kotlin.ktlint-convention", - pluginClass = "org.gradle.kotlin.dsl.experiments.plugins.GradleKotlinDslKtlintConventionPlugin") - - -// default versions --------------------------------------------------- - -val ktlintVersion = "0.22.0" - -val basePackagePath = "org/gradle/kotlin/dsl/experiments/plugins" -val processResources: ProcessResources by tasks -val writeDefaultVersionsProperties by tasks.creating(WriteProperties::class) { - outputFile = processResources.destinationDir.resolve("$basePackagePath/default-versions.properties") - property("ktlint", ktlintVersion) -} -processResources.dependsOn(writeDefaultVersionsProperties) - - -// ktlint custom ruleset ---------------------------------------------- - -val ruleset by java.sourceSets.creating -val rulesetShaded by configurations.creating -val rulesetCompileOnly by configurations.getting { - extendsFrom(rulesetShaded) -} - -val generatedResourcesRulesetJarDir = file("$buildDir/generated-resources/ruleset/resources") -val rulesetJar by tasks.creating(ShadowJar::class) { - archiveName = "gradle-kotlin-dsl-ruleset.jar" - destinationDir = generatedResourcesRulesetJarDir.resolve(basePackagePath) - configurations = listOf(rulesetShaded) - from(ruleset.output) -} -val rulesetChecksum by tasks.creating { - dependsOn(rulesetJar) - val rulesetChecksumFile = generatedResourcesRulesetJarDir - .resolve(basePackagePath) - .resolve("gradle-kotlin-dsl-ruleset.md5") - inputs.file(rulesetJar.archivePath) - outputs.file(rulesetChecksumFile) - doLast { - rulesetChecksumFile.parentFile.mkdirs() - rulesetChecksumFile.writeText(Hashing.md5().hashBytes(rulesetJar.archivePath.readBytes()).toString()) - } -} -java.sourceSets["main"].output.dir( - mapOf("builtBy" to listOf(rulesetJar, rulesetChecksum)), - generatedResourcesRulesetJarDir) - -dependencies { - rulesetShaded("com.github.shyiko.ktlint:ktlint-ruleset-standard:$ktlintVersion") { - isTransitive = false - } - rulesetCompileOnly("com.github.shyiko.ktlint:ktlint-core:$ktlintVersion") - rulesetCompileOnly(futureKotlin("reflect")) -} Index: plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPlugin.kt =================================================================== diff -u -N --- plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPlugin.kt (revision 4a341e2348cab6eb67516f71341162951ca0438d) +++ plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPlugin.kt (revision 0) @@ -1,137 +0,0 @@ -package org.gradle.kotlin.dsl.experiments.plugins - -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.execution.TaskExecutionListener -import org.gradle.api.plugins.JavaPluginConvention -import org.gradle.api.tasks.JavaExec -import org.gradle.api.tasks.SourceSet -import org.gradle.api.tasks.TaskState - -import org.gradle.cache.internal.GeneratedGradleJarCache -import org.gradle.internal.logging.ConsoleRenderer - -import org.jlleitschuh.gradle.ktlint.KtlintExtension -import org.jlleitschuh.gradle.ktlint.reporter.ReporterType - -import org.gradle.kotlin.dsl.* -import org.gradle.kotlin.dsl.support.serviceOf - - -private -val rulesetChecksum by lazy { - GradleKotlinDslKtlintConventionPlugin::class.java.getResource("gradle-kotlin-dsl-ruleset.md5").readText() -} - - -private -val rulesetJar by lazy { - GradleKotlinDslKtlintConventionPlugin::class.java.getResource("gradle-kotlin-dsl-ruleset.jar") -} - - -open class GradleKotlinDslKtlintConventionPlugin : Plugin { - - override fun apply(project: Project): Unit = project.run { - - plugins.apply("org.jlleitschuh.gradle.ktlint") - - configure { - version = DefaultVersions.ktlint - reporters = arrayOf(ReporterType.PLAIN) - } - - val ktlint by configurations.creating { - exclude(module = "ktlint-ruleset-standard") - } - - dependencies { - ktlint(files(gradleKotlinDslKtlintRulesetJar())) - ktlint(kotlin("reflect")) - } - - plugins.withId("kotlin") { - afterEvaluate { - fixKtlintTasks() - } - } - } - - - private - fun Project.gradleKotlinDslKtlintRulesetJar() = provider { - serviceOf().get("ktlint-convention-ruleset-$rulesetChecksum") { jar -> - jar.outputStream().use { it.write(rulesetJar.readBytes()) } - } - } - - - // Note that below are workarounds, not how things should be fixed upstream - // https://github.com/JLLeitschuh/ktlint-gradle/issues/67 - // https://github.com/JLLeitschuh/ktlint-gradle/issues/51 - private - fun Project.fixKtlintTasks() { - val reporters = the().reporters - val ktLintCheckTasks = collectKtLintCheckTasks() - fixKtlintCheckTaskCacheability(ktLintCheckTasks, reporters) - displayLinkToReportsOnFailure(ktLintCheckTasks, reporters) - } - - - private - fun Project.collectKtLintCheckTasks() = - the().sourceSets.mapNotNull { sourceSet -> - (tasks.findByName("ktlint${sourceSet.name.capitalize()}Check") as? JavaExec)?.let { task -> - Pair(sourceSet, task) - } - } - - - private - fun Project.fixKtlintCheckTaskCacheability( - tasksBySourceSets: List>, - reporters: Array - ) = - - tasksBySourceSets.forEach { (sourceSet, task) -> - - sourceSet.allSource.sourceDirectories.forEach { _ -> - reporters.forEach { - task.outputs.file("$buildDir/${it.reportPathFor(sourceSet)}") - } - task.outputs.cacheIf { true } - } - } - - - private - fun Project.displayLinkToReportsOnFailure( - tasksBySourceSets: List>, - reporters: Array - ) = - - gradle.taskGraph.addTaskExecutionListener(object : TaskExecutionListener { - - val consoleRenderer = ConsoleRenderer() - - override fun beforeExecute(aTask: Task) = Unit - - override fun afterExecute(aTask: Task, state: TaskState) { - if (state.failure != null) { - tasksBySourceSets.find { it.second == aTask }?.let { (sourceSet, _) -> - val message = "ktlint check failed\n\n" + reporters.map { - file("$buildDir/${it.reportPathFor(sourceSet)}") - }.joinToString(separator = "\n") { - consoleRenderer.asClickableFileUrl(it).prependIndent() - } + '\n' - logger.error(message) - } - } - } - }) - - private - fun ReporterType.reportPathFor(sourceSet: SourceSet) = - "reports/ktlint/ktlint-${sourceSet.name}.$fileExtension" -} Index: plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/default-versions.kt =================================================================== diff -u -N --- plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/default-versions.kt (revision cbda79b7f3c306a7ef90df9321fc55e84886547c) +++ plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/default-versions.kt (revision 0) @@ -1,19 +0,0 @@ -package org.gradle.kotlin.dsl.experiments.plugins - -import java.util.Properties - - -internal -object DefaultVersions { - - val ktlint: String by DEFAULT_VERSIONS -} - - -private -val DEFAULT_VERSIONS = - Properties().also { props -> - DefaultVersions::javaClass.get().getResourceAsStream("default-versions.properties")!!.use { input -> - props.load(input) - } - } Index: plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/BlankLinesRule.kt =================================================================== diff -u -N --- plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/BlankLinesRule.kt (revision a761ae725b981e43f6e7a3ab37c6ac39d9496392) +++ plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/BlankLinesRule.kt (revision 0) @@ -1,74 +0,0 @@ -package org.gradle.kotlin.dsl.ktlint.ruleset - -import com.github.shyiko.ktlint.core.Rule - -import org.jetbrains.kotlin.com.intellij.lang.ASTNode -import org.jetbrains.kotlin.com.intellij.psi.PsiComment -import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace -import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement -import org.jetbrains.kotlin.com.intellij.psi.stubs.IStubElementType -import org.jetbrains.kotlin.com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.kdoc.psi.api.KDoc -import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes - -import kotlin.reflect.KClass - - -class BlankLinesRule : Rule("gradle-kotlin-dsl-blank-lines") { - - companion object { - - private - val ignoredTopLevelElementTypes = listOf>( - KtStubElementTypes.FILE_ANNOTATION_LIST, - KtStubElementTypes.IMPORT_LIST, - KtStubElementTypes.PACKAGE_DIRECTIVE) - - private - val ignoredTopLevelPsiTypes = listOf>( - PsiComment::class, - KDoc::class) - } - - private - var skippedFirstTopLevelWhiteSpace = false - - override fun visit( - node: ASTNode, - autoCorrect: Boolean, - emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit - ) { - - if (node is PsiWhiteSpace) { - - val split = node.getText().split("\n") - - // Not more than 2 blank lines anywhere in the file - if (split.size > 4 || split.size == 3 && PsiTreeUtil.nextLeaf(node) == null /* eof */) { - emit(node.startOffset + split[0].length + split[1].length + 2, "Needless blank line(s)", true) - if (autoCorrect) { - (node as LeafPsiElement) - .rawReplaceWithText("${split.first()}\n${if (split.size > 3) "\n" else ""}${split.last()}") - } - } - - // Two blank lines before top level elements - if (node.treeParent.elementType == KtStubElementTypes.FILE) { - if (!skippedFirstTopLevelWhiteSpace) { - skippedFirstTopLevelWhiteSpace = true - return - } - } - - if (node.treeParent.elementType == KtStubElementTypes.FILE - && node.treeNext != null - && node.treeNext.elementType !in ignoredTopLevelElementTypes - && ignoredTopLevelPsiTypes.none { it.isInstance(node.treeNext) } - && PsiTreeUtil.nextLeaf(node) != null /* not oef */ - && split.size < 4) { - - emit(node.startOffset, "Top level elements must be separated by two blank lines", false) - } - } - } -} Index: plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomChainWrappingRule.kt =================================================================== diff -u -N --- plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomChainWrappingRule.kt (revision cbda79b7f3c306a7ef90df9321fc55e84886547c) +++ plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomChainWrappingRule.kt (revision 0) @@ -1,54 +0,0 @@ -package org.gradle.kotlin.dsl.ktlint.ruleset - -import com.github.shyiko.ktlint.core.Rule - -import org.jetbrains.kotlin.com.intellij.lang.ASTNode -import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement -import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl -import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.psiUtil.nextLeaf -import org.jetbrains.kotlin.psi.psiUtil.prevLeaf - - -// Same as upstream except it doesn't have checks for "same line tokens" -class CustomChainWrappingRule : Rule("gradle-kotlin-dsl-chain-wrapping") { - - private - val nextLineTokens = TokenSet.create(KtTokens.DOT, KtTokens.SAFE_ACCESS, KtTokens.ELVIS) - - private - val noSpaceAroundTokens = TokenSet.create(KtTokens.DOT, KtTokens.SAFE_ACCESS) - - override fun visit( - node: ASTNode, - autoCorrect: Boolean, - emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit - ) { - /* - org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement (DOT) | "." - org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl (WHITE_SPACE) | "\n " - org.jetbrains.kotlin.psi.KtCallExpression (CALL_EXPRESSION) - */ - val elementType = node.elementType - if (nextLineTokens.contains(elementType)) { - val nextLeaf = node.psi.nextLeaf(true) - if (nextLeaf is PsiWhiteSpaceImpl && nextLeaf.textContains('\n')) { - emit(node.startOffset, "Line must not end with \"${node.text}\"", true) - if (autoCorrect) { - val prevLeaf = node.psi.prevLeaf(true) - if (prevLeaf is PsiWhiteSpaceImpl) { - prevLeaf.rawReplaceWithText(nextLeaf.text) - } else { - (node.psi as LeafPsiElement).rawInsertBeforeMe(PsiWhiteSpaceImpl(nextLeaf.text)) - } - if (noSpaceAroundTokens.contains(elementType)) { - nextLeaf.node.treeParent.removeChild(nextLeaf.node) - } else { - nextLeaf.rawReplaceWithText(" ") - } - } - } - } - } -} Index: plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomImportsRule.kt =================================================================== diff -u -N --- plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomImportsRule.kt (revision cbda79b7f3c306a7ef90df9321fc55e84886547c) +++ plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomImportsRule.kt (revision 0) @@ -1,37 +0,0 @@ -package org.gradle.kotlin.dsl.ktlint.ruleset - -import com.github.shyiko.ktlint.core.Rule - -import org.jetbrains.kotlin.com.intellij.lang.ASTNode -import org.jetbrains.kotlin.psi.KtImportDirective -import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes - - -private -val allowedWildcardImports = listOf( - - "java.util.*", - "org.gradle.kotlin.dsl.*", - - "org.junit.Assert.*", - "org.hamcrest.CoreMatchers.*", - "com.nhaarman.mockito_kotlin.*" -) - - -class CustomImportsRule : Rule("gradle-kotlin-dsl-imports") { - - override fun visit( - node: ASTNode, - autoCorrect: Boolean, - emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit - ) { - if (node.elementType == KtStubElementTypes.IMPORT_DIRECTIVE) { - val importDirective = node.psi as KtImportDirective - val path = importDirective.importPath?.pathStr - if (path != null && path.contains('*') && path !in allowedWildcardImports) { - emit(node.startOffset, "Wildcard import not allowed ($path)", false) - } - } - } -} Index: plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/GradleKotlinDslRuleSetProvider.kt =================================================================== diff -u -N --- plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/GradleKotlinDslRuleSetProvider.kt (revision cbda79b7f3c306a7ef90df9321fc55e84886547c) +++ plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/GradleKotlinDslRuleSetProvider.kt (revision 0) @@ -1,82 +0,0 @@ -package org.gradle.kotlin.dsl.ktlint.ruleset - -import com.github.shyiko.ktlint.core.RuleSet -import com.github.shyiko.ktlint.core.RuleSetProvider -import com.github.shyiko.ktlint.ruleset.standard.FinalNewlineRule -import com.github.shyiko.ktlint.ruleset.standard.IndentationRule -import com.github.shyiko.ktlint.ruleset.standard.MaxLineLengthRule -import com.github.shyiko.ktlint.ruleset.standard.ModifierOrderRule -import com.github.shyiko.ktlint.ruleset.standard.NoBlankLineBeforeRbraceRule -import com.github.shyiko.ktlint.ruleset.standard.NoEmptyClassBodyRule -import com.github.shyiko.ktlint.ruleset.standard.NoLineBreakAfterElseRule -import com.github.shyiko.ktlint.ruleset.standard.NoLineBreakBeforeAssignmentRule -import com.github.shyiko.ktlint.ruleset.standard.NoMultipleSpacesRule -import com.github.shyiko.ktlint.ruleset.standard.NoSemicolonsRule -import com.github.shyiko.ktlint.ruleset.standard.NoTrailingSpacesRule -import com.github.shyiko.ktlint.ruleset.standard.NoUnitReturnRule -import com.github.shyiko.ktlint.ruleset.standard.NoUnusedImportsRule -import com.github.shyiko.ktlint.ruleset.standard.ParameterListWrappingRule -import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundColonRule -import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundCommaRule -import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundCurlyRule -import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundKeywordRule -import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundOperatorsRule -import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundRangeOperatorRule -import com.github.shyiko.ktlint.ruleset.standard.StringTemplateRule - - -/** - * Gradle Kotlin DSL ktlint RuleSetProvider. - * - * Reuse ktlint-standard-ruleset rules and add custom ones. - */ -class GradleKotlinDslRuleSetProvider : RuleSetProvider { - - override fun get(): RuleSet = - RuleSet( - "gradle-kotlin-dsl", - - // ktlint standard ruleset rules -------------------------- - // See https://github.com/shyiko/ktlint/blob/master/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/StandardRuleSetProvider.kt - - // kotlin-dsl: disabled in favor of CustomChainWrappingRule - // ChainWrappingRule(), - FinalNewlineRule(), - // disabled until it's clear how to reconcile difference in Intellij & Android Studio import layout - // ImportOrderingRule(), - IndentationRule(), - MaxLineLengthRule(), - ModifierOrderRule(), - NoBlankLineBeforeRbraceRule(), - // kotlin-dsl disabled in favor of BlankLinesRule - // NoConsecutiveBlankLinesRule(), - NoEmptyClassBodyRule(), - // disabled until it's clear what to do in case of `import _.it` - // NoItParamInMultilineLambdaRule(), - NoLineBreakAfterElseRule(), - NoLineBreakBeforeAssignmentRule(), - NoMultipleSpacesRule(), - NoSemicolonsRule(), - NoTrailingSpacesRule(), - NoUnitReturnRule(), - NoUnusedImportsRule(), - // kotlin-dsl: disabled in favor of CustomImportsRule - // NoWildcardImportsRule(), - ParameterListWrappingRule(), - SpacingAroundColonRule(), - SpacingAroundCommaRule(), - SpacingAroundCurlyRule(), - SpacingAroundKeywordRule(), - SpacingAroundOperatorsRule(), - SpacingAroundRangeOperatorRule(), - StringTemplateRule(), - - // gradle-kotlin-dsl rules -------------------------------- - - BlankLinesRule(), - CustomChainWrappingRule(), - CustomImportsRule(), - VisibilityModifiersOwnLineRule(), - PropertyAccessorOnNewLine() - ) -} Index: plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/PropertyAccessorOnNewLine.kt =================================================================== diff -u -N --- plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/PropertyAccessorOnNewLine.kt (revision 0669d16c7719043edfa0f3d0cdd7c6920d97c539) +++ plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/PropertyAccessorOnNewLine.kt (revision 0) @@ -1,22 +0,0 @@ -package org.gradle.kotlin.dsl.ktlint.ruleset - -import com.github.shyiko.ktlint.core.Rule -import org.jetbrains.kotlin.KtNodeTypes - -import org.jetbrains.kotlin.com.intellij.lang.ASTNode - - -class PropertyAccessorOnNewLine : Rule("property-get-new-line") { - - override fun visit( - node: ASTNode, - autoCorrect: Boolean, - emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit - ) { - if (node.elementType == KtNodeTypes.PROPERTY_ACCESSOR) { - if (!node.treePrev.text.contains("\n")) { - emit(node.startOffset, "Property accessor must be on a new line", false) - } - } - } -} Index: plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/VisibilityModifiersOwnLineRule.kt =================================================================== diff -u -N --- plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/VisibilityModifiersOwnLineRule.kt (revision cbda79b7f3c306a7ef90df9321fc55e84886547c) +++ plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/VisibilityModifiersOwnLineRule.kt (revision 0) @@ -1,92 +0,0 @@ -package org.gradle.kotlin.dsl.ktlint.ruleset - -import com.github.shyiko.ktlint.core.Rule - -import org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR -import org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER -import org.jetbrains.kotlin.com.intellij.lang.ASTNode -import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE -import org.jetbrains.kotlin.psi.KtDeclarationModifierList - - -class VisibilityModifiersOwnLineRule : Rule("visibility-modifiers-own-line") { - - private - val ownSingleLineModifierTokens = arrayOf( - KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD - ) - - private - val order = arrayOf( - KtTokens.PUBLIC_KEYWORD, - KtTokens.PROTECTED_KEYWORD, - KtTokens.PRIVATE_KEYWORD, - KtTokens.INTERNAL_KEYWORD, - KtTokens.EXPECT_KEYWORD, - KtTokens.ACTUAL_KEYWORD, - KtTokens.FINAL_KEYWORD, - KtTokens.OPEN_KEYWORD, - KtTokens.ABSTRACT_KEYWORD, - KtTokens.SEALED_KEYWORD, - KtTokens.CONST_KEYWORD, - KtTokens.EXTERNAL_KEYWORD, - KtTokens.OVERRIDE_KEYWORD, - KtTokens.LATEINIT_KEYWORD, - KtTokens.TAILREC_KEYWORD, - KtTokens.VARARG_KEYWORD, - KtTokens.SUSPEND_KEYWORD, - KtTokens.INNER_KEYWORD, - KtTokens.ENUM_KEYWORD, - KtTokens.ANNOTATION_KEYWORD, - KtTokens.COMPANION_KEYWORD, - KtTokens.INLINE_KEYWORD, - KtTokens.INFIX_KEYWORD, - KtTokens.OPERATOR_KEYWORD, - KtTokens.DATA_KEYWORD - // NOINLINE_KEYWORD, CROSSINLINE_KEYWORD, OUT_KEYWORD, IN_KEYWORD, REIFIED_KEYWORD - // HEADER_KEYWORD, IMPL_KEYWORD - ) - - private - val tokenSet = TokenSet.create(*order) - - private - val skippedParents = listOf(PRIMARY_CONSTRUCTOR, VALUE_PARAMETER) - - override fun visit( - node: ASTNode, - autoCorrect: Boolean, - emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit - ) { - - if (node.psi is KtDeclarationModifierList && node.treeParent.elementType !in skippedParents) { - - val modifierArr = node.getChildren(tokenSet) - - val vizModifiers = modifierArr.filter { it.elementType in ownSingleLineModifierTokens } - - if (vizModifiers.isNotEmpty()) { - - val vizModifierExpectedText = vizModifiers.joinToString(separator = " ", postfix = "\n") { it.text } - - if (!node.textIncludingSurroundingWhitespace.contains(vizModifierExpectedText)) { - emit( - node.startOffset, - "Visibility modifiers must be on their own single line", - false - ) - } - } - } - } - - private - val ASTNode.textIncludingSurroundingWhitespace - get() = "${ - if (treePrev?.elementType == WHITE_SPACE) treePrev.text else "" - }$text${ - if (treeNext?.elementType == WHITE_SPACE) treeNext.text else "" - }" -} Index: plugins-experiments/src/ruleset/resources/META-INF/services/com.github.shyiko.ktlint.core.RuleSetProvider =================================================================== diff -u -N --- plugins-experiments/src/ruleset/resources/META-INF/services/com.github.shyiko.ktlint.core.RuleSetProvider (revision cbda79b7f3c306a7ef90df9321fc55e84886547c) +++ plugins-experiments/src/ruleset/resources/META-INF/services/com.github.shyiko.ktlint.core.RuleSetProvider (revision 0) @@ -1 +0,0 @@ -org.gradle.kotlin.dsl.ktlint.ruleset.GradleKotlinDslRuleSetProvider Index: plugins-experiments/src/test/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPluginTest.kt =================================================================== diff -u -N --- plugins-experiments/src/test/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPluginTest.kt (revision 6ba4f693699ad75ee0fe1f88165e99e98f4ed3af) +++ plugins-experiments/src/test/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPluginTest.kt (revision 0) @@ -1,265 +0,0 @@ -package org.gradle.kotlin.dsl.experiments.plugins - -import org.gradle.kotlin.dsl.embeddedKotlinVersion -import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest - -import org.gradle.testkit.runner.TaskOutcome - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.containsString - -import org.junit.Assert.assertThat -import org.junit.Before -import org.junit.Test - - -class GradleKotlinDslKtlintConventionPluginTest : AbstractPluginTest() { - - @Before - fun setup() { - withBuildScript(""" - plugins { - kotlin("jvm") version "$embeddedKotlinVersion" - id("org.gradle.kotlin.ktlint-convention") - } - - repositories { - jcenter() - } - """) - } - - @Test - fun `ktlint dependencies include kotlin-reflect`() { - - assertThat( - build("dependencies", "--configuration", "ktlint").output, - containsString("org.jetbrains.kotlin:kotlin-reflect:$embeddedKotlinVersion")) - } - - @Test - fun `ktlint check tasks are cacheable`() { - - withFile("gradle.properties", "org.gradle.caching=true") - existing("settings.gradle.kts").run { - writeText(readText() + """ - buildCache { - local { isEnabled = false } - remote(DirectoryBuildCache::class.java) { - directory = file("local-build-cache") - isEnabled = true - isPush = true - } - } - """) - } - - withSource("""val foo = "bar"""") - - build("ktlintMainCheck").apply { - - assertThat(outcomeOf(":ktlintMainCheck"), equalTo(TaskOutcome.SUCCESS)) - } - - build("ktlintMainCheck").apply { - - assertThat(outcomeOf(":ktlintMainCheck"), equalTo(TaskOutcome.UP_TO_DATE)) - } - - build("clean") - - build("ktlintMainCheck").apply { - - assertThat(outcomeOf(":ktlintMainCheck"), equalTo(TaskOutcome.FROM_CACHE)) - } - } - - @Test - fun `visibility modifiers on their own single line`() { - - withSource(""" - - private val bar = false - - - class Bazar(private val name: String) { - - private lateinit - var description: String - - private inline - fun something() = Unit - } - """) - - buildAndFail("ktlintMainCheck") - - assertKtlintErrors(3) - assertKtLintError("Visibility modifiers must be on their own single line", 3, 13) - assertKtLintError("Visibility modifiers must be on their own single line", 8, 17) - assertKtLintError("Visibility modifiers must be on their own single line", 11, 17) - - withSource(""" - - private - val bar = false - - - class Bazar(private val name: String) { - - private - lateinit var description: String - - private - inline fun something() = Unit - } - """) - - build("ktlintMainCheck") - } - - @Test - fun `allowed wildcard imports`() { - - withSource(""" - - import java.util.* - import org.w3c.dom.* - - import org.gradle.kotlin.dsl.* - """) - - buildAndFail("ktlintMainCheck") - - assertKtlintErrors(1) - assertKtLintError("Wildcard import not allowed (org.w3c.dom.*)", 4, 13) - } - - @Test - fun `blank lines`() { - - withSource(""" - package some - - import org.gradle.kotlin.dsl.* - - val foo = "bar" - - interface Foo - - - - object Bar - - - data class Some(val name: String) - """) - - buildAndFail("ktlintMainCheck") - - assertKtlintErrors(3) - assertKtLintError("Top level elements must be separated by two blank lines", 4, 43) - assertKtLintError("Top level elements must be separated by two blank lines", 6, 28) - assertKtLintError("Needless blank line(s)", 10, 1) - - withSource(""" - /* - * Copyright 2016 the original author or authors. - */ - - // Random words - @file:JvmName("Something") - - /** - * Package kdoc. - */ - package some - - import org.gradle.kotlin.dsl.* - - - /* - * Some file documentation. - */ - - - val foo = "bar" - - - /** - * Interface kdoc. - */ - interface Foo - - - object Bar - - - data class Some(val name: String) - """) - - build("ktlintMainCheck") - } - - @Test - fun `new lines starting with ANDAND are allowed`() { - - withSource(""" - - val foo = "bar".isNotEmpty() - && "bazar".isNotEmpty() // either - """) - - build("ktlintMainCheck") - } - - @Test - fun `property accessors on new line`() { - - withSource(""" - - val foo get() = "bar" - - - val bar: String get() { return "bar" } - """) - - buildAndFail("ktlintMainCheck") - - assertKtlintErrors(2) - assertKtLintError("Property accessor must be on a new line", 3, 17) - assertKtLintError("Property accessor must be on a new line", 6, 25) - - withSource(""" - - val foo - get() = "bar" - - - val bar: String - get() { return "bar" } - """) - - build("ktlintMainCheck") - } - - private - fun withSource(text: String) = - withFile("src/main/kotlin/source.kt", text) - - private - val ktlintReportFile by lazy { existing("build/reports/ktlint/ktlint-main.txt") } - - private - fun assertKtlintErrors(count: Int) = - assertThat( - "ktlint error count", - ktlintReportFile.readLines().filter { it.contains("source.kt:") }.count(), - equalTo(count)) - - private - fun assertKtLintError(error: String, line: Int, column: Int) = - assertThat( - ktlintReportFile.readText(), - containsString("source.kt:$line:$column: $error")) -} Index: plugins/.gitignore =================================================================== diff -u -N --- plugins/.gitignore (revision b7fe7e4d695235451d46ac64c2a40c7914337757) +++ plugins/.gitignore (revision 0) @@ -1,2 +0,0 @@ -/build -/out Index: plugins/build.gradle.kts =================================================================== diff -u -N --- plugins/build.gradle.kts (revision 1ce7639bda12e7a3d2dd07e6c89c24ff9e841f79) +++ plugins/build.gradle.kts (revision 0) @@ -1,35 +0,0 @@ -import build.futureKotlin -import plugins.bundledGradlePlugin - -plugins { - id("kotlin-dsl-plugin-bundle") -} - -base { - archivesBaseName = "gradle-kotlin-dsl-plugins" -} - -dependencies { - compileOnly(project(":provider")) - - implementation(futureKotlin("stdlib-jdk8")) - implementation(futureKotlin("gradle-plugin")) - implementation(futureKotlin("sam-with-receiver")) - - testImplementation(project(":test-fixtures")) -} - - -// plugins ------------------------------------------------------------ - -bundledGradlePlugin( - name = "embeddedKotlin", - shortDescription = "Embedded Kotlin Gradle Plugin", - pluginId = "org.gradle.kotlin.embedded-kotlin", - pluginClass = "org.gradle.kotlin.dsl.plugins.embedded.EmbeddedKotlinPlugin") - -bundledGradlePlugin( - name = "kotlinDsl", - shortDescription = "Gradle Kotlin DSL Plugin", - pluginId = "org.gradle.kotlin.kotlin-dsl", - pluginClass = "org.gradle.kotlin.dsl.plugins.dsl.KotlinDslPlugin") Index: plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslCompilerPlugins.kt =================================================================== diff -u -N --- plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslCompilerPlugins.kt (revision d72d78cce20e786cec0327bea3d60ee3745a73b3) +++ plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslCompilerPlugins.kt (revision 0) @@ -1,40 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.plugins.dsl - -import org.gradle.api.HasImplicitReceiver -import org.gradle.api.Plugin -import org.gradle.api.Project - -import org.jetbrains.kotlin.samWithReceiver.gradle.SamWithReceiverExtension -import org.jetbrains.kotlin.samWithReceiver.gradle.SamWithReceiverGradleSubplugin - - -/** - * Configures the Kotlin compiler to recognise Gradle functional interface - * annotated with [HasImplicitReceiver]. - */ -open class KotlinDslCompilerPlugins : Plugin { - - override fun apply(project: Project): Unit = project.run { - - plugins.apply(SamWithReceiverGradleSubplugin::class.java) - extensions.configure(SamWithReceiverExtension::class.java) { samWithReceiver -> - samWithReceiver.annotation(HasImplicitReceiver::class.qualifiedName!!) - } - } -} Index: plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPlugin.kt =================================================================== diff -u -N --- plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPlugin.kt (revision ff6318f459efc329156b1de40637fb3565104de7) +++ plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPlugin.kt (revision 0) @@ -1,61 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.plugins.dsl - -import org.gradle.api.Plugin -import org.gradle.api.Project - -import org.gradle.kotlin.dsl.gradleKotlinDsl -import org.gradle.kotlin.dsl.plugins.embedded.EmbeddedKotlinPlugin - - -/** - * The `kotlin-dsl` plugin. - * - * - Applies the `embedded-kotlin` plugin - * - Adds the `gradleKotlinDsl()` dependency to the `compileOnly` and `testImplementation` configurations - * - Configures the Kotlin DSL compiler plugins - * - * @see org.gradle.kotlin.dsl.plugins.embedded.EmbeddedKotlinPlugin - */ -open class KotlinDslPlugin : Plugin { - - override fun apply(project: Project) { - project.run { - - applyEmbeddedKotlinPlugin() - applyKotlinDslCompilerPlugins() - addGradleKotlinDslDependencyTo("compileOnly", "testImplementation") - } - } - - private - fun Project.applyEmbeddedKotlinPlugin() { - plugins.apply(EmbeddedKotlinPlugin::class.java) - } - - private - fun Project.applyKotlinDslCompilerPlugins() { - plugins.apply(KotlinDslCompilerPlugins::class.java) - } - - private - fun Project.addGradleKotlinDslDependencyTo(vararg configurations: String) { - configurations.forEach { - dependencies.add(it, gradleKotlinDsl()) - } - } -} Index: plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPlugin.kt =================================================================== diff -u -N --- plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPlugin.kt (revision e1a19b2b552fd1dc08d0455b7def529e5ee670fc) +++ plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPlugin.kt (revision 0) @@ -1,62 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.plugins.embedded - -import org.gradle.api.Plugin -import org.gradle.api.Project - -import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper - -import org.gradle.kotlin.dsl.support.EmbeddedKotlinProvider - -import javax.inject.Inject - - -/** - * The `embedded-kotlin` plugin. - * - * Applies the `org.jetbrains.kotlin.jvm` plugin, - * adds compile only dependencies on `kotlin-stdlib` and `kotlin-reflect`, - * configures an embedded repository that contains all embedded Kotlin libraries, - * and pins them to the embedded Kotlin version. - */ -open class EmbeddedKotlinPlugin @Inject internal constructor( - private val embeddedKotlin: EmbeddedKotlinProvider -) : Plugin { - - override fun apply(project: Project) { - project.run { - - plugins.apply(KotlinPluginWrapper::class.java) - - embeddedKotlin.addRepositoryTo(repositories) - - val embeddedKotlinConfiguration = configurations.create("embeddedKotlin") - embeddedKotlin.addDependenciesTo( - dependencies, - embeddedKotlinConfiguration.name, - "stdlib-jdk8", "reflect") - - listOf("compileOnly", "testCompileOnly").forEach { - configurations.getByName(it).extendsFrom(embeddedKotlinConfiguration) - } - - configurations.all { - embeddedKotlin.pinDependenciesOn(it, "stdlib-jdk8", "reflect", "compiler-embeddable") - } - } - } -} Index: plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPlugins.kt =================================================================== diff -u -N --- plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPlugins.kt (revision dfa49ee788b1ac408c7084498e8078c7bac3c6da) +++ plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPlugins.kt (revision 0) @@ -1,226 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.plugins.precompiled - -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.file.FileTree -import org.gradle.api.file.SourceDirectorySet -import org.gradle.api.plugins.JavaPluginConvention -import org.gradle.api.tasks.SourceSet - -import org.gradle.kotlin.dsl.* - -import org.gradle.kotlin.dsl.precompile.PrecompiledInitScript -import org.gradle.kotlin.dsl.precompile.PrecompiledProjectScript -import org.gradle.kotlin.dsl.precompile.PrecompiledScriptDependenciesResolver -import org.gradle.kotlin.dsl.precompile.PrecompiledSettingsScript - -import org.gradle.kotlin.dsl.support.ImplicitImports -import org.gradle.kotlin.dsl.support.serviceOf - -import org.gradle.plugin.devel.GradlePluginDevelopmentExtension -import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin - -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -import java.io.File - - -/* - * Exposes `*.gradle.kts` scripts from regular Kotlin source-sets as binary Gradle plugins. - */ -open class PrecompiledScriptPlugins : Plugin { - - override fun apply(project: Project): Unit = project.run { - - enableScriptCompilation() - - plugins.withType { - exposeScriptsAsGradlePlugins() - } - } -} - - -private -fun Project.enableScriptCompilation() { - - afterEvaluate { - - tasks { - - "compileKotlin"(KotlinCompile::class) { - kotlinOptions { - freeCompilerArgs += listOf( - "-script-templates", scriptTemplates, - // Propagate implicit imports and other settings - "-Xscript-resolver-environment=${resolverEnvironment()}" - ) - } - } - } - } -} - - -private -val scriptTemplates by lazy { - listOf( - // treat *.settings.gradle.kts files as Settings scripts - PrecompiledSettingsScript::class.qualifiedName!!, - // treat *.init.gradle.kts files as Gradle scripts - PrecompiledInitScript::class.qualifiedName!!, - // treat *.gradle.kts files as Project scripts - PrecompiledProjectScript::class.qualifiedName!! - ).joinToString(separator = ",") -} - - -private -fun Project.resolverEnvironment() = - (PrecompiledScriptDependenciesResolver.EnvironmentProperties.kotlinDslImplicitImports - + "=\"" + implicitImports().joinToString(separator = ":") + "\"") - - -private -fun Project.implicitImports(): List = - serviceOf().list - - -private -fun Project.exposeScriptsAsGradlePlugins() { - - val scriptSourceFiles = pluginSourceSet.allSource.matching { - it.include("**/*.gradle.kts") - } - - val scriptPlugins = - scriptSourceFiles.map(::ScriptPlugin) - - declareScriptPlugins(scriptPlugins) - - generatePluginAdaptersFor(scriptPlugins, scriptSourceFiles) -} - - -private -val Project.pluginSourceSet - get() = gradlePlugin.pluginSourceSet - - -private -val Project.gradlePlugin - get() = the() - - -private -fun Project.declareScriptPlugins(scriptPlugins: List) { - - configure { - for (scriptPlugin in scriptPlugins) { - plugins.create(scriptPlugin.id) { - it.id = scriptPlugin.id - it.implementationClass = scriptPlugin.implementationClass - } - } - } -} - - -private -fun Project.generatePluginAdaptersFor(scriptPlugins: List, scriptSourceFiles: FileTree) { - - tasks { - - val generatedSourcesDir = layout.buildDirectory.dir("generated-sources/kotlin-dsl-plugins/kotlin") - - sourceSets["main"].kotlin.srcDir(generatedSourcesDir) - - val generateScriptPluginAdapters by creating { - inputs.files(scriptSourceFiles) - outputs.dir(generatedSourcesDir) - doLast { - val outputDir = generatedSourcesDir.get().asFile - for (scriptPlugin in scriptPlugins) { - scriptPlugin.writeScriptPluginAdapterTo(outputDir) - } - } - } - - getByName("compileKotlin") { - it.dependsOn(generateScriptPluginAdapters) - } - } -} - - -internal -fun ScriptPlugin.writeScriptPluginAdapterTo(outputDir: File) { - - val (packageDir, packageDeclaration) = - packageName?.let { packageName -> - packageDir(outputDir, packageName) to "package $packageName" - } ?: outputDir to "" - - val outputFile = - packageDir.resolve("$simplePluginAdapterClassName.kt") - - outputFile.writeText(""" - - $packageDeclaration - - /** - * Precompiled [$scriptFileName][$compiledScriptTypeName] script plugin. - * - * @see $compiledScriptTypeName - */ - class $simplePluginAdapterClassName : org.gradle.api.Plugin<$targetType> { - override fun apply(target: $targetType) { - try { - Class - .forName("$compiledScriptTypeName") - .getDeclaredConstructor($targetType::class.java) - .newInstance(target) - } catch (e: java.lang.reflect.InvocationTargetException) { - throw e.targetException - } - } - } - - """.replaceIndent().trim() + "\n") -} - - -private -fun packageDir(outputDir: File, packageName: String) = - outputDir.mkdir(packageName.replace('.', '/')) - - -private -fun File.mkdir(relative: String) = - resolve(relative).apply { mkdirs() } - - -private -val Project.sourceSets - get() = project.the().sourceSets - - -private -val SourceSet.kotlin: SourceDirectorySet - get() = withConvention(KotlinSourceSet::class) { kotlin } Index: plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPlugin.kt =================================================================== diff -u -N --- plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPlugin.kt (revision 88d3836b2963bb38448e2c1046f2acf97848454d) +++ plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPlugin.kt (revision 0) @@ -1,173 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.plugins.precompiled - - -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.initialization.Settings -import org.gradle.api.invocation.Gradle - -import org.gradle.kotlin.dsl.support.KotlinScriptType -import org.gradle.kotlin.dsl.support.KotlinScriptTypeMatch - -import org.gradle.util.TextUtil.normaliseLineSeparators - -import org.jetbrains.kotlin.lexer.KotlinLexer -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.NameUtils - -import java.io.File - - -internal -data class ScriptPlugin(private val scriptFile: File) { - - val scriptFileName = scriptFile.name - - /** - * Gradle plugin id inferred from the script file name and package declaration (if any). - */ - val id by lazy { - packagePrefixed(fileNameWithoutScriptExtension) - } - - /** - * Fully qualified name for the [Plugin] implementation class. - * - * The [Plugin] implementation class adapts the precompiled script class - * to the Gradle [Plugin] protocol and it is automatically generated by - * the `generateScriptPluginAdapters` task. - */ - val implementationClass by lazy { - packagePrefixed(simplePluginAdapterClassName) - } - - val simplePluginAdapterClassName by lazy { - fileNameWithoutScriptExtension - .kebabCaseToPascalCase() - .asJavaIdentifier() + "Plugin" - } - - private - val fileNameWithoutScriptExtension by lazy { - scriptFileName.removeSuffix(scriptExtension) - } - - val targetType by lazy { - when (scriptType) { - KotlinScriptType.PROJECT -> Project::class.qualifiedName - KotlinScriptType.SETTINGS -> Settings::class.qualifiedName - KotlinScriptType.INIT -> Gradle::class.qualifiedName - } - } - - private - val scriptType - get() = scriptTypeMatch.scriptType - - private - val scriptExtension - get() = scriptTypeMatch.match.value - - private - val scriptTypeMatch by lazy { - KotlinScriptTypeMatch.forName(scriptFileName)!! - } - - /** - * Fully qualified name - */ - val compiledScriptTypeName by lazy { - packagePrefixed(scriptClassNameForFile(scriptFile)) - } - - val packageName: String? by lazy { - packageNameOf(scriptFile) - } - - private - fun packagePrefixed(id: String) = - packageName?.let { "$it.$id" } ?: id -} - - -private -fun packageNameOf(file: File): String? = - packageNameOf(normaliseLineSeparators(file.readText())) - - -private -fun packageNameOf(code: String): String? = - KotlinLexer().run { - start(code) - skipWhiteSpaceAndComments() - when (tokenType) { - KtTokens.PACKAGE_KEYWORD -> { - advance() - skipWhiteSpaceAndComments() - parseQualifiedName() - } - else -> null - } - } - - -private -fun KotlinLexer.parseQualifiedName(): String = - StringBuilder().run { - while (tokenType == KtTokens.IDENTIFIER || tokenType == KtTokens.DOT) { - append(tokenText) - advance() - } - toString() - } - - -private -fun KotlinLexer.skipWhiteSpaceAndComments() { - while (tokenType in KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET) { - advance() - } -} - - -private -fun scriptClassNameForFile(file: File) = - NameUtils.getScriptNameForFile(file.name).asString() - - -private -fun CharSequence.kebabCaseToPascalCase() = - kebabCaseToCamelCase().capitalize() - - -private -fun CharSequence.kebabCaseToCamelCase() = - replace("-[a-z]".toRegex()) { it.value.drop(1).toUpperCase() } - - -private -fun CharSequence.asJavaIdentifier() = - replaceBy { if (it.isJavaIdentifierPart()) it else '_' } - - -private -inline fun CharSequence.replaceBy(f: (Char) -> Char) = - StringBuilder(length).let { builder -> - forEach { char -> builder.append(f(char)) } - builder.toString() - } Index: plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPluginTest.kt =================================================================== diff -u -N --- plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPluginTest.kt (revision ff6318f459efc329156b1de40637fb3565104de7) +++ plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPluginTest.kt (revision 0) @@ -1,240 +0,0 @@ -package org.gradle.kotlin.dsl.plugins.dsl - -import org.gradle.kotlin.dsl.fixtures.customDaemonRegistry -import org.gradle.kotlin.dsl.fixtures.customInstallation -import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest - -import org.gradle.testkit.runner.TaskOutcome - -import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.CoreMatchers.equalTo - -import org.junit.Assert.assertThat -import org.junit.Test - -import java.io.File - - -class KotlinDslPluginTest : AbstractPluginTest() { - - @Test - fun `gradle kotlin dsl api dependency is added`() { - - withBuildScript(""" - - plugins { - `kotlin-dsl` - } - - """) - - withFile("src/main/kotlin/code.kt", """ - - // src/main/kotlin - import org.gradle.kotlin.dsl.GradleDsl - - // src/generated - import org.gradle.kotlin.dsl.embeddedKotlinVersion - - """) - - val result = buildWithPlugin("classes") - - assertThat(result.outcomeOf(":compileKotlin"), equalTo(TaskOutcome.SUCCESS)) - } - - @Test - fun `gradle kotlin dsl api is available for test implementation`() { - withBuildScript(""" - - plugins { - `java-gradle-plugin` - `kotlin-dsl` - } - - repositories { - jcenter() - } - - dependencies { - testCompile("junit:junit:4.12") - } - - """) - - withFile("src/main/kotlin/code.kt", """ - - import org.gradle.api.Plugin - import org.gradle.api.Project - import org.gradle.kotlin.dsl.embeddedKotlinVersion - - class MyPlugin : Plugin { - override fun apply(project: Project) { - project.run { - println("Plugin Using Embedded Kotlin " + embeddedKotlinVersion) - } - } - } - """) - - withFile("src/test/kotlin/test.kt", """ - - import org.gradle.testfixtures.ProjectBuilder - import org.junit.Test - import org.gradle.kotlin.dsl.* - - class MyTest { - - @Test - fun `my test`() { - ProjectBuilder.builder().build().run { - apply() - } - } - } - """) - - assertThat( - outputOf("test", "-i"), - containsString("Plugin Using Embedded Kotlin ")) - } - - @Test - fun `gradle kotlin dsl api is available in test-kit injected plugin classpath`() { - - withBuildScript(""" - - plugins { - `java-gradle-plugin` - `kotlin-dsl` - } - - repositories { - jcenter() - } - - dependencies { - testCompile("junit:junit:4.12") - testCompile(gradleTestKit()) - } - - gradlePlugin { - (plugins) { - "myPlugin" { - id = "my-plugin" - implementationClass = "my.MyPlugin" - } - } - } - - """) - - withFile("src/main/kotlin/my/code.kt", """ - package my - - import org.gradle.api.* - import org.gradle.kotlin.dsl.* - - class MyPlugin : Plugin { - override fun apply(project: Project) { - println("Plugin Using Embedded Kotlin " + embeddedKotlinVersion) - } - } - """) - - withFile("src/test/kotlin/test.kt", """ - - import java.io.File - - import org.gradle.testkit.runner.GradleRunner - - import org.hamcrest.CoreMatchers.containsString - import org.junit.Assert.assertThat - - import org.junit.Rule - import org.junit.Test - import org.junit.rules.TemporaryFolder - - class MyTest { - - @JvmField @Rule val temporaryFolder = TemporaryFolder() - - val projectRoot by lazy { - File(temporaryFolder.root, "test").apply { mkdirs() } - } - - @Test - fun `my test`() { - // given: - File(projectRoot, "build.gradle.kts") - .writeText("plugins { id(\"my-plugin\") }") - - // and: - System.setProperty("org.gradle.daemon.idletimeout", "1000") - System.setProperty("org.gradle.daemon.registry.base", "${escapedPathOf(customDaemonRegistry())}") - File(projectRoot, "gradle.properties").writeText("org.gradle.jvmargs=-Xmx128m") - - // and: - val runner = GradleRunner.create() - .withGradleInstallation(File("${escapedPathOf(customInstallation())}")) - .withProjectDir(projectRoot) - .withPluginClasspath() - .forwardOutput() - - // when: - val result = runner.withArguments("help").build() - - // then: - assertThat(result.output, containsString("Plugin Using Embedded Kotlin ")) - } - } - - """) - - assertThat( - outputOf("test", "-i"), - containsString("Plugin Using Embedded Kotlin ")) - } - - @Test - fun `sam-with-receiver kotlin compiler plugin is applied to production code`() { - - withBuildScript(""" - - plugins { - `kotlin-dsl` - } - - """) - - withFile("src/main/kotlin/code.kt", """ - - import org.gradle.api.Plugin - import org.gradle.api.Project - - class MyPlugin : Plugin { - override fun apply(project: Project) { - project.run { - copy { - from("build.gradle.kts") - into("build/build.gradle.kts.copy") - } - } - } - } - - """) - - val result = buildWithPlugin("classes") - - assertThat(result.outcomeOf(":compileKotlin"), equalTo(TaskOutcome.SUCCESS)) - } - - private - fun escapedPathOf(file: File) = - file.absolutePath.replace("\\", "\\\\") - - private - fun outputOf(vararg arguments: String) = - buildWithPlugin(*arguments).output -} Index: plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPluginTest.kt =================================================================== diff -u -N --- plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPluginTest.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPluginTest.kt (revision 0) @@ -1,268 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.plugins.embedded - -import org.gradle.kotlin.dsl.embeddedKotlinVersion -import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest - -import org.gradle.testkit.runner.TaskOutcome - -import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.CoreMatchers.equalTo - -import org.junit.Assert.assertThat -import org.junit.Test - - -class EmbeddedKotlinPluginTest : AbstractPluginTest() { - - @Test - fun `applies the kotlin plugin`() { - - withBuildScript(""" - - plugins { - `embedded-kotlin` - } - - """) - - val result = buildWithPlugin("assemble") - - assertThat(result.outcomeOf(":compileKotlin"), equalTo(TaskOutcome.NO_SOURCE)) - } - - @Test - fun `adds stdlib and reflect as compile only dependencies`() { - withBuildScript(""" - - plugins { - `embedded-kotlin` - } - - tasks { - "assertions" { - doLast { - val requiredLibs = listOf("kotlin-stdlib-jdk8-$embeddedKotlinVersion.jar", "kotlin-reflect-$embeddedKotlinVersion.jar") - listOf("compileOnly", "testCompileOnly").forEach { configuration -> - require(configurations[configuration].files.map { it.name }.containsAll(requiredLibs), { - "Embedded Kotlin libraries not found in ${'$'}configuration" - }) - } - } - } - } - - """) - - buildWithPlugin("assertions") - } - - @Test - fun `all embedded kotlin dependencies are resolvable without any added repository`() { - - withBuildScript(""" - - plugins { - `embedded-kotlin` - } - - dependencies { - ${dependencyDeclarationsFor("compile", listOf("compiler-embeddable"))} - } - - println(repositories.map { it.name }) - configurations["compileClasspath"].files.map { println(it) } - - """) - - val result = buildWithPlugin("dependencies") - - assertThat(result.output, containsString("Embedded Kotlin Repository")) - listOf("stdlib", "reflect", "compiler-embeddable").forEach { - assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) - } - } - - @Test - fun `sources and javadoc of all embedded kotlin dependencies are resolvable with an added repository`() { - - withBuildScript(""" - - plugins { - `embedded-kotlin` - } - - repositories { - jcenter() - } - - dependencies { - ${dependencyDeclarationsFor("compile", listOf("stdlib", "reflect"))} - } - - configurations["compileClasspath"].files.forEach { - println(it) - } - - val components = - configurations - .compile - .incoming - .artifactView { lenient(true) } - .artifacts - .map { it.id.componentIdentifier } - - val resolvedComponents = - dependencies - .createArtifactResolutionQuery() - .forComponents(*components.toTypedArray()) - .withArtifacts( - JvmLibrary::class.java, - SourcesArtifact::class.java, - JavadocArtifact::class.java) - .execute() - .resolvedComponents - - inline fun printFileNamesOf() = - resolvedComponents - .flatMap { it.getArtifacts(T::class.java) } - .filterIsInstance() - .forEach { println(it.file.name) } - - printFileNamesOf() - printFileNamesOf() - """) - - val result = buildWithPlugin("help") - - listOf("stdlib", "reflect").forEach { - assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) - assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion-sources.jar")) - assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion-javadoc.jar")) - } - } - - @Test - fun `embedded kotlin modules versions are pinned to the embedded Kotlin version`() { - - withBuildScript(""" - - plugins { - `embedded-kotlin` - } - - repositories { - jcenter() - } - - dependencies { - ${dependencyDeclarationsFor("compile", listOf("stdlib", "reflect", "compiler-embeddable"), "1.1.1")} - compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:0.15") - } - - configurations["compileClasspath"].files.map { println(it) } - - """) - - val result = buildWithPlugin("dependencies") - - listOf("stdlib", "reflect", "compiler-embeddable").forEach { - assertThat(result.output, containsString("org.jetbrains.kotlin:kotlin-$it:1.1.1 -> $embeddedKotlinVersion")) - assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) - } - } - - @Test - fun `can add embedded dependencies to custom configuration`() { - - withBuildScript(""" - - plugins { - `embedded-kotlin` - } - - val customConfiguration by configurations.creating - customConfiguration.extendsFrom(configurations["embeddedKotlin"]) - - configurations["customConfiguration"].files.map { println(it) } - """) - - val result = buildWithPlugin("dependencies", "--configuration", "customConfiguration") - - listOf("stdlib", "reflect").forEach { - assertThat(result.output, containsString("org.jetbrains.kotlin:kotlin-$it:$embeddedKotlinVersion")) - assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) - } - } - - @Test - fun `embedded kotlin dependencies are pinned on custom configurations too`() { - withBuildScript(""" - - plugins { - `embedded-kotlin` - } - - val customConfiguration by configurations.creating - customConfiguration.extendsFrom(configurations["embeddedKotlin"]) - - dependencies { - ${dependencyDeclarationsFor("customConfiguration", listOf("stdlib", "reflect", "compiler-embeddable"), "1.1.1")} - customConfiguration("org.jetbrains.kotlinx:kotlinx-coroutines-core:0.15") - } - - repositories { - jcenter() - } - - configurations["customConfiguration"].files.map { println(it) } - """) - - val result = buildWithPlugin("dependencies", "--configuration", "customConfiguration") - - listOf("stdlib", "reflect", "compiler-embeddable").forEach { - assertThat(result.output, containsString("org.jetbrains.kotlin:kotlin-$it:1.1.1 -> $embeddedKotlinVersion")) - assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) - } - } - - @Test - fun `can be used with GRADLE_METADATA feature preview enabled`() { - - withSettings("""enableFeaturePreview("GRADLE_METADATA")""") - - withBuildScript(""" - - plugins { - `embedded-kotlin` - } - - """) - - withFile("src/main/kotlin/source.kt", """var foo = "bar"""") - - val result = buildWithPlugin("assemble") - - assertThat(result.outcomeOf(":compileKotlin"), equalTo(TaskOutcome.SUCCESS)) - } - - private - fun dependencyDeclarationsFor(configuration: String, modules: List, version: String? = null) = - modules.map { - "$configuration(\"org.jetbrains.kotlin:kotlin-$it:${version ?: embeddedKotlinVersion}\")" - }.joinToString("\n") -} Index: plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPluginTest.kt =================================================================== diff -u -N --- plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPluginTest.kt (revision 1ed716ccc04c0167966c4027c63cf37ed7422581) +++ plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPluginTest.kt (revision 0) @@ -1,374 +0,0 @@ -package org.gradle.kotlin.dsl.plugins.precompiled - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify - -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.initialization.Settings -import org.gradle.api.invocation.Gradle -import org.gradle.api.tasks.TaskContainer - -import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest -import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles -import org.gradle.kotlin.dsl.fixtures.assertFailsWith -import org.gradle.kotlin.dsl.fixtures.assertInstanceOf -import org.gradle.kotlin.dsl.fixtures.classLoaderFor -import org.gradle.kotlin.dsl.fixtures.joinLines -import org.gradle.kotlin.dsl.fixtures.withFolders - -import org.gradle.kotlin.dsl.precompile.PrecompiledInitScript -import org.gradle.kotlin.dsl.precompile.PrecompiledProjectScript -import org.gradle.kotlin.dsl.precompile.PrecompiledSettingsScript - -import org.gradle.testkit.runner.TaskOutcome - -import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.CoreMatchers.equalTo - -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Test - - -class PrecompiledScriptPluginTest : AbstractPluginTest() { - - @Test - fun `Project scripts from regular source-sets are compiled via the PrecompiledProjectScript template`() { - - givenPrecompiledKotlinScript("my-project-script.gradle.kts", """ - - task("my-task") - - """) - - val project = mock() - - assertInstanceOf( - instantiatePrecompiledScriptOf( - project, - "My_project_script_gradle")) - - verify(project).task("my-task") - } - - @Test - fun `Settings scripts from regular source-sets are compiled via the PrecompiledSettingsScript template`() { - - givenPrecompiledKotlinScript("my-settings-script.settings.gradle.kts", """ - - include("my-project") - - """) - - val settings = mock() - - assertInstanceOf( - instantiatePrecompiledScriptOf( - settings, - "My_settings_script_settings_gradle")) - - verify(settings).include("my-project") - } - - @Test - fun `Gradle scripts from regular source-sets are compiled via the PrecompiledInitScript template`() { - - givenPrecompiledKotlinScript("my-gradle-script.init.gradle.kts", """ - - useLogger("my-logger") - - """) - - val gradle = mock() - - assertInstanceOf( - instantiatePrecompiledScriptOf( - gradle, - "My_gradle_script_init_gradle")) - - verify(gradle).useLogger("my-logger") - } - - @Test - fun `plugin adapter doesn't mask exceptions thrown by precompiled script`() { - - // given: - val expectedMessage = "Not on my watch!" - - withPrecompiledScriptPluginsPlus( - "kotlin-dsl", - "java-gradle-plugin") - - withFile("src/main/kotlin/my-project-script.gradle.kts", """ - throw IllegalStateException("$expectedMessage") - """) - - // when: - compileKotlin() - - // then: - @Suppress("unchecked_cast") - val pluginAdapter = - loadCompiledKotlinClass("MyProjectScriptPlugin") - .newInstance() as Plugin - - val exception = - assertFailsWith(IllegalStateException::class) { - pluginAdapter.apply(mock()) - } - - assertThat( - exception.message, - equalTo(expectedMessage)) - } - - @Test - fun `implicit imports are available to precompiled scripts`() { - - givenPrecompiledKotlinScript("my-project-script.gradle.kts", """ - - task("jar") - - """) - - val tasks = mock() - val project = mock() { - on { getTasks() } doReturn tasks - } - - instantiatePrecompiledScriptOf( - project, - "My_project_script_gradle") - - verify(tasks).create("jar", org.gradle.api.tasks.bundling.Jar::class.java) - } - - @Test - fun `precompiled script plugin ids are honored by java-gradle-plugin plugin`() { - - projectRoot.withFolders { - - "buildSrc" { - - "src/main/kotlin" { - - // Plugin id for script with no package declaration is simply - // the file name minus the script file extension. - - // Project plugins must be named `*.gradle.kts` - withFile("my-plugin.gradle.kts", """ - println("my-plugin applied!") - """) - - // Settings plugins must be named `*.settings.gradle.kts` - withFile("my-settings-plugin.settings.gradle.kts", """ - println("my-settings-plugin applied!") - """) - - // Gradle object plugins, a.k.a., precompiled init script plugins, - // must be named `*.init.gradle.kts` - withFile("my-init-plugin.init.gradle.kts", """ - println("my-init-plugin applied!") - """) - - // plugin id for script with package declaration is the - // package name dot the file name minus the `.gradle.kts` suffix - withFile("org/acme/my-other-plugin.gradle.kts", """ - package org.acme - - println("my-other-plugin applied!") - """) - } - - withFile("settings.gradle.kts", """ - - $pluginManagementBlock - - """) - - withFile( - "build.gradle.kts", - scriptWithPrecompiledScriptPluginsPlus( - "kotlin-dsl", - "java-gradle-plugin")) - } - } - - withSettings(""" - - // Apply Gradle plugin via type as it cannot be applied via id - // because `buildSrc` is not in the `gradle` object - // plugin search classpath - - gradle.apply() - - apply(plugin = "my-settings-plugin") - """) - - withBuildScript(""" - plugins { - id("my-plugin") - id("org.acme.my-other-plugin") - } - """) - - assertThat( - build("help").output, - allOf( - containsString("my-init-plugin applied!"), - containsString("my-settings-plugin applied!"), - containsString("my-plugin applied!"), - containsString("my-other-plugin applied!") - ) - ) - } - - @LeaksFileHandles - @Test - fun `precompiled script plugins can be published by maven-publish plugin`() { - - projectRoot.withFolders { - - "plugins" { - - "src/main/kotlin" { - - withFile("my-plugin.gradle.kts", """ - println("my-plugin applied!") - """) - - withFile("org/acme/my-other-plugin.gradle.kts", """ - package org.acme - - println("org.acme.my-other-plugin applied!") - """) - - withFile("org/acme/plugins/my-init.init.gradle.kts", """ - - package org.acme.plugins - - println("org.acme.plugins.my-init applied!") - """) - } - - withFile("settings.gradle.kts", """ - - $pluginManagementBlock - - """) - - withFile( "build.gradle.kts", """ - - plugins { - `kotlin-dsl` - `java-gradle-plugin` - `maven-publish` - } - - group = "org.acme" - - version = "0.1.0" - - $applyPrecompiledScriptPlugins - - publishing { - repositories { - maven(url = "../repository") - } - } - """) - } - } - - build(existing("plugins"), "publish") - - val repositoriesBlock = """ - repositories { - maven { url = uri("./repository") } - } - """ - - withSettings(""" - pluginManagement { - $repositoriesBlock - } - """) - - withBuildScript(""" - plugins { - id("my-plugin") version "0.1.0" - id("org.acme.my-other-plugin") version "0.1.0" - } - """) - - val initScript = - withFile("my-init-script.init.gradle.kts", """ - - initscript { - $repositoriesBlock - dependencies { - classpath("org.acme:plugins:0.1.0") - } - } - - apply() - - // TODO: can't apply plugin by id - // apply(plugin = "org.acme.plugins.my-init") - """) - - assertThat( - build("help", "-I", initScript.canonicalPath).output, - allOf( - containsString("org.acme.plugins.my-init applied!"), - containsString("my-plugin applied!"), - containsString("org.acme.my-other-plugin applied!") - ) - ) - } - - private - fun givenPrecompiledKotlinScript(fileName: String, code: String) { - withPrecompiledScriptPluginsPlus("kotlin-dsl") - withFile("src/main/kotlin/$fileName", code) - compileKotlin() - } - - private - inline fun instantiatePrecompiledScriptOf(target: T, className: String): Any = - loadCompiledKotlinClass(className) - .getConstructor(T::class.java) - .newInstance(target) - - private - fun loadCompiledKotlinClass(className: String) = - classLoaderFor(existing("build/classes/kotlin/main")) - .loadClass(className) - - private - fun withPrecompiledScriptPluginsPlus(vararg additionalPlugins: String) = - withBuildScript(scriptWithPrecompiledScriptPluginsPlus(*additionalPlugins)) - - private - fun scriptWithPrecompiledScriptPluginsPlus(vararg additionalPlugins: String): String = - """ - plugins { - ${additionalPlugins.asIterable().joinLines { "`$it`" }} - } - - $applyPrecompiledScriptPlugins - """ - - private - val applyPrecompiledScriptPlugins - get() = "apply<${PrecompiledScriptPlugins::class.qualifiedName}>()" - - private - fun compileKotlin() { - assertThat( - buildWithPlugin("classes").outcomeOf(":compileKotlin"), - equalTo(TaskOutcome.SUCCESS)) - } -} Index: plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPluginTest.kt =================================================================== diff -u -N --- plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPluginTest.kt (revision 88d3836b2963bb38448e2c1046f2acf97848454d) +++ plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPluginTest.kt (revision 0) @@ -1,120 +0,0 @@ -package org.gradle.kotlin.dsl.plugins.precompiled - -import org.gradle.kotlin.dsl.fixtures.TestWithTempFiles - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.startsWith -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - -import java.io.File - - -class ScriptPluginTest : TestWithTempFiles() { - - @Test - fun `plugin id is derived from script file name`() { - - val script = - newFile("my-script.gradle.kts") - - assertThat( - ScriptPlugin(script).id, - equalTo("my-script")) - } - - @Test - fun `plugin id is prefixed by package name if present`() { - - val script = - newFile("my-script.gradle.kts", """ - - package org.acme - - """) - - assertThat( - ScriptPlugin(script).id, - equalTo("org.acme.my-script")) - } - - @Test - fun `implementationClass is a valid Java identifier`() { - - val script = - newFile("my-script.with invalid characters.gradle.kts") - - assertThat( - ScriptPlugin(script).implementationClass, - equalTo("MyScript_with_invalid_charactersPlugin")) - } - - @Test - fun `plugin adapter is written to package sub-dir and starts with correct package declaration`() { - - val script = - newFile("my-script.gradle.kts", """ - - package org.acme - - """) - - val outputDir = - root.resolve("output") - - ScriptPlugin(script) - .writeScriptPluginAdapterTo(outputDir) - - val expectedFile = - outputDir.resolve("org/acme/MyScriptPlugin.kt") - - assertThat( - firstNonBlankLineOf(expectedFile), - equalTo("package org.acme")) - } - - @Test - fun `given no package declaration, plugin adapter is written directly to output dir`() { - - val script = - newFile("my-script.gradle.kts") - - val outputDir = - root.resolve("output").apply { mkdir() } - - ScriptPlugin(script) - .writeScriptPluginAdapterTo(outputDir) - - val expectedFile = - outputDir.resolve("MyScriptPlugin.kt") - - assertThat( - expectedFile.readText(), - startsWith(""" - /** - * Precompiled [my-script.gradle.kts][My_script_gradle] script plugin. - * - * @see My_script_gradle - */ - class MyScriptPlugin - """.trimIndent())) - } - - @Test - fun `can extract package name from script with Windows line endings`() { - - val script = - newFile("my-script.gradle.kts", "/*\r\n */\r\npackage org.acme\r\n") - - assertThat( - ScriptPlugin(script).packageName, - equalTo("org.acme")) - } - - private - fun firstNonBlankLineOf(expectedFile: File) = - expectedFile.bufferedReader().useLines { - it.first { it.isNotBlank() } - } -} Index: provider-plugins/.gitignore =================================================================== diff -u -N --- provider-plugins/.gitignore (revision f1b2c1bc5f81e2aed878fd02739935f0c5da8a99) +++ provider-plugins/.gitignore (revision 0) @@ -1,2 +0,0 @@ -/build -/out Index: provider-plugins/build.gradle.kts =================================================================== diff -u -N --- provider-plugins/build.gradle.kts (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider-plugins/build.gradle.kts (revision 0) @@ -1,15 +0,0 @@ -import build.* - -plugins { - id("public-kotlin-dsl-module") -} - -base { - archivesBaseName = "gradle-kotlin-dsl-provider-plugins" -} - -dependencies { - compileOnly(gradleApi()) - - compile(project(":provider")) -} Index: provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultKotlinScriptBasePluginsApplicator.kt =================================================================== diff -u -N --- provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultKotlinScriptBasePluginsApplicator.kt (revision f40d46afc43f067c03373c67ed4e060319edf2c5) +++ provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultKotlinScriptBasePluginsApplicator.kt (revision 0) @@ -1,46 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider.plugins - -import org.gradle.api.Plugin -import org.gradle.api.Project - -import org.gradle.kotlin.dsl.accessors.tasks.PrintAccessors -import org.gradle.kotlin.dsl.accessors.tasks.UpdateProjectSchema -import org.gradle.kotlin.dsl.provider.KotlinScriptBasePluginsApplicator - - -class DefaultKotlinScriptBasePluginsApplicator : KotlinScriptBasePluginsApplicator { - override fun apply(project: Project) { - project.plugins.apply(KotlinScriptBasePlugin::class.java) - } -} - - -class KotlinScriptBasePlugin : Plugin { - override fun apply(project: Project): Unit = project.run { - rootProject.plugins.apply(KotlinScriptRootPlugin::class.java) - tasks.createLater("kotlinDslAccessorsReport", PrintAccessors::class.java) - } -} - - -class KotlinScriptRootPlugin : Plugin { - override fun apply(project: Project): Unit = project.run { - tasks.createLater("kotlinDslAccessorsSnapshot", UpdateProjectSchema::class.java) - } -} Index: provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultProjectSchemaProvider.kt =================================================================== diff -u -N --- provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultProjectSchemaProvider.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultProjectSchemaProvider.kt (revision 0) @@ -1,134 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider.plugins - -import org.gradle.api.Project -import org.gradle.api.plugins.ExtensionAware -import org.gradle.api.plugins.ExtensionsSchema -import org.gradle.api.plugins.JavaPluginConvention -import org.gradle.api.reflect.HasPublicType -import org.gradle.api.reflect.TypeOf -import org.gradle.api.tasks.SourceSet - -import org.gradle.kotlin.dsl.accessors.ProjectSchema -import org.gradle.kotlin.dsl.accessors.ProjectSchemaEntry -import org.gradle.kotlin.dsl.accessors.ProjectSchemaProvider - - -class DefaultProjectSchemaProvider : ProjectSchemaProvider { - - override fun schemaFor(project: Project): ProjectSchema> = - targetSchemaFor(project, typeOfProject).let { targetSchema -> - ProjectSchema( - targetSchema.extensions, - targetSchema.conventions, - accessibleConfigurationsOf(project)) - } -} - - -private -data class ExtensionConventionSchema( - val extensions: List>>, - val conventions: List>> -) - - -private -fun targetSchemaFor(target: Any, targetType: TypeOf<*>): ExtensionConventionSchema { - - val extensions = mutableListOf>>() - val conventions = mutableListOf>>() - - fun collectSchemaOf(target: Any, targetType: TypeOf<*>) { - if (target is ExtensionAware) { - accessibleExtensionsSchema(target.extensions.extensionsSchema).forEach { schema -> - extensions.add(ProjectSchemaEntry(targetType, schema.name, schema.publicType)) - if (!schema.isDeferredConfigurable) { - collectSchemaOf(target.extensions.getByName(schema.name), schema.publicType) - } - } - } - if (target is Project) { - accessibleConventionsSchema(target.convention.plugins).forEach { name, type -> - conventions.add(ProjectSchemaEntry(targetType, name, type)) - collectSchemaOf(target.convention.plugins[name]!!, type) - } - sourceSetsOf(target)?.forEach { sourceSet -> - collectSchemaOf(sourceSet, typeOfSourceSet) - } - } - } - - collectSchemaOf(target, targetType) - - return ExtensionConventionSchema(extensions.distinct(), conventions.distinct()) -} - - -private -fun accessibleExtensionsSchema(extensionsSchema: ExtensionsSchema) = - extensionsSchema.filter { isPublic(it.name) } - - -private -fun accessibleConventionsSchema(plugins: Map) = - plugins.filterKeys(::isPublic).mapValues { inferPublicTypeOfConvention(it.value) } - - -private -fun sourceSetsOf(project: Project) = - project.convention.findPlugin(JavaPluginConvention::class.java)?.sourceSets - - -private -fun inferPublicTypeOfConvention(instance: Any) = - if (instance is HasPublicType) instance.publicType - else TypeOf.typeOf(instance::class.java.firstNonSyntheticOrSelf) - - -private -val Class<*>.firstNonSyntheticOrSelf - get() = firstNonSyntheticOrNull ?: this - - -private -val Class<*>.firstNonSyntheticOrNull: Class<*>? - get() = takeIf { !isSynthetic } ?: superclass?.firstNonSyntheticOrNull - - -private -fun accessibleConfigurationsOf(project: Project) = - project.configurations.names.filter(::isPublic) - - -private -fun isPublic(name: String): Boolean = - !name.startsWith("_") - - -private -val typeOfProject = typeOf() - - -private -val typeOfSourceSet = typeOf() - - -internal -inline fun typeOf(): TypeOf = - object : TypeOf() {} Index: provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/KotlinDslProviderPluginsServiceRegistry.kt =================================================================== diff -u -N --- provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/KotlinDslProviderPluginsServiceRegistry.kt (revision fe18753a10a75fb9586db64fb57d41cca0acff94) +++ provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/KotlinDslProviderPluginsServiceRegistry.kt (revision 0) @@ -1,41 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider.plugins - -import org.gradle.internal.service.ServiceRegistration -import org.gradle.internal.service.scopes.AbstractPluginServiceRegistry - - -class KotlinDslProviderPluginsServiceRegistry : AbstractPluginServiceRegistry() { - - override fun registerGradleUserHomeServices(registration: ServiceRegistration) { - registration.addProvider(GradleUserHomeServices) - } -} - - -internal -object GradleUserHomeServices { - - @Suppress("unused") - fun createProjectSchemaProvider() = - DefaultProjectSchemaProvider() - - @Suppress("unused") - fun createKotlinScriptBasePluginsApplicator() = - DefaultKotlinScriptBasePluginsApplicator() -} Index: provider-plugins/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry =================================================================== diff -u -N --- provider-plugins/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry (revision bee240769cd007abbb2dca204f8d02a3e84298f2) +++ provider-plugins/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry (revision 0) @@ -1 +0,0 @@ -org.gradle.kotlin.dsl.provider.plugins.KotlinDslProviderPluginsServiceRegistry Index: provider/.gitignore =================================================================== diff -u -N --- provider/.gitignore (revision b7fe7e4d695235451d46ac64c2a40c7914337757) +++ provider/.gitignore (revision 0) @@ -1,3 +0,0 @@ -/src/generated -/build -/out Index: provider/build.gradle.kts =================================================================== diff -u -N --- provider/build.gradle.kts (revision 28ca5ad75e2926f289db23178ce8a629fab460cb) +++ provider/build.gradle.kts (revision 0) @@ -1,80 +0,0 @@ -import build.* - -import codegen.GenerateKotlinDependencyExtensions - -plugins { - id("public-kotlin-dsl-module") -} - -base { - archivesBaseName = "gradle-kotlin-dsl" -} - -dependencies { - compileOnly(gradleApi()) - - compile(project(":tooling-models")) - compile(futureKotlin("stdlib-jdk8")) - compile(futureKotlin("reflect")) - compile(futureKotlin("compiler-embeddable")) - compile(futureKotlin("sam-with-receiver-compiler-plugin")) { - isTransitive = false - } - - testCompile(project(":test-fixtures")) - testCompile("com.squareup.okhttp3:mockwebserver:3.9.1") -} - - -// --- Enable automatic generation of API extensions ------------------- -val apiExtensionsOutputDir = file("src/generated/kotlin") - -java.sourceSets["main"].kotlin { - srcDir(apiExtensionsOutputDir) -} - -val publishedPluginsVersion: String by rootProject.extra - -val generateKotlinDependencyExtensions by task { - outputFile = File(apiExtensionsOutputDir, "org/gradle/kotlin/dsl/KotlinDependencyExtensions.kt") - embeddedKotlinVersion = kotlinVersion - kotlinDslPluginsVersion = publishedPluginsVersion -} - -val generateExtensions by tasks.creating { - dependsOn(generateKotlinDependencyExtensions) -} - -val compileKotlin by tasks -compileKotlin.dependsOn(generateExtensions) - -val clean: Delete by tasks -clean.delete(apiExtensionsOutputDir) - - -// -- Version manifest properties -------------------------------------- -val versionsManifestOutputDir = file("$buildDir/versionsManifest") -val writeVersionsManifest by tasks.creating(WriteProperties::class) { - outputFile = versionsManifestOutputDir.resolve("gradle-kotlin-dsl-versions.properties") - property("provider", version) - property("kotlin", kotlinVersion) -} -val processResources by tasks.getting(ProcessResources::class) { - from(writeVersionsManifest) -} - -// -- Testing ---------------------------------------------------------- -val prepareIntegrationTestFixtures by rootProject.tasks -val customInstallation by rootProject.tasks -tasks { - "test" { - dependsOn(prepareIntegrationTestFixtures) - dependsOn(customInstallation) - } -} - -withParallelTests() - -// --- Utility functions ----------------------------------------------- -inline fun task(noinline configuration: T.() -> Unit) = tasks.creating(T::class, configuration) - Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ActionExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ActionExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ActionExtensions.kt (revision 0) @@ -1,25 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.Action - - -/** - * Enables function invocation syntax on [Action] references. - */ -inline operator fun Action.invoke(target: T) = execute(target) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensions.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensions.kt (revision 0) @@ -1,39 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.file.ConfigurableFileCollection - -import kotlin.reflect.KProperty - - -/** - * Property delegate for [ConfigurableFileCollection] instances. - * - * Example: `val aFileCollection by project.files()` - */ -operator fun ConfigurableFileCollection.getValue(receiver: Any?, property: KProperty<*>): ConfigurableFileCollection = - this - - -/** - * Property delegate for [ConfigurableFileCollection] instances. - * - * Example: `var aFileCollection by project.files()` - */ -operator fun ConfigurableFileCollection.setValue(receiver: Any?, property: KProperty<*>, value: Iterable<*>) = - setFrom(value) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensions.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensions.kt (revision 0) @@ -1,34 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.ModuleDependency - -import org.gradle.kotlin.dsl.support.excludeMapFor - - -/** - * Adds an exclude rule to exclude transitive dependencies for all dependencies of this configuration. - * You can also add exclude rules per-dependency. See [ModuleDependency.exclude]. - * - * @param group the optional group identifying the dependencies to be excluded. - * @param module the optional module name identifying the dependencies to be excluded. - * @return this - */ -fun Configuration.exclude(group: String? = null, module: String? = null): Configuration = - exclude(excludeMapFor(group, module)) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensions.kt (revision 0) @@ -1,113 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.file.ContentFilterable - -import java.io.FilterReader -import kotlin.reflect.KClass - - -/** - * Adds a content filter to be used during the copy. - * Multiple calls add additional filters to the filter chain. - * Each filter should implement [FilterReader]. - * Import `org.apache.tools.ant.filters.*` for access to all the standard Ant filters. - * - * Examples: - * - * ``` - * filter() - * filter() - * filter("lines" to 25, "skip" to 2) - * filter("tokens" to mapOf("copyright" to "2009", "version" to "2.3.1")) - * ``` - * - * @param T type of the filter to add - * @param properties map of filter properties - * @return this - */ -inline fun ContentFilterable.filter(vararg properties: Pair) = - if (properties.isEmpty()) filter(T::class.java) - else filter(mapOf(*properties), T::class.java) - - -/** - * Adds a content filter to be used during the copy. - * Multiple calls add additional filters to the filter chain. - * Each filter should implement [FilterReader]. - * Import `org.apache.tools.ant.filters.*` for access to all the standard Ant filters. - * - * Examples: - * - * ``` - * filter(mapOf("lines" to 25, "skip" to 2)) - * filter(mapOf("tokens" to mapOf("copyright" to "2009", "version" to "2.3.1"))) - * ``` - * - * @param T type of the filter to add - * @param properties map of filter properties - * @return this - */ -inline fun ContentFilterable.filter(properties: Map) = - if (properties.isEmpty()) filter(T::class.java) - else filter(properties, T::class.java) - - -/** - * Adds a content filter to be used during the copy. - * Multiple calls add additional filters to the filter chain. - * Each filter should implement [FilterReader]. - * Import `org.apache.tools.ant.filters.*` for access to all the standard Ant filters. - * - * Examples: - * - * ``` - * filter(StripJavaComments::class) - * filter(com.mycompany.project.CustomFilter::class) - * filter(HeadFilter::class, "lines" to 25, "skip" to 2) - * filter(ReplaceTokens::class, "tokens" to mapOf("copyright" to "2009", "version" to "2.3.1")) - * ``` - * - * @param filterType type of the filter to add - * @param properties map of filter properties - * @return this - */ -fun ContentFilterable.filter(filterType: KClass, vararg properties: Pair) = - if (properties.isEmpty()) filter(filterType.java) - else filter(mapOf(*properties), filterType.java) - - -/** - * Adds a content filter to be used during the copy. - * Multiple calls add additional filters to the filter chain. - * Each filter should implement [FilterReader]. - * Import `org.apache.tools.ant.filters.*` for access to all the standard Ant filters. - * - * Examples: - * - * ``` - * filter(HeadFilter::class, mapOf("lines" to 25, "skip" to 2)) - * filter(ReplaceTokens::class, mapOf("tokens" to mapOf("copyright" to "2009", "version" to "2.3.1"))) - * ``` - * - * @param filterType type of the filter to add - * @param properties map of filter properties - * @return this - */ -fun ContentFilterable.filter(filterType: KClass, properties: Map) = - if (properties.isEmpty()) filter(filterType.java) - else filter(properties, filterType.java) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ConventionExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ConventionExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ConventionExtensions.kt (revision 0) @@ -1,72 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.internal.HasConvention -import org.gradle.api.plugins.Convention -import kotlin.reflect.KClass - - -/** - * Looks for the convention plugin of a given name and casts it to the expected type [T]. - * - * If no convention is found or if the one found cannot be cast to the expected type it will throw an [IllegalStateException]. - * - * @param name convention plugin name - * @return the convention plugin, never null - * @throws [IllegalStateException] When the convention cannot be found or cast to the expected type. - */ -inline fun Convention.getPluginByName(name: String): T = - plugins[name]?.let { - (it as T?) ?: throw IllegalStateException("Convention '$name' of type '${it::class.java.name}' cannot be cast to '${T::class.java.name}'.") - } ?: throw IllegalStateException("A convention named '$name' could not be found.") - - -inline fun Convention.getPlugin() = - getPlugin(T::class) - - -fun Convention.getPlugin(conventionType: KClass): T = - getPlugin(conventionType.java) - - -inline fun Convention.findPlugin() = - findPlugin(T::class) - - -fun Convention.findPlugin(conventionType: KClass): T? = - findPlugin(conventionType.java) - - -/** - * Evaluates the given [function] against the convention plugin of the given [conventionType]. - * - * @param conventionType the type of the convention to be located. - * @param function function to be evaluated. - * @return the value returned by the given [function]. - * @throws [IllegalStateException] When the receiver does not support convention plugins, when there is no convention plugin of the given type, or when there are multiple such plugins. - * - * @see [Convention.getPlugin] - */ -inline fun Any.withConvention( - conventionType: KClass, - function: ConventionType.() -> ReturnType -): ReturnType = - when (this) { - is HasConvention -> convention.getPlugin(conventionType).run(function) - else -> throw IllegalStateException("Object `$this` doesn't support conventions!") - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/CopySpecExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/CopySpecExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/CopySpecExtensions.kt (revision 0) @@ -1,30 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.file.CopySpec - -import java.io.FilterReader - - -// Interim extensions until those methods are added to CopySpec -inline fun CopySpec.filter(vararg properties: Pair) = - filter(mapOf(*properties), T::class.java) - - -inline fun CopySpec.filter(properties: Map) = - filter(properties, T::class.java) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensions.kt (revision 0) @@ -1,283 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.artifacts.ClientModule -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.ExternalModuleDependency -import org.gradle.api.artifacts.ModuleDependency -import org.gradle.api.artifacts.ProjectDependency -import org.gradle.api.artifacts.ResolutionStrategy -import org.gradle.api.artifacts.dsl.DependencyHandler - -import org.gradle.internal.Cast.uncheckedCast - -import org.gradle.kotlin.dsl.support.excludeMapFor -import org.gradle.kotlin.dsl.support.mapOfNonNullValuesOf - - -/** - * Creates a dependency on a module without adding it to a configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * - * @return The dependency. - * - * @see [DependencyHandler.create] - */ -fun DependencyHandler.create( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null -): ExternalModuleDependency = - - create( - mapOfNonNullValuesOf( - "group" to group, - "name" to name, - "version" to version, - "configuration" to configuration, - "classifier" to classifier, - "ext" to ext)) as ExternalModuleDependency - - -/** - * Creates a dependency on a client module without adding it to a configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * - * @return The dependency. - * - * @see [DependencyHandler.create] - */ -fun DependencyHandler.module( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null -): ClientModule = - - module( - mapOfNonNullValuesOf( - "group" to group, - "name" to name, - "version" to version, - "configuration" to configuration, - "classifier" to classifier, - "ext" to ext)) as ClientModule - - -/** - * Creates a dependency on a client module without adding it to a configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * @param clientModuleConfiguration The expression to use to configure the dependency. - * @return The dependency. - * - * @see [DependencyHandler.create] - */ -fun DependencyHandler.module( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null, - clientModuleConfiguration: ClientModuleScope.() -> Unit -): ClientModule = - - configureClientModule( - module( - mapOfNonNullValuesOf( - "group" to group, - "name" to name, - "version" to version, - "configuration" to configuration, - "classifier" to classifier, - "ext" to ext)) as ClientModule, - clientModuleConfiguration) - - -/** - * Creates a dependency on a client module without adding it to a configuration. - * - * @param notation The module notation, in one of the notations described at [DependencyHandler]. - * @param clientModuleConfiguration The expression to use to configure the dependency. - * @return The dependency. - */ -fun DependencyHandler.module( - notation: Any, - clientModuleConfiguration: ClientModuleScope.() -> Unit -): ClientModule = - - configureClientModule(module(notation) as ClientModule, clientModuleConfiguration) - - -private -inline fun DependencyHandler.configureClientModule( - module: ClientModule, - clientModuleConfiguration: ClientModuleScope.() -> Unit -): ClientModule = - module.apply { - ClientModuleScope(this@configureClientModule, this@apply).clientModuleConfiguration() - } - - -/** - * Receiver for [ClientModule] configuration blocks. - */ -class ClientModuleScope( - private val dependencyHandler: DependencyHandler, - val clientModule: ClientModule -) : ClientModule by clientModule { - - fun module( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null, - setup: ClientModuleScope.() -> Unit - ) { - - clientModule.addDependency( - dependencyHandler.module(group, name, version, configuration, classifier, ext, setup)) - } - - fun dependency(notation: Any) { - clientModule.addDependency( - dependencyHandler.create(notation) as ModuleDependency) - } - - fun dependency(notation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit) { - clientModule.addDependency( - create(notation, dependencyConfiguration)) - } - - fun dependencies(vararg notations: Any) { - notations.forEach { - clientModule.addDependency( - dependencyHandler.create(it) as ModuleDependency) - } - } - - private - fun create(notation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit) = - (dependencyHandler.create(notation) as ExternalModuleDependency).apply(dependencyConfiguration) -} - - -/** - * Creates a dependency on a project without adding it to a configuration. - * - * @param path the path of the project to be added as a dependency. - * @param configuration the optional configuration of the project to be added as a dependency. - * @return The dependency. - */ -fun DependencyHandler.project( - path: String, - configuration: String? = null -): ProjectDependency = - - uncheckedCast( - project( - if (configuration != null) mapOf("path" to path, "configuration" to configuration) - else mapOf("path" to path))) - - -/** - * Adds a dependency to the given configuration, and configures the dependency using the given expression. - * - * @param configuration The name of the configuration. - * @param dependencyNotation The dependency notation. - * @param dependencyConfiguration The expression to use to configure the dependency. - * @return The dependency. - */ -inline fun DependencyHandler.add( - configuration: String, - dependencyNotation: String, - dependencyConfiguration: ExternalModuleDependency.() -> Unit -): ExternalModuleDependency = - - add(configuration, create(dependencyNotation) as ExternalModuleDependency, dependencyConfiguration) - - -/** - * Adds a dependency to the given configuration, and configures the dependency using the given expression. - * - * @param configuration The name of the configuration. - * @param dependency The dependency. - * @param dependencyConfiguration The expression to use to configure the dependency. - * @return The dependency. - */ -inline fun DependencyHandler.add( - configuration: String, - dependency: T, - dependencyConfiguration: T.() -> Unit -): T = - - dependency.apply { - dependencyConfiguration() - add(configuration, this) - } - - -/** - * Adds an exclude rule to exclude transitive dependencies of this dependency. - * - * Excluding a particular transitive dependency does not guarantee that it does not show up - * in the dependencies of a given configuration. - * For example, some other dependency, which does not have any exclude rules, - * might pull in exactly the same transitive dependency. - * To guarantee that the transitive dependency is excluded from the entire configuration - * please use per-configuration exclude rules: [Configuration.getExcludeRules]. - * In fact, in majority of cases the actual intention of configuring per-dependency exclusions - * is really excluding a dependency from the entire configuration (or classpath). - * - * If your intention is to exclude a particular transitive dependency - * because you don't like the version it pulls in to the configuration - * then consider using the forced versions feature: [ResolutionStrategy.force]. - * - * @param group the optional group identifying the dependencies to be excluded. - * @param module the optional module name identifying the dependencies to be excluded. - * @return this - * - * @see [ModuleDependency.exclude] - */ -fun T.exclude(group: String? = null, module: String? = null): T = - uncheckedCast(exclude(excludeMapFor(group, module))) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerScope.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerScope.kt (revision 823cb09ed220778532237269d3d863b0b01a81c3) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerScope.kt (revision 0) @@ -1,199 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.ExternalModuleDependency -import org.gradle.api.artifacts.ModuleDependency -import org.gradle.api.artifacts.dsl.DependencyHandler - - -/** - * Receiver for `dependencies` block providing convenient utilities for configuring dependencies. - * - * @see [DependencyHandler] - */ -class DependencyHandlerScope(val dependencies: DependencyHandler) : DependencyHandler by dependencies { - - /** - * Adds a dependency to the given configuration. - * - * @param dependencyNotation notation for the dependency to be added. - * @return The dependency. - * @see [DependencyHandler.add] - */ - operator fun String.invoke(dependencyNotation: Any): Dependency? = - dependencies.add(this, dependencyNotation) - - /** - * Adds a dependency to the given configuration. - * - * @param dependencyNotation notation for the dependency to be added. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * @see [DependencyHandler.add] - */ - inline operator fun String.invoke(dependencyNotation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency = - dependencies.add(this, dependencyNotation, dependencyConfiguration) - - /** - * Adds a dependency to the given configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * @return The dependency. - * - * @see [DependencyHandler.add] - */ - operator fun String.invoke( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null - ): ExternalModuleDependency = - dependencies.create(group, name, version, configuration, classifier, ext).apply { add(this@invoke, this) } - - /** - * Adds a dependency to the given configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * - * @see [DependencyHandler.create] - * @see [DependencyHandler.add] - */ - inline operator fun String.invoke( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null, - dependencyConfiguration: ExternalModuleDependency.() -> Unit - ): ExternalModuleDependency = - dependencies.add(this, create(group, name, version, configuration, classifier, ext), dependencyConfiguration) - - /** - * Adds a dependency to the given configuration. - * - * @param dependency dependency to be added. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * - * @see [DependencyHandler.add] - */ - inline operator fun String.invoke(dependency: T, dependencyConfiguration: T.() -> Unit): T = - dependencies.add(this, dependency, dependencyConfiguration) - - /** - * Adds a dependency to the given configuration. - * - * @param dependencyNotation notation for the dependency to be added. - * @return The dependency. - * @see [DependencyHandler.add] - */ - operator fun Configuration.invoke(dependencyNotation: Any): Dependency? = - add(name, dependencyNotation) - - /** - * Adds a dependency to the given configuration. - * - * @param dependencyNotation notation for the dependency to be added. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * @see [DependencyHandler.add] - */ - inline operator fun Configuration.invoke(dependencyNotation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency = - add(name, dependencyNotation, dependencyConfiguration) - - /** - * Adds a dependency to the given configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * @return The dependency. - * - * @see [DependencyHandler.add] - */ - operator fun Configuration.invoke( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null - ): ExternalModuleDependency = - create(group, name, version, configuration, classifier, ext).apply { add(this@invoke.name, this) } - - /** - * Adds a dependency to the given configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * - * @see [DependencyHandler.create] - * @see [DependencyHandler.add] - */ - inline operator fun Configuration.invoke( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null, - dependencyConfiguration: ExternalModuleDependency.() -> Unit - ): ExternalModuleDependency = - add(this.name, create(group, name, version, configuration, classifier, ext), dependencyConfiguration) - - /** - * Adds a dependency to the given configuration. - * - * @param dependency dependency to be added. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * - * @see [DependencyHandler.add] - */ - inline operator fun Configuration.invoke(dependency: T, dependencyConfiguration: T.() -> Unit): T = - add(name, dependency, dependencyConfiguration) - - inline operator fun invoke(configuration: DependencyHandlerScope.() -> Unit) = - configuration() -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/DomainObjectCollectionExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/DomainObjectCollectionExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/DomainObjectCollectionExtensions.kt (revision 0) @@ -1,47 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.DomainObjectCollection - - -/** - * Returns a collection containing the objects in this collection of the given type. Equivalent to calling - * {@code withType(type).all(configureAction)} - * - * @param S The type of objects to find. - * @param configuration The action to execute for each object in the resulting collection. - * @return The matching objects. Returns an empty collection if there are no such objects - * in this collection. - * @see [DomainObjectCollection.withType] - */ -inline fun DomainObjectCollection.withType(crossinline configuration: S.() -> Unit) = - withType(S::class.java, { it.configuration() }) - - -/** - * Returns a collection containing the objects in this collection of the given type. The - * returned collection is live, so that when matching objects are later added to this - * collection, they are also visible in the filtered collection. - * - * @param S The type of objects to find. - * @return The matching objects. Returns an empty collection if there are no such objects - * in this collection. - * @see [DomainObjectCollection.withType] - */ -inline fun DomainObjectCollection.withType() = - withType(S::class.java) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensions.kt (revision 0) @@ -1,49 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.plugins.ExtensionAware -import kotlin.reflect.KClass - - -/** - * Returns the extension of the specified type. - * - * @param T the extension type. - */ -inline fun ExtensionAware.the(): T = - extensions.getByType(typeOf()) - - -/** - * Returns the extension of the specified [extensionType]. - * - * @param T the extension type. - * @param extensionType the reified extension type. - */ -fun ExtensionAware.the(extensionType: KClass): T = - extensions.getByType(extensionType.java) - - -/** - * Executes the given configuration block against the [extension][ExtensionAware] of the specified type. - * - * @param T the extension type. - * @param configuration the configuration block. - * @see [ExtensionAware] - */ -inline fun ExtensionAware.configure(noinline configuration: T.() -> Unit): Unit = - extensions.configure(typeOf(), configuration) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionContainerExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionContainerExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionContainerExtensions.kt (revision 0) @@ -1,59 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.UnknownDomainObjectException -import org.gradle.api.plugins.ExtensionContainer - -import kotlin.reflect.KProperty - - -/** - * Looks for the extension of a given name. If none found it will throw an exception. - * - * @param name extension name - * @return extension - * @throws [UnknownDomainObjectException] When the given extension is not found. - * - * @see [ExtensionContainer.getByName] - */ -operator fun ExtensionContainer.get(name: String): Any = - getByName(name) - - -/** - * Looks for the extension of a given name and casts it to the expected type [T]. - * - * If none found it will throw an [UnknownDomainObjectException]. - * If the extension is found but cannot be cast to the expected type it will throw an [IllegalStateException]. - * - * @param name extension name - * @return extension, never null - * @throws [UnknownDomainObjectException] When the given extension is not found. - * @throws [IllegalStateException] When the given extension cannot be cast to the expected type. - */ -@Suppress("extension_shadowed_by_member") -inline fun ExtensionContainer.getByName(name: String) = - getByName(name).let { - it as? T - ?: throw IllegalStateException( - "Element '$name' of type '${it::class.java.name}' from container '$this' cannot be cast to '${T::class.qualifiedName}'.") - } - - -inline operator fun ExtensionContainer.getValue(thisRef: Any?, property: KProperty<*>): T = - getByName(property.name) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensions.kt (revision 0) @@ -1,118 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.InvalidUserCodeException -import org.gradle.api.plugins.ExtensionAware -import org.gradle.api.plugins.ExtensionContainer -import org.gradle.api.plugins.ExtraPropertiesExtension - -import org.gradle.internal.Cast.uncheckedCast - -import kotlin.reflect.KProperty - - -/** - * The extra properties extension in this object's extension container. - * - * @see [ExtensionContainer.getExtraProperties] - */ -val ExtensionAware.extra: ExtraPropertiesExtension - get() = extensions.extraProperties - - -operator fun ExtraPropertiesExtension.provideDelegate(receiver: Any?, property: KProperty<*>): MutablePropertyDelegate = - if (property.returnType.isMarkedNullable) NullableExtraPropertyDelegate(this, property.name) - else NonNullExtraPropertyDelegate(this, property.name) - - -private -class NonNullExtraPropertyDelegate( - private val extra: ExtraPropertiesExtension, - private val name: String -) : MutablePropertyDelegate { - - override fun getValue(receiver: Any?, property: KProperty<*>): T = - if (!extra.has(name)) cannotGetExtraProperty("does not exist") - else uncheckedCast(extra.get(name) ?: cannotGetExtraProperty("is null")) - - override fun setValue(receiver: Any?, property: KProperty<*>, value: T) = - extra.set(property.name, value) - - private - fun cannotGetExtraProperty(reason: String): Nothing = - throw InvalidUserCodeException("Cannot get non-null extra property '$name' as it $reason") -} - - -private -class NullableExtraPropertyDelegate( - private val extra: ExtraPropertiesExtension, - private val name: String -) : MutablePropertyDelegate { - - override fun getValue(receiver: Any?, property: KProperty<*>): T = - uncheckedCast(if (extra.has(name)) extra.get(name) else null) - - override fun setValue(receiver: Any?, property: KProperty<*>, value: T) = - extra.set(property.name, value) -} - - -/** - * Returns a property delegate provider that will initialize the extra property to the value provided - * by [initialValueProvider]. - * - * Usage: `val answer by extra { 42 }` - */ -inline operator fun ExtraPropertiesExtension.invoke(initialValueProvider: () -> T): InitialValueExtraPropertyDelegateProvider = - invoke(initialValueProvider()) - - -/** - * Returns a property delegate provider that will initialize the extra property to the given [initialValue]. - * - * Usage: `val answer by extra(42)` - */ -operator fun ExtraPropertiesExtension.invoke(initialValue: T): InitialValueExtraPropertyDelegateProvider = - InitialValueExtraPropertyDelegateProvider(this, initialValue) - - -class InitialValueExtraPropertyDelegateProvider( - val extra: ExtraPropertiesExtension, - val initialValue: T -) { - - operator fun provideDelegate(thisRef: Any?, property: kotlin.reflect.KProperty<*>): InitialValueExtraPropertyDelegate { - extra.set(property.name, initialValue) - return InitialValueExtraPropertyDelegate(extra) - } -} - - -/** - * Enables typed access to extra properties with initial value. - */ -class InitialValueExtraPropertyDelegate(val extra: ExtraPropertiesExtension) { - - operator fun setValue(receiver: Any?, property: kotlin.reflect.KProperty<*>, value: T) = - extra.set(property.name, value) - - @Suppress("unchecked_cast") - operator fun getValue(receiver: Any?, property: kotlin.reflect.KProperty<*>): T = - uncheckedCast(extra.get(property.name)) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleDsl.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleDsl.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleDsl.kt (revision 0) @@ -1,26 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - - -/** - * Delimits a Gradle DSL. - * - * See [DslMarker] - */ -@DslMarker -annotation class GradleDsl Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleExtensions.kt (revision 0) @@ -1,33 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.Plugin -import org.gradle.api.invocation.Gradle -import org.gradle.api.plugins.PluginAware - - -/** - * Applies the plugin of the given type [T]. Does nothing if the plugin has already been applied. - * - * The given class should implement the [Plugin] interface, and be parameterized for a - * compatible type of `this`. - * - * @param T the plugin type. - * @see [PluginAware.apply] - */ -inline fun > Gradle.apply() = - (this as PluginAware).apply() Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/GroovyInteroperability.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/GroovyInteroperability.kt (revision 92329459a346fd2bc6aa06ae3503bb49a6886b73) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/GroovyInteroperability.kt (revision 0) @@ -1,238 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import groovy.lang.Closure -import groovy.lang.GroovyObject -import groovy.lang.MetaClass - -import org.gradle.internal.Cast.uncheckedCast - -import org.codehaus.groovy.runtime.InvokerHelper.getMetaClass - -import org.gradle.kotlin.dsl.support.unsafeLazy - - -/** - * Adapts a Kotlin function to a single argument Groovy [Closure]. - * - * @param T the expected type of the single argument to the closure. - * @param action the function to be adapted. - * - * @see [KotlinClosure1] - */ -fun Any.closureOf(action: T.() -> Unit): Closure = - KotlinClosure1(action, this, this) - - -/** - * Adapts a Kotlin function to a Groovy [Closure] that operates on the - * configured Closure delegate. - * - * @param T the expected type of the delegate argument to the closure. - * @param action the function to be adapted. - * - * @see [KotlinClosure1] - */ -fun Any.delegateClosureOf(action: T.() -> Unit) = - object : Closure(this, this) { - @Suppress("unused") // to be called dynamically by Groovy - fun doCall() = uncheckedCast(delegate).action() - } - - -/** - * Adapts a parameterless Kotlin function to a parameterless Groovy [Closure]. - * - * @param V the return type. - * @param function the function to be adapted. - * @param owner optional owner of the Closure. - * @param thisObject optional _this Object_ of the Closure. - * - * @see [Closure] - */ -open class KotlinClosure0( - val function: () -> V?, - owner: Any? = null, - thisObject: Any? = null -) : groovy.lang.Closure(owner, thisObject) { - - @Suppress("unused") // to be called dynamically by Groovy - fun doCall(): V? = function() -} - - -/** - * Adapts an unary Kotlin function to an unary Groovy [Closure]. - * - * @param T the type of the single argument to the closure. - * @param V the return type. - * @param function the function to be adapted. - * @param owner optional owner of the Closure. - * @param thisObject optional _this Object_ of the Closure. - * - * @see [Closure] - */ -class KotlinClosure1( - val function: T.() -> V?, - owner: Any? = null, - thisObject: Any? = null -) : Closure(owner, thisObject) { - - @Suppress("unused") // to be called dynamically by Groovy - fun doCall(it: T): V? = it.function() -} - - -/** - * Adapts a binary Kotlin function to a binary Groovy [Closure]. - * - * @param T the type of the first argument. - * @param U the type of the second argument. - * @param V the return type. - * @param function the function to be adapted. - * @param owner optional owner of the Closure. - * @param thisObject optional _this Object_ of the Closure. - * - * @see [Closure] - */ -class KotlinClosure2( - val function: (T, U) -> V?, - owner: Any? = null, - thisObject: Any? = null -) : Closure(owner, thisObject) { - - @Suppress("unused") // to be called dynamically by Groovy - fun doCall(t: T, u: U): V? = function(t, u) -} - - -operator fun Closure.invoke(): T = call() - - -operator fun Closure.invoke(x: Any?): T = call(x) - - -operator fun Closure.invoke(vararg xs: Any?): T = call(*xs) - - -/** - * Executes the given [builder] against this object's [GroovyBuilderScope]. - * - * @see [GroovyBuilderScope] - */ -inline fun Any.withGroovyBuilder(builder: GroovyBuilderScope.() -> T): T = - GroovyBuilderScope.of(this).builder() - - -/** - * Provides a dynamic dispatching DSL with Groovy semantics for better integration with - * plugins that rely on Groovy builders such as the core `maven` plugin. - * - * It supports Groovy keyword arguments and arbitrary nesting, for instance, the following Groovy code: - * - * ```Groovy - * repository(url: "scp://repos.mycompany.com/releases") { - * authentication(userName: "me", password: "myPassword") - * } - * ``` - * - * Can be mechanically translated to the following Kotlin with the aid of `withGroovyBuilder`: - * - * ```Kotlin - * withGroovyBuilder { - * "repository"("url" to "scp://repos.mycompany.com/releases") { - * "authentication"("userName" to "me", "password" to "myPassword") - * } - * } - * ``` - * - * @see [withGroovyBuilder] - */ -interface GroovyBuilderScope : GroovyObject { - - companion object { - - fun of(value: Any): GroovyBuilderScope = - when (value) { - is GroovyObject -> GroovyBuilderScopeForGroovyObject(value) - else -> GroovyBuilderScopeForRegularObject(value) - } - } - - val delegate: Any - - operator fun String.invoke(vararg arguments: Any?): Any? - - operator fun String.invoke(): Any? = - invoke(*emptyArray()) - - operator fun String.invoke(vararg arguments: Any?, builder: GroovyBuilderScope.() -> T): Any? = - invoke(*arguments, closureFor(builder)) - - operator fun String.invoke(builder: GroovyBuilderScope.() -> T): Any? = - invoke(closureFor(builder)) - - operator fun String.invoke(vararg keywordArguments: Pair, builder: GroovyBuilderScope.() -> T): Any? = - invoke(keywordArguments.toMap(), closureFor(builder)) - - operator fun String.invoke(vararg keywordArguments: Pair): Any? = - invoke(keywordArguments.toMap()) - - private - fun closureFor(builder: GroovyBuilderScope.() -> T): Closure = - object : Closure(this, this) { - @Suppress("unused") - fun doCall() = delegate.withGroovyBuilder(builder) - } -} - - -private -class GroovyBuilderScopeForGroovyObject(override val delegate: GroovyObject) : GroovyBuilderScope, GroovyObject by delegate { - - override fun String.invoke(vararg arguments: Any?): Any? = - delegate.invokeMethod(this, arguments) -} - - -private -class GroovyBuilderScopeForRegularObject(override val delegate: Any) : GroovyBuilderScope { - - private - val groovyMetaClass: MetaClass by unsafeLazy { - getMetaClass(delegate) - } - - override fun invokeMethod(name: String, args: Any?): Any? = - groovyMetaClass.invokeMethod(delegate, name, args) - - override fun setProperty(propertyName: String, newValue: Any?) = - groovyMetaClass.setProperty(delegate, propertyName, newValue) - - override fun getProperty(propertyName: String): Any = - groovyMetaClass.getProperty(delegate, propertyName) - - override fun setMetaClass(metaClass: MetaClass?) = - throw IllegalStateException() - - override fun getMetaClass(): MetaClass = - groovyMetaClass - - override fun String.invoke(vararg arguments: Any?): Any? = - groovyMetaClass.invokeMethod(delegate, this, arguments) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinBuildScript.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinBuildScript.kt (revision 4fc15ec02526e4543fbcb4ce5d7acc2bebd5562b) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinBuildScript.kt (revision 0) @@ -1,70 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.Project -import org.gradle.api.initialization.dsl.ScriptHandler - -import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptDependenciesResolver -import org.gradle.kotlin.dsl.support.KotlinScriptHost -import org.gradle.kotlin.dsl.support.internalError - -import org.gradle.plugin.use.PluginDependenciesSpec - -import kotlin.script.extensions.SamWithReceiverAnnotations -import kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments -import kotlin.script.templates.ScriptTemplateDefinition - - -/** - * Base class for Kotlin build scripts. - */ -@ScriptTemplateDefinition( - resolver = KotlinBuildScriptDependenciesResolver::class, - scriptFilePattern = ".*\\.gradle\\.kts") -@ScriptTemplateAdditionalCompilerArguments(["-Xjsr305=strict"]) -@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") -@GradleDsl -abstract class KotlinBuildScript( - private val host: KotlinScriptHost -) : Project by host.target { - - /** - * The [ScriptHandler] for this script. - */ - override fun getBuildscript(): ScriptHandler = - host.scriptHandler - - /** - * Configures the build script classpath for this project. - * - * @see [Project.buildscript] - */ - @Suppress("unused") - open fun buildscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit): Unit = - internalError() - - /** - * Configures the plugin dependencies for this project. - * - * @see [PluginDependenciesSpec] - */ - @Suppress("unused") - fun plugins(@Suppress("unused_parameter") block: PluginDependenciesSpecScope.() -> Unit): Unit = - throw Exception("The plugins {} block must not be used here. " - + "If you need to apply a plugin imperatively, please use apply() or apply(plugin = \"id\") instead.") -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinInitScript.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinInitScript.kt (revision 92329459a346fd2bc6aa06ae3503bb49a6886b73) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinInitScript.kt (revision 0) @@ -1,407 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.Action -import org.gradle.api.PathValidation -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.ConfigurableFileTree -import org.gradle.api.file.CopySpec -import org.gradle.api.file.DeleteSpec -import org.gradle.api.file.FileTree -import org.gradle.api.initialization.dsl.ScriptHandler -import org.gradle.api.internal.file.DefaultFileOperations -import org.gradle.api.invocation.Gradle -import org.gradle.api.logging.Logger -import org.gradle.api.logging.Logging -import org.gradle.api.logging.LoggingManager -import org.gradle.api.plugins.ObjectConfigurationAction -import org.gradle.api.plugins.PluginAware -import org.gradle.api.resources.ResourceHandler -import org.gradle.api.tasks.WorkResult - -import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptDependenciesResolver -import org.gradle.kotlin.dsl.support.KotlinScriptHost -import org.gradle.kotlin.dsl.support.internalError -import org.gradle.kotlin.dsl.support.serviceOf -import org.gradle.kotlin.dsl.support.unsafeLazy - -import org.gradle.process.ExecResult -import org.gradle.process.ExecSpec -import org.gradle.process.JavaExecSpec - -import java.io.File -import java.net.URI - -import kotlin.script.extensions.SamWithReceiverAnnotations -import kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments -import kotlin.script.templates.ScriptTemplateDefinition - - -/** - * Base class for Kotlin init scripts. - */ -@ScriptTemplateDefinition( - resolver = KotlinBuildScriptDependenciesResolver::class, - scriptFilePattern = ".+\\.init\\.gradle\\.kts") -@ScriptTemplateAdditionalCompilerArguments(["-Xjsr305=strict"]) -@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") -abstract class KotlinInitScript( - private val host: KotlinScriptHost -) : InitScriptApi(host.target) { - - /** - * The [ScriptHandler] for this script. - */ - val initscript - get() = host.scriptHandler - - /** - * Applies zero or more plugins or scripts. - *

- * The given action is used to configure an [ObjectConfigurationAction], which “builds” the plugin application. - *

- * @param action the action to configure an [ObjectConfigurationAction] with before “executing” it - * @see [PluginAware.apply] - */ - override fun apply(action: Action) = - host.applyObjectConfigurationAction(action) - - override val operations - get() = host.operations -} - - -/** - * Standard implementation of the API exposed to all types of [Gradle] scripts, - * precompiled and otherwise. - */ -abstract class InitScriptApi(target: Gradle) : Gradle by target { - - protected - abstract val operations: DefaultFileOperations - - /** - * Configures the classpath of the init script. - */ - @Suppress("unused") - open fun initscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit): Unit = - internalError() - - /** - * Logger for init scripts. You can use this in your init script to write log messages. - */ - @Suppress("unused") - val logger: Logger by unsafeLazy { Logging.getLogger(Gradle::class.java) } - - /** - * The [LoggingManager] which can be used to receive logging and to control the standard output/error capture for - * this script. By default, `System.out` is redirected to the Gradle logging system at the `QUIET` log level, - * and `System.err` is redirected at the `ERROR` log level. - */ - @Suppress("unused") - val logging by unsafeLazy { gradle.serviceOf() } - - /** - * Provides access to resource-specific utility methods, for example factory methods that create various resources. - */ - @Suppress("unused") - val resources: ResourceHandler by unsafeLazy { operations.resources } - - /** - * Returns the relative path from this script's target base directory to the given path. - * - * The given path object is (logically) resolved as described for [KotlinInitScript.file], - * from which a relative path is calculated. - * - * @param path The path to convert to a relative path. - * @return The relative path. - */ - @Suppress("unused") - fun relativePath(path: Any): String = - operations.relativePath(path) - - /** - * Resolves a file path to a URI, relative to this script's target base directory. - * - * Evaluates the provided path object as described for [KotlinInitScript.file], - * with the exception that any URI scheme is supported, not just `file:` URIs. - */ - @Suppress("unused") - fun uri(path: Any): URI = - operations.uri(path) - - /** - * Resolves a file path relative to this script's target base directory. - * - * If this script targets [org.gradle.api.Project], - * then `path` is resolved relative to the project directory. - * - * If this script targets [org.gradle.api.initialization.Settings], - * then `path` is resolved relative to the build root directory. - * - * Otherwise the file is resolved relative to the script itself. - * - * This method converts the supplied path based on its type: - * - * - A [CharSequence], including [String]. - * A string that starts with `file:` is treated as a file URL. - * - A [File]. - * If the file is an absolute file, it is returned as is. Otherwise it is resolved. - * - A [java.nio.file.Path]. - * The path must be associated with the default provider and is treated the same way as an instance of `File`. - * - A [URI] or [java.net.URL]. - * The URL's path is interpreted as the file path. Only `file:` URLs are supported. - * - A [org.gradle.api.file.Directory] or [org.gradle.api.file.RegularFile]. - * - A [org.gradle.api.provider.Provider] of any supported type. - * The provider's value is resolved recursively. - * - A [java.util.concurrent.Callable] that returns any supported type. - * The callable's return value is resolved recursively. - * - * @param path The object to resolve as a `File`. - * @return The resolved file. - */ - @Suppress("unused") - fun file(path: Any): File = - operations.file(path) - - /** - * Resolves a file path relative to this script's target base directory. - * - * @param path The object to resolve as a `File`. - * @param validation The validation to perform on the file. - * @return The resolved file. - * @see KotlinInitScript.file - */ - @Suppress("unused") - fun file(path: Any, validation: PathValidation): File = - operations.file(path, validation) - - /** - * Creates a [ConfigurableFileCollection] containing the given files. - * - * You can pass any of the following types to this method: - * - * - A [CharSequence], including [String] as defined by [KotlinInitScript.file]. - * - A [File] as defined by [KotlinInitScript.file]. - * - A [java.nio.file.Path] as defined by [KotlinInitScript.file]. - * - A [URI] or [java.net.URL] as defined by [KotlinInitScript.file]. - * - A [org.gradle.api.file.Directory] or [org.gradle.api.file.RegularFile] - * as defined by [KotlinInitScript.file]. - * - A [Sequence], [Array] or [Iterable] that contains objects of any supported type. - * The elements of the collection are recursively converted to files. - * - A [org.gradle.api.file.FileCollection]. - * The contents of the collection are included in the returned collection. - * - A [org.gradle.api.provider.Provider] of any supported type. - * The provider's value is recursively converted to files. If the provider represents an output of a task, - * that task is executed if the file collection is used as an input to another task. - * - A [java.util.concurrent.Callable] that returns any supported type. - * The callable's return value is recursively converted to files. - * A `null` return value is treated as an empty collection. - * - A [org.gradle.api.Task]. - * Converted to the task's output files. - * The task is executed if the file collection is used as an input to another task. - * - A [org.gradle.api.tasks.TaskOutputs]. - * Converted to the output files the related task. - * The task is executed if the file collection is used as an input to another task. - * - Anything else is treated as a failure. - * - * The returned file collection is lazy, so that the paths are evaluated only when the contents of the file - * collection are queried. The file collection is also live, so that it evaluates the above each time the contents - * of the collection is queried. - * - * The returned file collection maintains the iteration order of the supplied paths. - * - * The returned file collection maintains the details of the tasks that produce the files, - * so that these tasks are executed if this file collection is used as an input to some task. - * - * This method can also be used to create an empty collection, which can later be mutated to add elements. - * - * @param paths The paths to the files. May be empty. - * @return The file collection. - */ - @Suppress("unused") - fun files(vararg paths: Any): ConfigurableFileCollection = - operations.files(paths) - - /** - * Creates a [ConfigurableFileCollection] containing the given files. - * - * @param paths The contents of the file collection. Evaluated as per [KotlinInitScript.files]. - * @param configuration The block to use to configure the file collection. - * @return The file collection. - * @see KotlinInitScript.files - */ - @Suppress("unused") - fun files(paths: Any, configuration: ConfigurableFileCollection.() -> Unit): ConfigurableFileCollection = - operations.files(paths).also(configuration) - - /** - * Creates a new [ConfigurableFileTree] using the given base directory. - * - * The given `baseDir` path is evaluated as per [KotlinInitScript.file]. - * - * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are - * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are - * queried. - * - * @param baseDir The base directory of the file tree. Evaluated as per [KotlinInitScript.file]. - * @return The file tree. - */ - @Suppress("unused") - fun fileTree(baseDir: Any): ConfigurableFileTree = - operations.fileTree(baseDir) - - /** - * Creates a new [ConfigurableFileTree] using the given base directory. - * - * @param baseDir The base directory of the file tree. Evaluated as per [KotlinInitScript.file]. - * @param configuration The block to use to configure the file tree. - * @return The file tree. - * @see [KotlinInitScript.fileTree] - */ - @Suppress("unused") - fun fileTree(baseDir: Any, configuration: ConfigurableFileTree.() -> Unit): ConfigurableFileTree = - operations.fileTree(baseDir).also(configuration) - - /** - * Creates a new [FileTree] which contains the contents of the given ZIP file. - * - * The given `zipPath` path is evaluated as per [KotlinInitScript.file] - * - * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are - * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are - * queried. - * - * You can combine this method with the [KotlinInitScript.copy] method to unzip a ZIP file. - * - * @param zipPath The ZIP file. Evaluated as per [KotlinInitScript.file]. - * @return The file tree. - */ - @Suppress("unused") - fun zipTree(zipPath: Any): FileTree = - operations.zipTree(zipPath) - - /** - * Creates a new [FileTree] which contains the contents of the given TAR file. - * - * The given tarPath path can be: - * - an instance of [org.gradle.api.resources.Resource], - * - any other object is evaluated as per [KotlinInitScript.file]. - * - * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are - * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are - * queried. - * - * Unless custom implementation of resources is passed, - * the tar tree attempts to guess the compression based on the file extension. - * - * You can combine this method with the [KotlinInitScript.copy] method to unzip a ZIP file. - * - * @param tarPath The TAR file or an instance of [org.gradle.api.resources.Resource]. - * @return The file tree. - */ - @Suppress("unused") - fun tarTree(tarPath: Any): FileTree = - operations.tarTree(tarPath) - - /** - * Copies the specified files. - * - * @param configuration The block to use to configure the [CopySpec]. - * @return `WorkResult` that can be used to check if the copy did any work. - */ - @Suppress("unused") - fun copy(configuration: CopySpec.() -> Unit): WorkResult = - operations.copy(configuration) - - /** - * Creates a {@link CopySpec} which can later be used to copy files or create an archive. - * - * @return The created [CopySpec] - */ - @Suppress("unused") - fun copySpec(): CopySpec = - operations.copySpec() - - /** - * Creates a {@link CopySpec} which can later be used to copy files or create an archive. - * - * @param configuration The block to use to configure the [CopySpec]. - * @return The configured [CopySpec] - */ - @Suppress("unused") - fun copySpec(configuration: CopySpec.() -> Unit): CopySpec = - operations.copySpec().also(configuration) - - /** - * Creates a directory and returns a file pointing to it. - * - * @param path The path for the directory to be created. Evaluated as per [KotlinInitScript.file]. - * @return The created directory. - * @throws org.gradle.api.InvalidUserDataException If the path points to an existing file. - */ - @Suppress("unused") - fun mkdir(path: Any): File = - operations.mkdir(path) - - /** - * Deletes files and directories. - * - * This will not follow symlinks. If you need to follow symlinks too use [KotlinInitScript.delete]. - * - * @param paths Any type of object accepted by [KotlinInitScript.file] - * @return true if anything got deleted, false otherwise - */ - @Suppress("unused") - fun delete(vararg paths: Any): Boolean = - operations.delete(*paths) - - /** - * Deletes the specified files. - * - * @param configuration The block to use to configure the [DeleteSpec]. - * @return `WorkResult` that can be used to check if delete did any work. - */ - @Suppress("unused") - fun delete(configuration: DeleteSpec.() -> Unit): WorkResult = - operations.delete(configuration) - - /** - * Executes an external command. - * - * This method blocks until the process terminates, with its result being returned. - * - * @param configuration The block to use to configure the [ExecSpec]. - * @return The result of the execution. - */ - @Suppress("unused") - fun exec(configuration: ExecSpec.() -> Unit): ExecResult = - operations.exec(configuration) - - /** - * Executes an external Java process. - * - * This method blocks until the process terminates, with its result being returned. - * - * @param configuration The block to use to configure the [JavaExecSpec]. - * @return The result of the execution. - */ - @Suppress("unused") - fun javaexec(configuration: JavaExecSpec.() -> Unit): ExecResult = - operations.javaexec(configuration) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinSettingsScript.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinSettingsScript.kt (revision 92329459a346fd2bc6aa06ae3503bb49a6886b73) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinSettingsScript.kt (revision 0) @@ -1,452 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.Action -import org.gradle.api.PathValidation -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.ConfigurableFileTree -import org.gradle.api.file.CopySpec -import org.gradle.api.file.DeleteSpec -import org.gradle.api.file.FileTree -import org.gradle.api.initialization.Settings -import org.gradle.api.initialization.dsl.ScriptHandler -import org.gradle.api.internal.GradleInternal -import org.gradle.api.internal.file.DefaultFileOperations -import org.gradle.api.internal.file.FileLookup -import org.gradle.api.internal.file.collections.DirectoryFileTreeFactory -import org.gradle.api.invocation.Gradle -import org.gradle.api.logging.Logger -import org.gradle.api.logging.Logging -import org.gradle.api.logging.LoggingManager -import org.gradle.api.plugins.ObjectConfigurationAction -import org.gradle.api.resources.ResourceHandler -import org.gradle.api.tasks.WorkResult - -import org.gradle.internal.hash.FileHasher -import org.gradle.internal.hash.StreamHasher -import org.gradle.internal.reflect.Instantiator -import org.gradle.internal.resource.TextResourceLoader -import org.gradle.internal.service.ServiceRegistry - -import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptDependenciesResolver -import org.gradle.kotlin.dsl.support.KotlinScriptHost -import org.gradle.kotlin.dsl.support.get -import org.gradle.kotlin.dsl.support.internalError -import org.gradle.kotlin.dsl.support.serviceOf -import org.gradle.kotlin.dsl.support.unsafeLazy - -import org.gradle.process.ExecResult -import org.gradle.process.ExecSpec -import org.gradle.process.JavaExecSpec -import org.gradle.process.internal.ExecFactory - -import java.io.File -import java.net.URI - -import kotlin.script.extensions.SamWithReceiverAnnotations -import kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments -import kotlin.script.templates.ScriptTemplateDefinition - - -/** - * Base class for Kotlin settings scripts. - */ -@ScriptTemplateDefinition( - resolver = KotlinBuildScriptDependenciesResolver::class, - scriptFilePattern = "^(settings|.+\\.settings)\\.gradle\\.kts$") -@ScriptTemplateAdditionalCompilerArguments(["-Xjsr305=strict"]) -@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") -abstract class KotlinSettingsScript( - private val host: KotlinScriptHost -) : SettingsScriptApi(host.target) { - - /** - * The [ScriptHandler] for this script. - */ - override fun getBuildscript(): ScriptHandler = - host.scriptHandler - - override val fileOperations: DefaultFileOperations - get() = host.operations - - /** - * Applies zero or more plugins or scripts. - * - * @param configuration the block to configure an {@link ObjectConfigurationAction} with before “executing” it - */ - override fun apply(configuration: ObjectConfigurationAction.() -> Unit) = - host.applyObjectConfigurationAction(Action { it.configuration() }) - - override fun apply(action: Action) = - host.applyObjectConfigurationAction(action) -} - - -/** - * Standard implementation of the API exposed to all types of [Settings] scripts, - * precompiled and otherwise. - */ -abstract class SettingsScriptApi(settings: Settings) : Settings by settings { - - protected - abstract val fileOperations: DefaultFileOperations - - /** - * Logger for settings. You can use this in your settings file to write log messages. - */ - @Suppress("unused") - val logger: Logger by unsafeLazy { Logging.getLogger(Settings::class.java) } - - /** - * The [LoggingManager] which can be used to receive logging and to control the standard output/error capture for - * this script. By default, `System.out` is redirected to the Gradle logging system at the `QUIET` log level, - * and `System.err` is redirected at the `ERROR` log level. - */ - @Suppress("unused") - val logging by unsafeLazy { settings.serviceOf() } - - /** - * Provides access to resource-specific utility methods, for example factory methods that create various resources. - */ - @Suppress("unused") - val resources: ResourceHandler by unsafeLazy { fileOperations.resources } - - /** - * Returns the relative path from this script's target base directory to the given path. - * - * The given path object is (logically) resolved as described for [KotlinSettingsScript.file], - * from which a relative path is calculated. - * - * @param path The path to convert to a relative path. - * @return The relative path. - */ - @Suppress("unused") - fun relativePath(path: Any): String = - fileOperations.relativePath(path) - - /** - * Resolves a file path to a URI, relative to this script's target base directory. - * - * Evaluates the provided path object as described for [KotlinSettingsScript.file], - * with the exception that any URI scheme is supported, not just `file:` URIs. - */ - @Suppress("unused") - fun uri(path: Any): URI = - fileOperations.uri(path) - - /** - * Resolves a file path relative to this script's target base directory. - * - * If this script targets [org.gradle.api.Project], - * then `path` is resolved relative to the project directory. - * - * If this script targets [org.gradle.api.initialization.Settings], - * then `path` is resolved relative to the build root directory. - * - * This method converts the supplied path based on its type: - * - * - A [CharSequence], including [String]. - * A string that starts with `file:` is treated as a file URL. - * - A [File]. - * If the file is an absolute file, it is returned as is. Otherwise it is resolved. - * - A [java.nio.file.Path]. - * The path must be associated with the default provider and is treated the same way as an instance of `File`. - * - A [URI] or [java.net.URL]. - * The URL's path is interpreted as the file path. Only `file:` URLs are supported. - * - A [org.gradle.api.file.Directory] or [org.gradle.api.file.RegularFile]. - * - A [org.gradle.api.provider.Provider] of any supported type. - * The provider's value is resolved recursively. - * - A [java.util.concurrent.Callable] that returns any supported type. - * The callable's return value is resolved recursively. - * - * @param path The object to resolve as a `File`. - * @return The resolved file. - */ - @Suppress("unused") - fun file(path: Any): File = - fileOperations.file(path) - - /** - * Resolves a file path relative to this script's target base directory. - * - * @param path The object to resolve as a `File`. - * @param validation The validation to perform on the file. - * @return The resolved file. - * @see KotlinSettingsScript.file - */ - @Suppress("unused") - fun file(path: Any, validation: PathValidation): File = - fileOperations.file(path, validation) - - /** - * Creates a [ConfigurableFileCollection] containing the given files. - * - * You can pass any of the following types to this method: - * - * - A [CharSequence], including [String] as defined by [KotlinSettingsScript.file]. - * - A [File] as defined by [KotlinSettingsScript.file]. - * - A [java.nio.file.Path] as defined by [KotlinSettingsScript.file]. - * - A [URI] or [java.net.URL] as defined by [KotlinSettingsScript.file]. - * - A [org.gradle.api.file.Directory] or [org.gradle.api.file.RegularFile] - * as defined by [KotlinSettingsScript.file]. - * - A [Sequence], [Array] or [Iterable] that contains objects of any supported type. - * The elements of the collection are recursively converted to files. - * - A [org.gradle.api.file.FileCollection]. - * The contents of the collection are included in the returned collection. - * - A [org.gradle.api.provider.Provider] of any supported type. - * The provider's value is recursively converted to files. If the provider represents an output of a task, - * that task is executed if the file collection is used as an input to another task. - * - A [java.util.concurrent.Callable] that returns any supported type. - * The callable's return value is recursively converted to files. - * A `null` return value is treated as an empty collection. - * - A [org.gradle.api.Task]. - * Converted to the task's output files. - * The task is executed if the file collection is used as an input to another task. - * - A [org.gradle.api.tasks.TaskOutputs]. - * Converted to the output files the related task. - * The task is executed if the file collection is used as an input to another task. - * - Anything else is treated as a failure. - * - * The returned file collection is lazy, so that the paths are evaluated only when the contents of the file - * collection are queried. The file collection is also live, so that it evaluates the above each time the contents - * of the collection is queried. - * - * The returned file collection maintains the iteration order of the supplied paths. - * - * The returned file collection maintains the details of the tasks that produce the files, - * so that these tasks are executed if this file collection is used as an input to some task. - * - * This method can also be used to create an empty collection, which can later be mutated to add elements. - * - * @param paths The paths to the files. May be empty. - * @return The file collection. - */ - @Suppress("unused") - fun files(vararg paths: Any): ConfigurableFileCollection = - fileOperations.files(paths) - - /** - * Creates a [ConfigurableFileCollection] containing the given files. - * - * @param paths The contents of the file collection. Evaluated as per [KotlinSettingsScript.files]. - * @param configuration The block to use to configure the file collection. - * @return The file collection. - * @see KotlinSettingsScript.files - */ - @Suppress("unused") - fun files(paths: Any, configuration: ConfigurableFileCollection.() -> Unit): ConfigurableFileCollection = - fileOperations.files(paths).also(configuration) - - /** - * Creates a new [ConfigurableFileTree] using the given base directory. - * - * The given `baseDir` path is evaluated as per [KotlinSettingsScript.file]. - * - * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are - * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are - * queried. - * - * @param baseDir The base directory of the file tree. Evaluated as per [KotlinSettingsScript.file]. - * @return The file tree. - */ - @Suppress("unused") - fun fileTree(baseDir: Any): ConfigurableFileTree = - fileOperations.fileTree(baseDir) - - /** - * Creates a new [ConfigurableFileTree] using the given base directory. - * - * @param baseDir The base directory of the file tree. Evaluated as per [KotlinSettingsScript.file]. - * @param configuration The block to use to configure the file tree. - * @return The file tree. - * @see [KotlinSettingsScript.fileTree] - */ - @Suppress("unused") - fun fileTree(baseDir: Any, configuration: ConfigurableFileTree.() -> Unit): ConfigurableFileTree = - fileOperations.fileTree(baseDir).also(configuration) - - /** - * Creates a new [FileTree] which contains the contents of the given ZIP file. - * - * The given `zipPath` path is evaluated as per [KotlinSettingsScript.file] - * - * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are - * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are - * queried. - * - * You can combine this method with the [KotlinSettingsScript.copy] method to unzip a ZIP file. - * - * @param zipPath The ZIP file. Evaluated as per [KotlinSettingsScript.file]. - * @return The file tree. - */ - @Suppress("unused") - fun zipTree(zipPath: Any): FileTree = - fileOperations.zipTree(zipPath) - - /** - * Creates a new [FileTree] which contains the contents of the given TAR file. - * - * The given tarPath path can be: - * - an instance of [org.gradle.api.resources.Resource], - * - any other object is evaluated as per [KotlinSettingsScript.file]. - * - * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are - * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are - * queried. - * - * Unless custom implementation of resources is passed, - * the tar tree attempts to guess the compression based on the file extension. - * - * You can combine this method with the [KotlinSettingsScript.copy] method to unzip a ZIP file. - * - * @param tarPath The TAR file or an instance of [org.gradle.api.resources.Resource]. - * @return The file tree. - */ - @Suppress("unused") - fun tarTree(tarPath: Any): FileTree = - fileOperations.tarTree(tarPath) - - /** - * Copies the specified files. - * - * @param configuration The block to use to configure the [CopySpec]. - * @return `WorkResult` that can be used to check if the copy did any work. - */ - @Suppress("unused") - fun copy(configuration: CopySpec.() -> Unit): WorkResult = - fileOperations.copy(configuration) - - /** - * Creates a {@link CopySpec} which can later be used to copy files or create an archive. - * - * @return The created [CopySpec] - */ - @Suppress("unused") - fun copySpec(): CopySpec = - fileOperations.copySpec() - - /** - * Creates a {@link CopySpec} which can later be used to copy files or create an archive. - * - * @param configuration The block to use to configure the [CopySpec]. - * @return The configured [CopySpec] - */ - @Suppress("unused") - fun copySpec(configuration: CopySpec.() -> Unit): CopySpec = - fileOperations.copySpec().also(configuration) - - /** - * Creates a directory and returns a file pointing to it. - * - * @param path The path for the directory to be created. Evaluated as per [KotlinSettingsScript.file]. - * @return The created directory. - * @throws org.gradle.api.InvalidUserDataException If the path points to an existing file. - */ - @Suppress("unused") - fun mkdir(path: Any): File = - fileOperations.mkdir(path) - - /** - * Deletes files and directories. - * - * This will not follow symlinks. If you need to follow symlinks too use [KotlinSettingsScript.delete]. - * - * @param paths Any type of object accepted by [KotlinSettingsScript.file] - * @return true if anything got deleted, false otherwise - */ - @Suppress("unused") - fun delete(vararg paths: Any): Boolean = - fileOperations.delete(*paths) - - /** - * Deletes the specified files. - * - * @param configuration The block to use to configure the [DeleteSpec]. - * @return `WorkResult` that can be used to check if delete did any work. - */ - @Suppress("unused") - fun delete(configuration: DeleteSpec.() -> Unit): WorkResult = - fileOperations.delete(configuration) - - /** - * Executes an external command. - * - * This method blocks until the process terminates, with its result being returned. - * - * @param configuration The block to use to configure the [ExecSpec]. - * @return The result of the execution. - */ - @Suppress("unused") - fun exec(configuration: ExecSpec.() -> Unit): ExecResult = - fileOperations.exec(configuration) - - /** - * Executes an external Java process. - * - * This method blocks until the process terminates, with its result being returned. - * - * @param configuration The block to use to configure the [JavaExecSpec]. - * @return The result of the execution. - */ - @Suppress("unused") - fun javaexec(configuration: JavaExecSpec.() -> Unit): ExecResult = - fileOperations.javaexec(configuration) - - /** - * Configures the build script classpath for settings. - * - * @see [Settings.getBuildscript] - */ - @Suppress("unused") - open fun buildscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit): Unit = - internalError() - - /** - * Applies zero or more plugins or scripts. - * - * @param configuration the block to configure an {@link ObjectConfigurationAction} with before “executing” it - */ - open fun apply(configuration: ObjectConfigurationAction.() -> Unit) = - settings.apply({ it.configuration() }) -} - - -internal -fun fileOperationsFor(settings: Settings): DefaultFileOperations = - fileOperationsFor(settings.gradle, settings.rootDir) - - -internal -fun fileOperationsFor(gradle: Gradle, baseDir: File?): DefaultFileOperations = - fileOperationsFor((gradle as GradleInternal).services, baseDir) - - -internal -fun fileOperationsFor(services: ServiceRegistry, baseDir: File?): DefaultFileOperations { - val fileLookup = services.get() - return DefaultFileOperations( - baseDir?.let { fileLookup.getFileResolver(it) } ?: fileLookup.fileResolver, - null, - null, - services.get(), - fileLookup, - services.get(), - services.get(), - services.get(), - services.get(), - services.get()) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensions.kt (revision ade1cc6b0cf0287ea074791a86e599df53bc2a4a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensions.kt (revision 0) @@ -1,139 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.NamedDomainObjectCollection -import org.gradle.api.UnknownDomainObjectException - -import org.gradle.kotlin.dsl.support.illegalElementType - -import kotlin.reflect.KClass -import kotlin.reflect.KProperty -import kotlin.reflect.full.safeCast - - -/** - * Locates an object by name and casts it to the expected type [T]. - * - * If an object with the given [name] is not found, [UnknownDomainObjectException] is thrown. - * If the object is found but cannot be cast to the expected type [T], [IllegalArgumentException] is thrown. - * - * @param name object name - * @return the object, never null - * @throws [UnknownDomainObjectException] When the given object is not found. - * @throws [IllegalArgumentException] When the given object cannot be cast to the expected type. - */ -@Suppress("extension_shadowed_by_member") -inline fun NamedDomainObjectCollection.getByName(name: String) = - getByName(name).let { - it as? T - ?: throw illegalElementType(this, name, T::class, it::class) - } - - -/** - * Locates an object by name and casts it to the expected [type]. - * - * If an object with the given [name] is not found, [UnknownDomainObjectException] is thrown. - * If the object is found but cannot be cast to the expected [type], [IllegalArgumentException] is thrown. - * - * @param name object name - * @param type expected type - * @return the object, never null - * @throws [UnknownDomainObjectException] When the given object is not found. - * @throws [IllegalArgumentException] When the given object cannot be cast to the expected type. - */ -fun NamedDomainObjectCollection.getByName(name: String, type: KClass): T = - getByName(name).let { - type.safeCast(it) - ?: throw illegalElementType(this, name, type, it::class) - } - - -/** - * Locates an object by name and casts it to the expected type [T] then configures it. - * - * If an object with the given [name] is not found, [UnknownDomainObjectException] is thrown. - * If the object is found but cannot be cast to the expected type [T], [IllegalArgumentException] is thrown. - * - * @param name object name - * @param configure configuration action to apply to the object before returning it - * @return the object, never null - * @throws [UnknownDomainObjectException] When the given object is not found. - * @throws [IllegalArgumentException] When the given object cannot be cast to the expected type. - */ -inline fun NamedDomainObjectCollection.getByName(name: String, configure: T.() -> Unit) = - getByName(name).also(configure) - - -/** - * Idiomatic way of referring to an existing element in a collection - * via a delegate property. - * - * `tasks { val jar by getting }` - */ -inline val > U.getting: U - get() = this - - -/** - * Idiomatic way of referring and configuring an existing element in a collection - * via a delegate property. - * - * `tasks { val jar by getting { group = "My" } }` - */ -fun > U.getting(configuration: T.() -> Unit) = - NamedDomainObjectCollectionDelegateProvider(this, configuration) - - -class NamedDomainObjectCollectionDelegateProvider( - val collection: NamedDomainObjectCollection, - val configuration: T.() -> Unit -) { - - operator fun provideDelegate(thisRef: Any?, property: kotlin.reflect.KProperty<*>): NamedDomainObjectCollection = - collection.apply { - getByName(property.name).apply(configuration) - } -} - - -/** - * Locates an object by name, failing if there is no such object. - * - * @param name The object name - * @return The object with the given name. - * @throws [UnknownDomainObjectException] when there is no such object in this collection. - * - * @see [NamedDomainObjectCollection.getByName] - */ -operator fun NamedDomainObjectCollection.get(name: String): T = - getByName(name) - - -/** - * Allows a [NamedDomainObjectCollection] to be used as a property delegate. - * - * @throws [UnknownDomainObjectException] upon property access when there is no such object in the given collection. - * - * @see [NamedDomainObjectCollection.getByName] - */ -inline operator fun NamedDomainObjectCollection.getValue(thisRef: Any?, property: KProperty<*>): U = - getByName(property.name).let { - it as? U - ?: throw illegalElementType(this, property.name, U::class, it::class) - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensions.kt (revision ade1cc6b0cf0287ea074791a86e599df53bc2a4a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensions.kt (revision 0) @@ -1,214 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.Action -import org.gradle.api.NamedDomainObjectContainer -import org.gradle.api.PolymorphicDomainObjectContainer - -import kotlin.reflect.KClass -import kotlin.reflect.KProperty - - -/** - * Allows the container to be configured, creating missing objects as they are referenced. - * - * @param configuration The expression to configure this container with - * @return The container. - */ -inline operator fun > C.invoke( - configuration: NamedDomainObjectContainerScope.() -> Unit -): C = - - apply { - configuration(NamedDomainObjectContainerScope(this)) - } - - -/** - * Receiver for [NamedDomainObjectContainer] configuration blocks. - */ -class NamedDomainObjectContainerScope( - private val container: NamedDomainObjectContainer -) : NamedDomainObjectContainer by container, PolymorphicDomainObjectContainer { - - override fun create(name: String, type: Class): U = - polymorphicDomainObjectContainer().create(name, type) - - override fun create(name: String, type: Class, configuration: Action): U = - polymorphicDomainObjectContainer().create(name, type, configuration) - - override fun maybeCreate(name: String, type: Class): U = - polymorphicDomainObjectContainer().maybeCreate(name, type) - - override fun containerWithType(type: Class): NamedDomainObjectContainer = - polymorphicDomainObjectContainer().containerWithType(type) - - /** - * @see [NamedDomainObjectContainer.maybeCreate] - */ - inline operator fun String.invoke(configuration: T.() -> Unit): T = - this().apply(configuration) - - /** - * @see [NamedDomainObjectContainer.maybeCreate] - */ - operator fun String.invoke(): T = - container.maybeCreate(this) - - /** - * @see [PolymorphicDomainObjectContainer.maybeCreate] - */ - inline operator fun String.invoke(type: KClass, configuration: U.() -> Unit): U = - this(type).apply(configuration) - - /** - * @see [PolymorphicDomainObjectContainer.maybeCreate] - */ - operator fun String.invoke(type: KClass): U = - polymorphicDomainObjectContainer().maybeCreate(this, type.java) - - /** - * Cast this to [PolymorphicDomainObjectContainer] or throw [IllegalArgumentException]. - * - * We must rely on the dynamic cast and possible runtime failure here due to a Kotlin extension member limitation. - * Kotlin currently can't disambiguate between invoke operators with more specific receivers in a type hierarchy. - * - * See https://youtrack.jetbrains.com/issue/KT-15711 - */ - private - fun polymorphicDomainObjectContainer() = - container as? PolymorphicDomainObjectContainer - ?: throw IllegalArgumentException("Container '$container' is not polymorphic.") -} - - -/** - * Provides a property delegate that creates elements of the default collection type. - */ -val NamedDomainObjectContainer.creating - get() = NamedDomainObjectContainerDelegateProvider(this, {}) - - -/** - * Provides a property delegate that creates elements of the default collection type with the given [configuration]. - * - * `val myElement by myContainer.creating { myProperty = 42 }` - */ -fun NamedDomainObjectContainer.creating(configuration: T.() -> Unit) = - NamedDomainObjectContainerDelegateProvider(this, configuration) - - -/** - * A property delegate that creates elements in the given [NamedDomainObjectContainer]. - * - * See [creating] - */ -class NamedDomainObjectContainerDelegateProvider( - val container: NamedDomainObjectContainer, - val configuration: T.() -> Unit -) { - - operator fun provideDelegate(thisRef: Any?, property: KProperty<*>) = - container.apply { - create(property.name).apply(configuration) - } -} - - -/** - * Provides a property delegate that creates elements of the given [type]. - */ -fun PolymorphicDomainObjectContainer.creating(type: KClass) = - creating(type.java, {}) - - -/** - * Provides a property delegate that creates elements of the given [type] with the given [configuration]. - */ -fun PolymorphicDomainObjectContainer.creating(type: KClass, configuration: U.() -> Unit) = - creating(type.java, configuration) - - -/** - * Provides a property delegate that creates elements of the given [type] expressed as a [java.lang.Class] - * with the given [configuration]. - */ -fun PolymorphicDomainObjectContainer.creating(type: Class, configuration: U.() -> Unit) = - PolymorphicDomainObjectContainerDelegateProvider(this, type, configuration) - - -/** - * A property delegate that creates elements of the given [type] with the given [configuration] in the given [container]. - */ -class PolymorphicDomainObjectContainerDelegateProvider( - val container: PolymorphicDomainObjectContainer, - val type: Class, - val configuration: U.() -> Unit -) { - - @Suppress("unchecked_cast") - operator fun provideDelegate(thisRef: Any?, property: KProperty<*>) = - container.apply { - create(property.name, type).apply(configuration) - } as PolymorphicDomainObjectContainer -} - - -/** - * Provides a property delegate that gets elements of the given [type] and applies the given [configuration]. - */ -fun NamedDomainObjectContainer.getting(type: KClass, configuration: U.() -> Unit) = - PolymorphicDomainObjectContainerGettingDelegateProvider(this, type, configuration) - - -/** - * Provides a property delegate that gets elements of the given [type]. - */ -fun NamedDomainObjectContainer.getting(type: KClass) = - PolymorphicDomainObjectContainerGettingDelegate(this, type) - - -/** - * A property delegate that gets elements of the given [type] in the given [container]. - */ -class PolymorphicDomainObjectContainerGettingDelegate( - val container: NamedDomainObjectContainer, - val type: KClass -) { - - operator fun getValue(receiver: Any?, property: kotlin.reflect.KProperty<*>): U = - container.getByName(property.name, type) -} - - -/** - * A property delegate that gets elements of the given [type] from the given [container] - * and applies the given [configuration]. - */ -class PolymorphicDomainObjectContainerGettingDelegateProvider( - val container: NamedDomainObjectContainer, - val type: KClass, - val configuration: U.() -> Unit -) { - - @Suppress("unchecked_cast") - operator fun provideDelegate(thisRef: Any?, property: KProperty<*>) = - container.apply { - getByName(property.name, type).configuration() - } as NamedDomainObjectContainer -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ObjectConfigurationActionExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ObjectConfigurationActionExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ObjectConfigurationActionExtensions.kt (revision 0) @@ -1,31 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.Plugin -import org.gradle.api.plugins.ObjectConfigurationAction - - -/** - * Adds a Plugin to use to configure the target objects. This method may be called - * multiple times, to use multiple plugins. Scripts and plugins are applied in the order - * that they are added. - * - * @param T the plugin to apply. - */ -inline fun > ObjectConfigurationAction.plugin() = - this.plugin(T::class.java) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensions.kt (revision 0) @@ -1,70 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.plugins.PluginAware - - -/** - * Applies the given plugin or script. - * - * @param from a script to apply, evaluated as per [Project.file] - * @param plugin a id of the plugin to apply - * @param to the plugin target object or collection of objects, target is self when null - * @see [PluginAware.apply] - */ -fun PluginAware.apply(from: Any? = null, plugin: String? = null, to: Any? = null) { - require(from != null || plugin != null) { "At least one of 'from' or 'plugin' must be given." } - apply { - if (plugin != null) it.plugin(plugin) - if (from != null) it.from(from) - if (to != null) it.to(to) - } -} - - -/** - * Applies the plugin of the given type [T]. Does nothing if the plugin has already been applied. - * - * The given class should implement the [Plugin] interface. - * - * @param T the plugin type. - * @see [PluginAware.apply] - */ -inline fun > PluginAware.apply() { - apply { - it.plugin(T::class.java) - } -} - - -/** - * Applies the plugin of the given type [T] to the specified object. Does nothing if the plugin has already been applied. - * - * The given class should implement the [Plugin] interface. - * - * @param T the plugin type. - * @param to the plugin target object or collection of objects - * @see [PluginAware.apply] - */ -inline fun > PluginAware.apply(to: Any) { - apply { - it.plugin(T::class.java) - it.to(to) - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecExtensions.kt (revision 490ec4c70ecb84b1524b8a8f8bdb100ce3d5e363) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecExtensions.kt (revision 0) @@ -1,33 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.plugin.management.internal.autoapply.AutoAppliedBuildScanPlugin -import org.gradle.plugin.use.PluginDependenciesSpec -import org.gradle.plugin.use.PluginDependencySpec - - -/** - * The `build-scan` plugin. - * - * Visit the [Build Scan Plugin User Manual](https://docs.gradle.com/build-scan-plugin/) for additional information. - * - * By default, the applied plugin version will be the same as the one used by the `--scan` command line option. - * - * You can also use e.g. `` `build-scan` version "1.8" `` to request a different version. - */ -val PluginDependenciesSpec.`build-scan`: PluginDependencySpec - get() = id(AutoAppliedBuildScanPlugin.ID.id) version AutoAppliedBuildScanPlugin.VERSION Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScope.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScope.kt (revision 6b27df709ccd65c52ffac86c46c1fe5d67620d94) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScope.kt (revision 0) @@ -1,49 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.plugin.use.PluginDependenciesSpec -import org.gradle.plugin.use.PluginDependencySpec - - -/** - * Receiver for the `plugins` block. - * - * This class exists for the sole purpose of marking the `plugins` block as a [GradleDsl] thus - * hiding all members provided by the outer [KotlinBuildScript] scope. - * - * @see [PluginDependenciesSpec] - */ -@GradleDsl -class PluginDependenciesSpecScope(plugins: PluginDependenciesSpec) : PluginDependenciesSpec by plugins - - -/** - * Specify the version of the plugin to depend on. - * - * Infix version of [PluginDependencySpec.version]. - */ -infix fun PluginDependencySpec.version(version: String?): PluginDependencySpec = version(version) - - -/** - * Specifies whether the plugin should be applied to the current project. Otherwise it is only put - * on the project's classpath. - * - * Infix version of [PluginDependencySpec.apply]. - */ -infix fun PluginDependencySpec.apply(apply: Boolean): PluginDependencySpec = apply(apply) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/PolymorphicDomainObjectContainerExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/PolymorphicDomainObjectContainerExtensions.kt (revision 77224e2e1b7a9d00b29d08cc4230f3fd2d964621) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/PolymorphicDomainObjectContainerExtensions.kt (revision 0) @@ -1,71 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.InvalidUserDataException -import org.gradle.api.PolymorphicDomainObjectContainer - - -/** - * Creates a domain object with the specified name and type, adds it to the container, - * and configures it with the specified action. - * - * @param name the name of the domain object to be created - * @param configuration an action for configuring the domain object - * @param the type of the domain object to be created - * @return the created domain object - * @throws [InvalidUserDataException] if a domain object with the specified name already - * exists or the container does not support creating a domain object with the specified - * type - */ -inline fun PolymorphicDomainObjectContainer.create( - name: String, - crossinline configuration: U.() -> Unit -) = - - this.create(name, U::class.java, { configuration(it) }) - - -/** - * Creates a domain object with the specified name and type, and adds it to the container. - * - * @param name the name of the domain object to be created - * @param the type of the domain object to be created - * @return the created domain object - * @throws [InvalidUserDataException] if a domain object with the specified name already - * exists or the container does not support creating a domain object with the specified - * type - */ -@Suppress("extension_shadowed_by_member") -inline fun PolymorphicDomainObjectContainer.create(name: String) = - create(name, U::class.java) - - -/** - * Creates a domain object with the specified name and type if it does not exists, and adds it to the container. - * - * @param name the name of the domain object to be created - * @param the type of the domain object to be created - * @return the created domain object - * @throws [InvalidUserDataException] if a domain object with the specified name already - * exists or the container does not support creating a domain object with the specified - * type - * @throws [ClassCastException] if a domain object with the specified name exists with a different type - */ -@Suppress("extension_shadowed_by_member") -inline fun PolymorphicDomainObjectContainer.maybeCreate(name: String) = - maybeCreate(name, U::class.java) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ProjectExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ProjectExtensions.kt (revision 293efbcd3428d8e8205946c71f98046c3512bc7f) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ProjectExtensions.kt (revision 0) @@ -1,240 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.DefaultTask -import org.gradle.api.Incubating -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.model.ObjectFactory - -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.dsl.RepositoryHandler - -import org.gradle.api.file.FileCollection - -import org.gradle.api.initialization.dsl.ScriptHandler - -import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency -import org.gradle.api.internal.file.DefaultFileCollectionFactory -import org.gradle.api.internal.file.FileCollectionInternal - -import org.gradle.api.plugins.Convention -import org.gradle.api.plugins.PluginAware - -import org.gradle.api.provider.ListProperty -import org.gradle.api.provider.Property -import org.gradle.api.provider.PropertyState - -import org.gradle.api.tasks.TaskContainer - -import org.gradle.kotlin.dsl.provider.gradleKotlinDslOf -import org.gradle.kotlin.dsl.support.configureWith - -import java.io.File - -import kotlin.reflect.KClass -import kotlin.reflect.KProperty - - -fun Project.buildscript(action: ScriptHandlerScope.() -> Unit): Unit = - project.buildscript.configureWith(action) - - -/** - * Sets the default tasks of this project. These are used when no tasks names are provided when - * starting the build. - */ -@Suppress("nothing_to_inline") -inline fun Project.defaultTasks(vararg tasks: Task) { - defaultTasks(*tasks.map { it.name }.toTypedArray()) -} - - -/** - * Applies the plugin of the given type [T]. Does nothing if the plugin has already been applied. - * - * The given class should implement the [Plugin] interface, and be parameterized for a - * compatible type of `this`. - * - * @param T the plugin type. - * @see [PluginAware.apply] - */ -inline fun > Project.apply() = - (this as PluginAware).apply() - - -/** - * Executes the given configuration block against the [plugin convention] - * [Convention.getPlugin] or extension of the specified type. - * - * @param T the plugin convention type. - * @param configuration the configuration block. - * @see [Convention.getPlugin] - */ -inline fun Project.configure(noinline configuration: T.() -> Unit): Unit = - typeOf().let { type -> - convention.findByType(type)?.let(configuration) - ?: convention.findPlugin()?.let(configuration) - ?: convention.configure(type, configuration) - } - - -/** - * Returns the plugin convention or extension of the specified type. - */ -inline fun Project.the(): T = - typeOf().let { type -> - convention.findByType(type) - ?: convention.findPlugin(T::class.java) - ?: convention.getByType(type) - } - - -/** - * Returns the plugin convention or extension of the specified type. - */ -fun Project.the(extensionType: KClass): T = - convention.findByType(extensionType.java) - ?: convention.findPlugin(extensionType.java) - ?: convention.getByType(extensionType.java) - - -/** - * Creates a [Task] with the given [name] and [type], configures it with the given [configuration] action, - * and adds it to this project tasks container. - */ -inline fun Project.task(name: String, noinline configuration: type.() -> Unit) = - task(name, type::class, configuration) - - -/** - * Creates a [Task] with the given [name] and [type], and adds it to this project tasks container. - * - * @see [Project.getTasks] - * @see [TaskContainer.create] - */ -@Suppress("extension_shadowed_by_member") -inline fun Project.task(name: String) = - tasks.create(name, type::class.java) - - -fun Project.task(name: String, type: KClass, configuration: T.() -> Unit) = - createTask(name, type, configuration) - - -/** - * Creates a [Task] with the given [name] and [DefaultTask] type, configures it with the given [configuration] action, - * and adds it to this project tasks container. - */ -fun Project.task(name: String, configuration: Task.() -> Unit): DefaultTask = - createTask(name, DefaultTask::class, configuration) - - -fun Project.createTask(name: String, type: KClass, configuration: T.() -> Unit): T = - tasks.create(name, type.java, configuration) - - -/** - * Configures the repositories for this project. - * - * Executes the given configuration block against the [RepositoryHandler] for this - * project. - * - * @param configuration the configuration block. - */ -fun Project.repositories(configuration: RepositoryHandler.() -> Unit) = - repositories.configuration() - - -fun ScriptHandler.repositories(configuration: RepositoryHandler.() -> Unit) = - repositories.configuration() - - -/** - * Configures the dependencies for this project. - * - * Executes the given configuration block against the [DependencyHandlerScope] for this - * project. - * - * @param configuration the configuration block. - */ -fun Project.dependencies(configuration: DependencyHandlerScope.() -> Unit) = - DependencyHandlerScope(dependencies).configuration() - - -/** - * Locates a property on [Project]. - */ -operator fun Project.provideDelegate(any: Any?, property: KProperty<*>): PropertyDelegate = - propertyDelegateFor(this, property) - - -/** - * Creates a [Property] that holds values of the given type [T]. - * - * @see [ObjectFactory.property] - */ -@Incubating -inline fun ObjectFactory.property(): Property = - property(T::class.java) - - -/** - * Creates a [ListProperty] that holds values of the given type [T]. - * - * @see [ObjectFactory.listProperty] - */ -@Incubating -inline fun ObjectFactory.listProperty(): ListProperty = - listProperty(T::class.java) - - -/** - * Creates a [PropertyState] that holds values of the given type [T]. - * - * @see [Project.property] - */ -@Incubating -@Deprecated("Will be removed in 1.0", replaceWith = ReplaceWith("objects.property()")) -inline fun Project.property(): PropertyState = - property(T::class.java) - - -/** - * Creates a dependency on the API of the current version of the Gradle Kotlin DSL. - * - * Includes the Kotlin and Gradle APIs. - * - * @return The dependency. - */ -fun Project.gradleKotlinDsl(): Dependency = - DefaultSelfResolvingDependency( - fileCollectionOf( - gradleKotlinDslOf(project), - "gradleKotlinDsl") as FileCollectionInternal) - - -@Deprecated("Will be removed in 1.0", ReplaceWith("gradleKotlinDsl()")) -fun Project.gradleScriptKotlinApi(): Dependency = - gradleKotlinDsl() - - -private -fun fileCollectionOf(files: Collection, name: String): FileCollection = - DefaultFileCollectionFactory().fixed(name, files) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/PropertyDelegate.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/PropertyDelegate.kt (revision 3dc44dc66008a26b3ec2d68c6c69aecf61b592d3) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/PropertyDelegate.kt (revision 0) @@ -1,83 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.InvalidUserCodeException -import org.gradle.api.internal.DynamicObjectAware -import org.gradle.api.internal.plugins.DslObject - -import org.gradle.internal.Cast.uncheckedCast -import org.gradle.internal.metaobject.DynamicObject - -import kotlin.reflect.KProperty - - -/** - * Provides efficient access to a property. - */ -interface PropertyDelegate { - operator fun getValue(receiver: Any?, property: KProperty<*>): T -} - - -/** - * Provides efficient access to a mutable dynamic property. - */ -interface MutablePropertyDelegate : PropertyDelegate { - operator fun setValue(receiver: Any?, property: KProperty<*>, value: T) -} - - -internal -fun propertyDelegateFor(target: Any, property: KProperty<*>): PropertyDelegate = - dynamicObjectFor(target).let { owner -> - if (property.returnType.isMarkedNullable) NullableDynamicPropertyDelegate(owner, property.name) - else NonNullDynamicPropertyDelegate(owner, property.name, { target.toString() }) - } - - -private -fun dynamicObjectFor(target: Any): DynamicObject = - (target as? DynamicObjectAware ?: DslObject(target)).asDynamicObject - - -private -class NullableDynamicPropertyDelegate( - private val owner: DynamicObject, - private val name: String -) : PropertyDelegate { - - override fun getValue(receiver: Any?, property: KProperty<*>): T = - owner.tryGetProperty(name).run { - uncheckedCast(if (isFound) value else null) - } -} - - -private -class NonNullDynamicPropertyDelegate( - private val owner: DynamicObject, - private val name: String, - private val describeOwner: () -> String -) : PropertyDelegate { - - override fun getValue(receiver: Any?, property: KProperty<*>): T = - owner.tryGetProperty(name).run { - if (isFound && value != null) uncheckedCast(value) - else throw InvalidUserCodeException("Cannot get non-null property '$name' on ${describeOwner()} as it ${if (isFound) "is null" else "does not exist"}") - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/PropertyStateExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/PropertyStateExtensions.kt (revision 79fb412d2eb49f35ec7990872c5710fe66eb4b47) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/PropertyStateExtensions.kt (revision 0) @@ -1,56 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.provider.Property -import org.gradle.api.provider.PropertyState - -import kotlin.reflect.KProperty - - -/** - * Property delegate for [Property] instances. - * - * Example: `val someProperty by somePropertyState` - */ -operator fun Property.getValue(receiver: Any?, property: KProperty<*>): T = get() - - -/** - * Property delegate for [Property] instances. - * - * Example: `var someProperty by somePropertyState` - */ -operator fun Property.setValue(receiver: Any?, property: KProperty<*>, value: T) = set(value) - - -/** - * Property delegate for [PropertyState] instances. - * - * Example: `val someProperty by somePropertyState` - */ -@Deprecated("Will be removed in 1.0") -operator fun PropertyState.getValue(receiver: Any?, property: KProperty<*>): T = get() - - -/** - * Property delegate for [PropertyState] instances. - * - * Example: `var someProperty by somePropertyState` - */ -@Deprecated("Will be removed in 1.0") -operator fun PropertyState.setValue(receiver: Any?, property: KProperty<*>, value: T) = set(value) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/RepositoryHandlerExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/RepositoryHandlerExtensions.kt (revision 6b27df709ccd65c52ffac86c46c1fe5d67620d94) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/RepositoryHandlerExtensions.kt (revision 0) @@ -1,92 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.artifacts.dsl.RepositoryHandler -import org.gradle.api.artifacts.repositories.IvyArtifactRepository -import org.gradle.api.artifacts.repositories.MavenArtifactRepository - - -/** - * Adds and configures a Maven repository. - * - * The provided [url] value is evaluated as per [org.gradle.api.Project.uri]. This means, for example, you can pass in a `File` object, or a relative path to be evaluated relative - * to the project directory. - * - * @param url the base URL of this repository. This URL is used to find both POMs and artifact files. - * @return The added repository. - * - * @see [RepositoryHandler.maven] - * @see [MavenArtifactRepository.setUrl] - */ -fun RepositoryHandler.maven(url: Any) = - maven { it.setUrl(url) } - - -/** - * Adds and configures a Maven repository. - * - * The provided [url] value is evaluated as per [org.gradle.api.Project.uri]. This means, for example, you can pass in a `File` object, or a relative path to be evaluated relative - * to the project directory. - * - * @param url The base URL of this repository. This URL is used to find both POMs and artifact files. - * @param action The action to use to configure the repository. - * @return The added repository. - * - * @see [RepositoryHandler.maven] - * @see [MavenArtifactRepository.setUrl] - */ -fun RepositoryHandler.maven(url: Any, action: MavenArtifactRepository.() -> Unit) = - maven { - it.setUrl(url) - it.action() - } - - -/** - * Adds and configures an Ivy repository. - * - * The provided [url] value is evaluated as per [org.gradle.api.Project.uri]. This means, for example, you can pass in a `File` object, or a relative path to be evaluated relative - * to the project directory. - * - * @param url The base URL of this repository. - * - * @return The added repository. - * - * @see [RepositoryHandler.ivy] - */ -fun RepositoryHandler.ivy(url: Any) = - ivy { it.setUrl(url) } - - -/** - * Adds and configures an Ivy repository. - * - * The provided [url] value is evaluated as per [org.gradle.api.Project.uri]. This means, for example, you can pass in a `File` object, or a relative path to be evaluated relative - * to the project directory. - * - * @param url The base URL of this repository. - * @param action The action to use to configure the repository. - * - * @return The added repository. - * - * @see [RepositoryHandler.ivy] - */ -fun RepositoryHandler.ivy(url: Any, action: IvyArtifactRepository.() -> Unit) = - ivy { - it.setUrl(url) - it.action() - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/ScriptHandlerScope.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/ScriptHandlerScope.kt (revision d866927e36deeda7e9e3266de843731cb4577477) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/ScriptHandlerScope.kt (revision 0) @@ -1,41 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl - -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.dsl.DependencyHandler - -import org.gradle.api.initialization.dsl.ScriptHandler -import org.gradle.api.initialization.dsl.ScriptHandler.CLASSPATH_CONFIGURATION - - -/** - * Receiver for the `buildscript` block. - */ -class ScriptHandlerScope(scriptHandler: ScriptHandler) : ScriptHandler by scriptHandler { - - /** - * The dependencies of the script. - */ - val dependencies = DependencyHandlerScope(scriptHandler.dependencies) - - /** - * Adds a dependency to the script classpath. - */ - fun DependencyHandler.classpath(dependencyNotation: Any): Dependency? = - add(CLASSPATH_CONFIGURATION, dependencyNotation) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/SettingsExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/SettingsExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/SettingsExtensions.kt (revision 0) @@ -1,42 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.Plugin -import org.gradle.api.initialization.Settings -import org.gradle.api.plugins.PluginAware - -import kotlin.reflect.KProperty - - -/** - * Applies the plugin of the given type [T]. Does nothing if the plugin has already been applied. - * - * The given class should implement the [Plugin] interface, and be parameterized for a - * compatible type of `this`. - * - * @param T the plugin type. - * @see [PluginAware.apply] - */ -inline fun > Settings.apply() = - (this as PluginAware).apply() - - -/** - * Locates a property on [Settings]. - */ -operator fun Settings.provideDelegate(any: Any?, property: KProperty<*>): PropertyDelegate = - propertyDelegateFor(this, property) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/SpecExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/SpecExtensions.kt (revision ef3f20787f09a560b3bb6de4edfd74cde7790089) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/SpecExtensions.kt (revision 0) @@ -1,27 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.specs.Spec - - -/** - * Enables function invocation syntax on [Spec] instances. - * - * @see Spec.isSatisfiedBy - */ -operator fun Spec.invoke(arg: T): Boolean = - isSatisfiedBy(arg) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/TaskContainerExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/TaskContainerExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/TaskContainerExtensions.kt (revision 0) @@ -1,27 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.Task -import org.gradle.api.tasks.TaskContainer - - -/** - * Creates a [Task] with the given [name] and type, passing the given arguments to the [javax.inject.Inject]-annotated constructor, - * and adds it to this project tasks container. - */ -inline fun TaskContainer.create(name: String, vararg arguments: Any) = - create(name, T::class.java, *arguments) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/TypeOfExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/TypeOfExtensions.kt (revision ef43a668aa585154de136afbccd3add5bd619731) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/TypeOfExtensions.kt (revision 0) @@ -1,28 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl - -import org.gradle.api.reflect.TypeOf - - -/** - * Creates an instance of [TypeOf] for the given parameterized type. - * - * @param T the type - * @return the [TypeOf] that captures the generic type of the given parameterized type - */ -inline fun typeOf(): TypeOf = - object : TypeOf() {} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/AccessorsClassPath.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/AccessorsClassPath.kt (revision f40d46afc43f067c03373c67ed4e060319edf2c5) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/AccessorsClassPath.kt (revision 0) @@ -1,559 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.accessors - -import org.gradle.api.Project -import org.gradle.api.internal.project.ProjectInternal -import org.gradle.api.reflect.TypeOf - -import org.gradle.cache.internal.CacheKeyBuilder.CacheKeySpec - -import org.gradle.internal.classpath.ClassPath -import org.gradle.internal.classpath.DefaultClassPath - -import org.gradle.kotlin.dsl.cache.ScriptCache -import org.gradle.kotlin.dsl.codegen.fileHeader -import org.gradle.kotlin.dsl.support.compileToJar -import org.gradle.kotlin.dsl.support.loggerFor -import org.gradle.kotlin.dsl.support.serviceOf - -import org.jetbrains.kotlin.metadata.ProtoBuf -import org.jetbrains.kotlin.metadata.ProtoBuf.Visibility -import org.jetbrains.kotlin.metadata.deserialization.Flags -import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil - -import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult - -import org.jetbrains.org.objectweb.asm.AnnotationVisitor -import org.jetbrains.org.objectweb.asm.ClassReader -import org.jetbrains.org.objectweb.asm.ClassVisitor -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SYNTHETIC -import org.jetbrains.org.objectweb.asm.Opcodes.ASM6 -import org.jetbrains.org.objectweb.asm.signature.SignatureReader -import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor - -import java.io.BufferedWriter -import java.io.Closeable -import java.io.File - -import java.util.* -import java.util.jar.JarFile - - -fun accessorsClassPathFor(project: Project, classPath: ClassPath) = - project.getOrCreateSingletonProperty { - buildAccessorsClassPathFor(project, classPath) - ?: AccessorsClassPath.empty - } - - -data class AccessorsClassPath(val bin: ClassPath, val src: ClassPath) { - companion object { - val empty = AccessorsClassPath(ClassPath.EMPTY, ClassPath.EMPTY) - } -} - - -private -fun buildAccessorsClassPathFor(project: Project, classPath: ClassPath) = - configuredProjectSchemaOf(project)?.let { projectSchema -> - val cacheDir = - scriptCacheOf(project) - .cacheDirFor(cacheKeyFor(projectSchema)) { - buildAccessorsJarFor(projectSchema, classPath, outputDir = baseDir) - } - AccessorsClassPath( - DefaultClassPath.of(accessorsJar(cacheDir)), - DefaultClassPath.of(accessorsSourceDir(cacheDir))) - } - - -private -fun configuredProjectSchemaOf(project: Project) = - aotProjectSchemaOf(project) ?: jitProjectSchemaOf(project) - - -private -fun aotProjectSchemaOf(project: Project) = - project - .rootProject - .getOrCreateSingletonProperty { multiProjectSchemaSnapshotOf(project) } - .schema - ?.let { it[project.path] } - - -private -fun jitProjectSchemaOf(project: Project) = - project.takeIf(::enabledJitAccessors)?.let { - require(classLoaderScopeOf(project).isLocked) { - "project.classLoaderScope must be locked before querying the project schema" - } - schemaFor(project).withKotlinTypeStrings() - } - - -internal -fun schemaFor(project: Project): ProjectSchema> = - projectSchemaProviderOf(project).schemaFor(project) - - -private -fun projectSchemaProviderOf(project: Project) = - project.serviceOf() - - -private -fun scriptCacheOf(project: Project) = project.serviceOf() - - -private -fun buildAccessorsJarFor(projectSchema: ProjectSchema, classPath: ClassPath, outputDir: File) { - val sourceFile = File(accessorsSourceDir(outputDir), "org/gradle/kotlin/dsl/accessors.kt") - val availableSchema = availableProjectSchemaFor(projectSchema, classPath) - writeAccessorsTo(sourceFile, availableSchema) - require(compileToJar(accessorsJar(outputDir), listOf(sourceFile), logger, classPath.asFiles), { - """ - Failed to compile accessors. - - projectSchema: $projectSchema - - classPath: $classPath - - availableSchema: $availableSchema - - """.replaceIndent() - }) -} - - -internal -fun availableProjectSchemaFor(projectSchema: ProjectSchema, classPath: ClassPath) = - TypeAccessibilityProvider(classPath).use { accessibilityProvider -> - projectSchema.map(accessibilityProvider::accessibilityForType) - } - - -sealed class TypeAccessibility { - data class Accessible(val type: String) : TypeAccessibility() - data class Inaccessible(val type: String, val reasons: List) : TypeAccessibility() -} - - -sealed class InaccessibilityReason { - - data class NonPublic(val type: String) : InaccessibilityReason() - data class NonAvailable(val type: String) : InaccessibilityReason() - data class Synthetic(val type: String) : InaccessibilityReason() - data class TypeErasure(val type: String) : InaccessibilityReason() - - val explanation - get() = when (this) { - is NonPublic -> "`$type` is not public" - is NonAvailable -> "`$type` is not available" - is Synthetic -> "`$type` is synthetic" - is TypeErasure -> "`$type` parameter types are missing" - } -} - - -private -typealias ClassFileIndex = (String) -> ByteArray? - - -private -data class TypeAccessibilityInfo( - val inaccessibilityReasons: List, - val hasTypeParameter: Boolean = false -) - - -internal -class TypeAccessibilityProvider(classPath: ClassPath) : Closeable { - - private - val classPathIndex = classPath.asFiles.map { classFileIndexFor(it) } - - private - val openJars = mutableMapOf() - - private - val typeAccessibilityInfoPerClass = mutableMapOf() - - fun accessibilityForType(type: String): TypeAccessibility = - inaccessibilityReasonsFor(classNamesFromTypeString(type)).let { inaccessibilityReasons -> - if (inaccessibilityReasons.isNotEmpty()) inaccessible(type, inaccessibilityReasons) - else accessible(type) - } - - private - fun inaccessibilityReasonsFor(classNames: ClassNamesFromTypeString): List = - classNames.all.flatMap { inaccessibilityReasonsFor(it) }.let { inaccessibilityReasons -> - if (inaccessibilityReasons.isNotEmpty()) inaccessibilityReasons - else classNames.leafs.filter { hasTypeParameter(it) }.map { typeErasure(it) } - } - - private - fun inaccessibilityReasonsFor(className: String): List = - accessibilityInfoFor(className).inaccessibilityReasons - - private - fun hasTypeParameter(className: String) = - accessibilityInfoFor(className).hasTypeParameter - - private - fun accessibilityInfoFor(className: String): TypeAccessibilityInfo = - typeAccessibilityInfoPerClass.computeIfAbsent(className) { - loadAccessibilityInfoFor(it) - } - - private - fun loadAccessibilityInfoFor(className: String): TypeAccessibilityInfo { - val classBytes = classBytesFor(className) ?: return TypeAccessibilityInfo(listOf(nonAvailable(className))) - val classReader = ClassReader(classBytes) - val access = classReader.access - return TypeAccessibilityInfo( - listOfNotNull( - when { - ACC_PUBLIC !in access -> nonPublic(className) - ACC_SYNTHETIC in access -> synthetic(className) - isNonPublicKotlinType(classReader) -> nonPublic(className) - else -> null - }), - hasTypeParameters(classReader) - ) - } - - private - fun isNonPublicKotlinType(classReader: ClassReader) = - kotlinVisibilityFor(classReader)?.let { it != Visibility.PUBLIC } ?: false - - private - fun kotlinVisibilityFor(classReader: ClassReader) = - classReader(KotlinVisibilityClassVisitor()).visibility - - private - fun hasTypeParameters(classReader: ClassReader): Boolean = - classReader(HasTypeParameterClassVisitor()).hasTypeParameters - - private - operator fun ClassReader.invoke(visitor: T): T = - visitor.also { - accept(it, ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES) - } - - private - fun classBytesFor(className: String): ByteArray? { - val classFilePath = className.replace(".", "/") + ".class" - return classPathIndex.firstNotNullResult { it(classFilePath) } - } - - private - fun classFileIndexFor(jarOrDir: File): ClassFileIndex = - when { - jarOrDir.isFile -> jarIndexFor(jarOrDir) - jarOrDir.isDirectory -> directoryIndexFor(jarOrDir) - else -> { _ -> null } - } - - private - fun jarIndexFor(file: File): ClassFileIndex = { classFilePath -> - openJarFile(file).run { - getJarEntry(classFilePath)?.let { jarEntry -> - getInputStream(jarEntry).use { jarInput -> - jarInput.readBytes() - } - } - } - } - - private - fun openJarFile(file: File) = - openJars.computeIfAbsent(file, ::JarFile) - - override fun close() { - openJars.values.forEach(JarFile::close) - } - - private - fun directoryIndexFor(baseDir: File): ClassFileIndex = { classFilePath -> - File(baseDir, classFilePath).takeIf { it.isFile }?.readBytes() - } -} - - -internal -class ClassNamesFromTypeString( - val all: List, - val leafs: List -) - - -internal -fun classNamesFromTypeString(typeString: String): ClassNamesFromTypeString { - - val all = mutableListOf() - val leafs = mutableListOf() - var buffer = StringBuilder() - - fun nonPrimitiveKotlinType(): String? = - if (buffer.isEmpty()) null - else buffer.toString().let { - if (it in primitiveKotlinTypeNames) null - else it - } - - typeString.forEach { char -> - when (char) { - '<' -> { - nonPrimitiveKotlinType()?.also { all.add(it) } - buffer = StringBuilder() - } - in " ,>" -> { - nonPrimitiveKotlinType()?.also { - all.add(it) - leafs.add(it) - } - buffer = StringBuilder() - } - else -> buffer.append(char) - } - } - nonPrimitiveKotlinType()?.also { - all.add(it) - leafs.add(it) - } - return ClassNamesFromTypeString(all, leafs) -} - - -private -class HasTypeParameterClassVisitor : ClassVisitor(ASM6) { - - var hasTypeParameters = false - - override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array?) { - if (signature != null) { - SignatureReader(signature).accept(object : SignatureVisitor(ASM6) { - override fun visitFormalTypeParameter(name: String) { - hasTypeParameters = true - } - }) - } - } -} - - -private -class KotlinVisibilityClassVisitor : ClassVisitor(ASM6) { - - var visibility: Visibility? = null - - override fun visitAnnotation(desc: String?, visible: Boolean): AnnotationVisitor? = - when (desc) { - "Lkotlin/Metadata;" -> ClassDataFromKotlinMetadataAnnotationVisitor { classData -> - visibility = Flags.VISIBILITY[classData.flags] - } - else -> null - } -} - - -/** - * Reads the serialized [ProtoBuf.Class] information stored in the visited [kotlin.Metadata] annotation. - */ -private -class ClassDataFromKotlinMetadataAnnotationVisitor( - private val onClassData: (ProtoBuf.Class) -> Unit -) : AnnotationVisitor(ASM6) { - - /** - * @see kotlin.Metadata.d1 - */ - private - var d1 = mutableListOf() - - /** - * @see kotlin.Metadata.d2 - */ - private - var d2 = mutableListOf() - - override fun visitArray(name: String?): AnnotationVisitor? = - when (name) { - "d1" -> AnnotationValueCollector(d1) - "d2" -> AnnotationValueCollector(d2) - else -> null - } - - override fun visitEnd() { - val (_, classData) = JvmProtoBufUtil.readClassDataFrom(d1.toTypedArray(), d2.toTypedArray()) - onClassData(classData) - super.visitEnd() - } -} - - -private -class AnnotationValueCollector(val output: MutableList) : AnnotationVisitor(ASM6) { - override fun visit(name: String?, value: Any?) { - @Suppress("unchecked_cast") - output.add(value as T) - } -} - - -private -operator fun Int.contains(flag: Int) = - and(flag) == flag - - -internal -fun nonAvailable(type: String): InaccessibilityReason = - InaccessibilityReason.NonAvailable(type) - - -internal -fun nonPublic(type: String): InaccessibilityReason = - InaccessibilityReason.NonPublic(type) - - -internal -fun synthetic(type: String): InaccessibilityReason = - InaccessibilityReason.Synthetic(type) - - -internal -fun typeErasure(type: String): InaccessibilityReason = - InaccessibilityReason.TypeErasure(type) - - -internal -fun accessible(type: String): TypeAccessibility = - TypeAccessibility.Accessible(type) - - -internal -fun inaccessible(type: String, vararg reasons: InaccessibilityReason) = - inaccessible(type, reasons.toList()) - - -internal -fun inaccessible(type: String, reasons: List): TypeAccessibility = - TypeAccessibility.Inaccessible(type, reasons) - - -private -val logger by lazy { loggerFor() } - - -private -fun accessorsSourceDir(baseDir: File) = File(baseDir, "src") - - -private -fun accessorsJar(baseDir: File) = File(baseDir, "gradle-kotlin-dsl-accessors.jar") - - -private -fun multiProjectSchemaSnapshotOf(project: Project) = - MultiProjectSchemaSnapshot( - projectSchemaSnapshotFileOf(project)?.let { - loadMultiProjectSchemaFrom(it) - }) - - -private -data class MultiProjectSchemaSnapshot(val schema: Map>?) - - -private -fun projectSchemaSnapshotFileOf(project: Project): File? = - project - .rootProject - .file(PROJECT_SCHEMA_RESOURCE_PATH) - .takeIf { it.isFile } - - -private -fun classLoaderScopeOf(project: Project) = - (project as ProjectInternal).classLoaderScope - - -private -fun cacheKeyFor(projectSchema: ProjectSchema): CacheKeySpec = - CacheKeySpec.withPrefix("gradle-kotlin-dsl-accessors") + projectSchema.toCacheKeyString() - - -private -fun ProjectSchema.toCacheKeyString(): String = - (extensions.associateBy { "${it.target}.${it.name}" }.mapValues { it.value.type }.asSequence() - + conventions.associateBy { "${it.target}.${it.name}" }.mapValues { it.value.type }.asSequence() - + mapEntry("configuration", configurations.sorted().joinToString(","))) - .map { "${it.key}=${it.value}" } - .sorted() - .joinToString(separator = ":") - - -private -fun mapEntry(key: K, value: V) = - AbstractMap.SimpleEntry(key, value) - - -private -fun enabledJitAccessors(project: Project) = - project.findProperty("org.gradle.kotlin.dsl.accessors")?.let { - it != "false" && it != "off" - } ?: true - - -private -fun writeAccessorsTo(outputFile: File, projectSchema: ProjectSchema): File = - outputFile.apply { - parentFile.mkdirs() - bufferedWriter().use { writer -> - writeAccessorsFor(projectSchema, writer) - } - } - - -private -fun writeAccessorsFor(projectSchema: ProjectSchema, 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) - } - } -} - - -/** - * Location of the project schema snapshot taken by the _kotlinDslAccessorsSnapshot_ task relative to the root project. - */ -const val PROJECT_SCHEMA_RESOURCE_PATH = "gradle/project-schema.json" Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/CodeGenerator.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/CodeGenerator.kt (revision f40d46afc43f067c03373c67ed4e060319edf2c5) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/CodeGenerator.kt (revision 0) @@ -1,341 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.accessors - -import org.gradle.api.internal.HasConvention -import org.gradle.api.plugins.ExtensionAware - -import org.jetbrains.kotlin.lexer.KotlinLexer -import org.jetbrains.kotlin.lexer.KtTokens - - -internal -fun ProjectSchema.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) - } -} - - -private -data class SeenAccessorSpecs(private val seen: MutableList = mutableListOf()) { - - fun add(accessorSpec: TypedAccessorSpec) = - seen.add(accessorSpec) - - fun hasConflict(accessorSpec: TypedAccessorSpec) = - seen.any { it.targetTypeAccess == accessorSpec.targetTypeAccess && it.name == accessorSpec.name } -} - - -private -fun extensionAccessorFor(spec: TypedAccessorSpec): String? = spec.run { - codeForAccessor(name) { - when (typeAccess) { - is TypeAccessibility.Accessible -> accessibleExtensionAccessorFor(targetTypeAccess.type, name, typeAccess.type) - is TypeAccessibility.Inaccessible -> inaccessibleExtensionAccessorFor(targetTypeAccess.type, name, typeAccess) - } - } -} - - -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) - - """ -} - - -private -fun inaccessibleExtensionAccessorFor(targetType: String, name: AccessorNameSpec, typeAccess: TypeAccessibility.Inaccessible): String = name.run { - """ - /** - * Retrieves the [$original][${typeAccess.type}] extension. - * - * ${documentInaccessibilityReasons(name, typeAccess)} - */ - val $targetType.`$kotlinIdentifier`: Any get() = - $thisExtensions.getByName("$stringLiteral") - - /** - * Configures the [$original][${typeAccess.type}] extension. - * - * ${documentInaccessibilityReasons(name, typeAccess)} - */ - fun $targetType.`$kotlinIdentifier`(configure: Any.() -> Unit): Unit = - $thisExtensions.configure("$stringLiteral", configure) - - """ -} - - -private -fun conventionAccessorFor(spec: TypedAccessorSpec): String? = spec.run { - codeForAccessor(name) { - when (typeAccess) { - is TypeAccessibility.Accessible -> accessibleConventionAccessorFor(targetTypeAccess.type, name, typeAccess.type) - is TypeAccessibility.Inaccessible -> inaccessibleConventionAccessorFor(targetTypeAccess.type, name, typeAccess) - } - } -} - - -private -fun accessibleConventionAccessorFor(targetType: String, name: AccessorNameSpec, type: String): String = name.run { - """ - /** - * Retrieves the [$original][$type] convention. - */ - val $targetType.`$kotlinIdentifier`: $type get() = - $thisConvention.getPluginByName<$type>("$stringLiteral") - - /** - * Configures the [$original][$type] convention. - */ - fun $targetType.`$kotlinIdentifier`(configure: $type.() -> Unit): Unit = - configure(`$stringLiteral`) - - """ -} - - -private -fun inaccessibleConventionAccessorFor(targetType: String, name: AccessorNameSpec, typeAccess: TypeAccessibility.Inaccessible): String = name.run { - """ - /** - * Retrieves the [$original][${typeAccess.type}] convention. - * - * ${documentInaccessibilityReasons(name, typeAccess)} - */ - val $targetType.`$kotlinIdentifier`: Any get() = - $thisConvention.getPluginByName("$stringLiteral") - - /** - * Configures the [$original][${typeAccess.type}] convention. - * - * ${documentInaccessibilityReasons(name, typeAccess)} - */ - fun $targetType.`$kotlinIdentifier`(configure: Any.() -> Unit): Unit = - configure(`$stringLiteral`) - - """ -} - - -private -fun configurationAccessorFor(name: AccessorNameSpec): String? = name.run { - codeForAccessor(name) { - """ - /** - * The '$original' configuration. - */ - val ConfigurationContainer.`$kotlinIdentifier`: Configuration - get() = getByName("$stringLiteral") - - /** - * Adds a dependency to the '$original' configuration. - * - * @param dependencyNotation notation for the dependency to be added. - * @return The dependency. - * - * @see [DependencyHandler.add] - */ - fun DependencyHandler.`$kotlinIdentifier`(dependencyNotation: Any): Dependency? = - add("$stringLiteral", dependencyNotation) - - /** - * Adds a dependency to the '$original' configuration. - * - * @param dependencyNotation notation for the dependency to be added. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * - * @see [DependencyHandler.add] - */ - inline fun DependencyHandler.`$kotlinIdentifier`( - dependencyNotation: String, - dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency = - add("$stringLiteral", dependencyNotation, dependencyConfiguration) - - /** - * Adds a dependency to the '$original' configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * @return The dependency. - * - * @see [DependencyHandler.add] - */ - fun DependencyHandler.`$kotlinIdentifier`( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null): ExternalModuleDependency = - create(group, name, version, configuration, classifier, ext).apply { add("$stringLiteral", this) } - - /** - * Adds a dependency to the '$original' configuration. - * - * @param group the group of the module to be added as a dependency. - * @param name the name of the module to be added as a dependency. - * @param version the optional version of the module to be added as a dependency. - * @param configuration the optional configuration of the module to be added as a dependency. - * @param classifier the optional classifier of the module artifact to be added as a dependency. - * @param ext the optional extension of the module artifact to be added as a dependency. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * - * @see [DependencyHandler.create] - * @see [DependencyHandler.add] - */ - inline fun DependencyHandler.`$kotlinIdentifier`( - group: String, - name: String, - version: String? = null, - configuration: String? = null, - classifier: String? = null, - ext: String? = null, - dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency = - add("$stringLiteral", create(group, name, version, configuration, classifier, ext), dependencyConfiguration) - - /** - * Adds a dependency to the '$original' configuration. - * - * @param dependency dependency to be added. - * @param dependencyConfiguration expression to use to configure the dependency. - * @return The dependency. - * - * @see [DependencyHandler.add] - */ - inline fun DependencyHandler.`$kotlinIdentifier`(dependency: T, dependencyConfiguration: T.() -> Unit): T = - add("$stringLiteral", dependency, dependencyConfiguration) - - """ - } -} - - -private -val thisExtensions = - "(this as ${ExtensionAware::class.java.name}).extensions" - - -private -val thisConvention = - "((this as? Project)?.convention ?: (this as ${HasConvention::class.java.name}).convention)" - - -internal -data class AccessorNameSpec(val original: String) { - - val kotlinIdentifier - get() = original - - val stringLiteral by lazy { stringLiteralFor(original) } -} - - -private -data class TypedAccessorSpec(val targetTypeAccess: TypeAccessibility.Accessible, val name: AccessorNameSpec, val typeAccess: TypeAccessibility) - - -private -fun stringLiteralFor(original: String) = - escapeStringTemplateDollarSign(original) - - -private -fun escapeStringTemplateDollarSign(string: String) = - string.replace("${'$'}", "${'$'}{'${'$'}'}") - - -private -fun accessorNameSpec(originalName: String) = - AccessorNameSpec(originalName) - - -private -fun typedAccessorSpec(schemaEntry: ProjectSchemaEntry) = - schemaEntry.target.run { - when (this) { - is TypeAccessibility.Accessible -> - TypedAccessorSpec(this, accessorNameSpec(schemaEntry.name), schemaEntry.type) - is TypeAccessibility.Inaccessible -> - null - } - } - - -private -fun documentInaccessibilityReasons(name: AccessorNameSpec, typeAccess: TypeAccessibility.Inaccessible): String = - "`${name.kotlinIdentifier}` is not accessible in a type safe way because:\n${typeAccess.reasons.joinToString("\n") { reason -> - " * - ${reason.explanation}" - }}" - - -private -inline fun codeForAccessor(name: AccessorNameSpec, code: () -> String): String? = - if (isLegalAccessorName(name.kotlinIdentifier)) code().replaceIndent() - else null - - -internal -fun isLegalAccessorName(name: String): Boolean = - isKotlinIdentifier("`$name`") - && name.indexOfAny(invalidNameChars) < 0 - - -private -val invalidNameChars = charArrayOf('.', '/', '\\') - - -private -fun isKotlinIdentifier(candidate: String): Boolean = - KotlinLexer().run { - start(candidate) - tokenStart == 0 - && tokenEnd == candidate.length - && tokenType == KtTokens.IDENTIFIER - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/KotlinTypeStrings.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/KotlinTypeStrings.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/KotlinTypeStrings.kt (revision 0) @@ -1,59 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.accessors - -import org.gradle.api.reflect.TypeOf - - -fun kotlinTypeStringFor(type: TypeOf<*>): String = type.run { - when { - isArray -> - "Array<${kotlinTypeStringFor(componentType!!)}>" - isParameterized -> - "$parameterizedTypeDefinition<${actualTypeArguments.joinToString(transform = ::kotlinTypeStringFor)}>" - isWildcard -> - upperBound?.let(::kotlinTypeStringFor) ?: "Any" - else -> - toString().let { primitiveTypeStrings[it] ?: it } - } -} - - -private -val primitiveTypeStrings = - mapOf( - "java.lang.Object" to "Any", - "java.lang.String" to "String", - "java.lang.Character" to "Char", - "char" to "Char", - "java.lang.Boolean" to "Boolean", - "boolean" to "Boolean", - "java.lang.Byte" to "Byte", - "byte" to "Byte", - "java.lang.Short" to "Short", - "short" to "Short", - "java.lang.Integer" to "Int", - "int" to "Int", - "java.lang.Long" to "Long", - "long" to "Long", - "java.lang.Float" to "Float", - "float" to "Float", - "java.lang.Double" to "Double", - "double" to "Double") - - -val primitiveKotlinTypeNames = primitiveTypeStrings.values.toHashSet() Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaProvider.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaProvider.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaProvider.kt (revision 0) @@ -1,100 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.accessors - -import groovy.json.JsonOutput -import groovy.json.JsonSlurper - -import org.gradle.api.Project -import org.gradle.api.reflect.TypeOf - -import java.io.File -import java.io.Serializable - - -interface ProjectSchemaProvider { - - fun schemaFor(project: Project): ProjectSchema> - - fun multiProjectSchemaFor(root: Project): Map>> = - root.allprojects.map { it.path to schemaFor(it) }.toMap() -} - - -data class ProjectSchema( - val extensions: List>, - val conventions: List>, - val configurations: List -) : Serializable { - - fun map(f: (T) -> U) = - ProjectSchema( - extensions.map { it.map(f) }, - conventions.map { it.map(f) }, - configurations.toList()) -} - - -data class ProjectSchemaEntry( - val target: T, - val name: String, - val type: T -) : Serializable { - - fun map(f: (T) -> U) = - ProjectSchemaEntry(f(target), name, f(type)) -} - - -fun ProjectSchema>.withKotlinTypeStrings() = - map(::kotlinTypeStringFor) - - -fun toJson(multiProjectStringSchema: Map>): String = - JsonOutput.toJson(multiProjectStringSchema) - - -@Suppress("unchecked_cast") -fun loadMultiProjectSchemaFrom(file: File) = - (JsonSlurper().parse(file) as Map>).mapValues { (_, value) -> - ProjectSchema( - extensions = loadSchemaEntryListFrom(value["extensions"]), - conventions = loadSchemaEntryListFrom(value["conventions"]), - configurations = value["configurations"] as? List ?: emptyList()) - } - - -@Suppress("unchecked_cast") -private -fun loadSchemaEntryListFrom(extensions: Any?): List> = - when (extensions) { - is Map<*, *> -> // <0.17 format - (extensions as? Map)?.map { - ProjectSchemaEntry( - Project::class.java.name, - it.key, - it.value) - } ?: emptyList() - is List<*> -> // >=0.17 format - (extensions as? List>)?.map { - ProjectSchemaEntry( - it.getValue("target"), - it.getValue("name"), - it.getValue("type")) - } ?: emptyList() - else -> emptyList() - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/SingletonProperties.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/SingletonProperties.kt (revision 05c6e9e4957fa24d056555a5b6a10c9499bed582) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/SingletonProperties.kt (revision 0) @@ -1,30 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.accessors - -import org.gradle.api.plugins.ExtensionAware - -import org.gradle.kotlin.dsl.extra - - -internal -inline fun ExtensionAware.getOrCreateSingletonProperty(crossinline create: () -> T): T = - extra.run { - val property = T::class.qualifiedName!! - if (has(property)) get(property) as T - else create().also { set(property, it) } - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/tasks/PrintAccessors.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/tasks/PrintAccessors.kt (revision f40d46afc43f067c03373c67ed4e060319edf2c5) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/tasks/PrintAccessors.kt (revision 0) @@ -1,49 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.accessors.tasks - -import org.gradle.api.DefaultTask -import org.gradle.api.tasks.TaskAction - -import org.gradle.kotlin.dsl.accessors.accessible -import org.gradle.kotlin.dsl.accessors.forEachAccessor -import org.gradle.kotlin.dsl.accessors.ProjectSchemaProvider -import org.gradle.kotlin.dsl.accessors.withKotlinTypeStrings -import org.gradle.kotlin.dsl.support.serviceOf - - -open class PrintAccessors : DefaultTask() { - - init { - group = "help" - description = "Prints the Kotlin code for accessing the currently available project extensions and conventions." - } - - @Suppress("unused") - @TaskAction - fun printExtensions() { - projectSchemaProvider.schemaFor(project).withKotlinTypeStrings().map(::accessible).forEachAccessor { - println() - println(it) - println() - } - } - - private - val projectSchemaProvider: ProjectSchemaProvider - get() = project.serviceOf() -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/tasks/UpdateProjectSchema.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/tasks/UpdateProjectSchema.kt (revision f40d46afc43f067c03373c67ed4e060319edf2c5) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/accessors/tasks/UpdateProjectSchema.kt (revision 0) @@ -1,63 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.accessors.tasks - -import groovy.json.JsonOutput.prettyPrint - -import org.gradle.api.DefaultTask -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -import org.gradle.kotlin.dsl.accessors.PROJECT_SCHEMA_RESOURCE_PATH -import org.gradle.kotlin.dsl.accessors.ProjectSchemaProvider -import org.gradle.kotlin.dsl.accessors.toJson -import org.gradle.kotlin.dsl.accessors.withKotlinTypeStrings -import org.gradle.kotlin.dsl.support.serviceOf - -import java.io.File - - -open class UpdateProjectSchema : DefaultTask() { - - init { - group = "Build Setup" - description = "Generates Kotlin accessors for accessing and configuring the currently available project extensions and conventions." - } - - @Suppress("unused") - @Input - fun getSchemaInput(): Map = schema - - @get:OutputFile - var destinationFile: File = project.file(PROJECT_SCHEMA_RESOURCE_PATH) - - private - val schema by lazy { - projectSchemaProvider.multiProjectSchemaFor(project).mapValues { it.value.withKotlinTypeStrings() } - } - - @Suppress("unused") - @TaskAction - fun generateProjectSchema() { - destinationFile.writeText(prettyPrint(toJson(schema))) - } - - private - val projectSchemaProvider: ProjectSchemaProvider - get() = project.serviceOf() -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/cache/BuildServices.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/cache/BuildServices.kt (revision e1a19b2b552fd1dc08d0455b7def529e5ee670fc) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/cache/BuildServices.kt (revision 0) @@ -1,37 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.cache - -import org.gradle.StartParameter - -import org.gradle.cache.CacheRepository -import org.gradle.cache.internal.CacheKeyBuilder - - -internal -object BuildServices { - - @Suppress("unused") - fun createScriptCache( - cacheKeyBuilder: CacheKeyBuilder, - cacheRepository: CacheRepository, - startParameters: StartParameter - ) = - - ScriptCache( - cacheRepository, cacheKeyBuilder, startParameters.isRecompileScripts) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/cache/ScriptCache.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/cache/ScriptCache.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/cache/ScriptCache.kt (revision 0) @@ -1,65 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.cache - -import org.gradle.cache.CacheRepository -import org.gradle.cache.PersistentCache - -import org.gradle.cache.internal.CacheKeyBuilder -import org.gradle.cache.internal.CacheKeyBuilder.CacheKeySpec - -import java.io.File - - -internal -class ScriptCache( - - private - val cacheRepository: CacheRepository, - - private - val cacheKeyBuilder: CacheKeyBuilder, - - private - val recompileScripts: Boolean -) { - - fun cacheDirFor( - keySpec: CacheKeySpec, - properties: Map? = null, - scope: Any? = null, - initializer: PersistentCache.() -> Unit - ): File = - - cacheRepository - .cache(scope, cacheKeyFor(keySpec)) - .apply { properties?.let { withProperties(it) } } - .apply { if (recompileScripts) withValidator { false } } - .withInitializer(initializer) - .open().run { - close() - baseDir - } - - private - fun cacheKeyFor(spec: CacheKeySpec) = cacheKeyBuilder.build(spec) -} - - -internal -operator fun CacheKeySpec.plus(files: List) = - files.fold(this, CacheKeySpec::plus) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/ApiExtensionsJar.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/ApiExtensionsJar.kt (revision e1a19b2b552fd1dc08d0455b7def529e5ee670fc) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/ApiExtensionsJar.kt (revision 0) @@ -1,95 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.codegen - -import org.gradle.kotlin.dsl.support.loggerFor -import org.gradle.kotlin.dsl.support.compileToDirectory -import org.gradle.kotlin.dsl.support.zipTo - -import java.io.File - - -internal -fun generateApiExtensionsJar(outputFile: File, gradleJars: Collection, onProgress: () -> Unit) { - ApiExtensionsJarGenerator(onProgress = onProgress).generate(outputFile, gradleJars) -} - - -internal -interface KotlinFileCompiler { - fun compileToDirectory(outputDirectory: File, sourceFiles: Collection, classPath: Collection) -} - - -internal -class ApiExtensionsJarGenerator( - val compiler: KotlinFileCompiler = StandardKotlinFileCompiler, - val onProgress: () -> Unit = {} -) { - - fun generate(outputFile: File, gradleJars: Collection = emptyList()) { - val tempDir = tempDirFor(outputFile) - compileExtensionsTo(tempDir, gradleJars) - zipTo(outputFile, tempDir) - } - - private - fun tempDirFor(outputFile: File): File = - createTempDir(outputFile.nameWithoutExtension, outputFile.extension).apply { - deleteOnExit() - } - - private - fun compileExtensionsTo(outputDir: File, gradleJars: Collection) { - compiler.compileToDirectory( - outputDir, - listOf(builtinPluginIdExtensionsSourceFileFor(gradleJars, outputDir)), - classPath = gradleJars) - } - - private - fun builtinPluginIdExtensionsSourceFileFor(gradleJars: Iterable, outputDir: File) = - generatedSourceFile(outputDir, "BuiltinPluginIdExtensions.kt").apply { - writeBuiltinPluginIdExtensionsTo(this, gradleJars) - onProgress() - } - - private - fun generatedSourceFile(outputDir: File, fileName: String) = - File(outputDir, sourceFileName(fileName)).apply { - parentFile.mkdirs() - } - - private - fun sourceFileName(fileName: String) = - packageDir + "/" + fileName - - private - val packageDir = packageName.replace('.', '/') -} - - -internal -object StandardKotlinFileCompiler : KotlinFileCompiler { - override fun compileToDirectory(outputDirectory: File, sourceFiles: Collection, classPath: Collection) { - compileToDirectory( - outputDirectory, - sourceFiles, - loggerFor(), - classPath = classPath) - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/Constants.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/Constants.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/Constants.kt (revision 0) @@ -1,47 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.codegen - - -internal -val fileHeader: String - get() = """$licenseHeader - -package $packageName -""" - - -internal -const val packageName = "org.gradle.kotlin.dsl" - - -internal -const val licenseHeader = """/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */""" Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/PluginIdExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/PluginIdExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/PluginIdExtensions.kt (revision 0) @@ -1,260 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.codegen - -import org.gradle.plugin.use.PluginDependenciesSpec -import org.gradle.plugin.use.PluginDependencySpec - -import java.io.File - -import java.util.Properties -import java.util.jar.JarFile - - -internal -fun writeBuiltinPluginIdExtensionsTo(file: File, gradleJars: Iterable) { - file.bufferedWriter().use { - it.apply { - write(fileHeader) - write("\n") - write("import ${PluginDependenciesSpec::class.qualifiedName}\n") - write("import ${PluginDependencySpec::class.qualifiedName}\n") - pluginIdExtensionDeclarationsFor(gradleJars).forEach { - write("\n") - write(it) - write("\n") - } - } - } -} - - -private -fun pluginIdExtensionDeclarationsFor(jars: Iterable): Sequence { - val extendedType = PluginDependenciesSpec::class.simpleName - val extensionType = PluginDependencySpec::class.simpleName - return pluginExtensionsFrom(jars) - .map { (memberName, pluginId, website, implementationClass) -> - """ - /** - * The builtin Gradle plugin implemented by [$implementationClass]. - * - * ${website?.let { "Visit the [plugin user guide]($it) for additional information." } ?: ""} - * - * @see $implementationClass - */ - inline val $extendedType.`$memberName`: $extensionType - get() = id("$pluginId") - """.replaceIndent() - } -} - - -private -data class PluginExtension( - val memberName: String, - val pluginId: String, - val website: String?, - val implementationClass: String -) - - -private -fun pluginExtensionsFrom(jars: Iterable): Sequence = - jars - .asSequence() - .filter { it.name.startsWith("gradle-") } - .flatMap(::pluginExtensionsFrom) - - -private -fun pluginExtensionsFrom(file: File): Sequence = - pluginEntriesFrom(file) - .asSequence() - .map { (id, implementationClass) -> - val simpleId = id.substringAfter("org.gradle.") - val website = UserGuideLink.forPlugin(simpleId) - // One plugin extension for the simple id, e.g., "application" - PluginExtension(simpleId, id, website, implementationClass) - } - - -internal -object UserGuideLink { - - fun forPlugin(simpleId: String): String? = - linkForPlugin[simpleId]?.let { - "https://docs.gradle.org/current/userguide/$it" - } - - private - val linkForPlugin = - mapOf( - "announce" to "announce_plugin.html", - "antlr" to "antlr_plugin.html", - "application" to "application_plugin.html", - - "assembler" to "native_software.html#assemblerPlugin", - "assembler-lang" to "native_software.html#assemblerPlugin", - - "base" to "standard_plugins.html#sec:base_plugins", - - "binary-base" to "software_model_concepts.html", - - "build-announcements" to "build_announcements_plugin.html", - "build-dashboard" to "buildDashboard_plugin.html", - - "build-init" to "build_init_plugin.html", - "c" to "native_software.html#sec:c_sources", - "c-lang" to "native_software.html#sec:c_sources", - - "checkstyle" to "checkstyle_plugin.html", - "clang-compiler" to "native_software.html", - - "codenarc" to "codenarc_plugin.html", - - // "coffeescript-base" to "coffeescript_base_plugin.html", - - "compare-gradle-builds" to "comparing_builds.html", - - "component-base" to "software_model_concepts.html", - "component-model-base" to "software_model_concepts.html", - - "cpp" to "native_software.html#cppPlugin", - "cpp-executable" to "native_software.html#cppPlugin", - "cpp-lang" to "native_software.html#cppPlugin", - "cpp-library" to "native_software.html#cppPlugin", - - "cunit" to "native_software.html#native_binaries:cunit", - "cunit-test-suite" to "native_software.html#native_binaries:cunit", - - "distribution" to "distribution_plugin.html", - "ear" to "ear_plugin.html", - "eclipse" to "eclipse_plugin.html", - "eclipse-wtp" to "eclipse_plugin.html", - - // "envjs" to "envjs_plugin.html", - - "findbugs" to "findbugs_plugin.html", - - "gcc-compiler" to "native_software.html#native_binaries:tool_chain", - - "google-test" to "native_software.html#native_binaries:google_test", - "google-test-test-suite" to "native_software.html#native_binaries:google_test", - - "groovy" to "groovy_plugin.html", - "groovy-base" to "standard_plugins.html#sec:base_plugins", - - "help-tasks" to "tutorial_gradle_command_line.html#sec:obtaining_information_about_your_build", - - "idea" to "idea_plugin.html", - - "ivy-publish" to "publishing_ivy.html#publishing_ivy:plugin", - - "jacoco" to "jacoco_plugin.html", - - "java" to "java_plugin.html", - "java-base" to "standard_plugins.html#sec:base_plugins", - - "java-gradle-plugin" to "javaGradle_plugin.html", - - "java-lang" to "java_software.html", - - "java-library" to "java_library_plugin.html", - "java-library-distribution" to "javaLibraryDistribution_plugin.html", - - // "javascript-base" to "javascript_base_plugin.html", - - "jdepend" to "jdepend_plugin.html", - - // "jshint" to "jshint_plugin.html", - - "junit-test-suite" to "java_software.html#sec:testing_java_libraries", - - "jvm-component" to "java_software.html", - "jvm-resources" to "java_software.html", - - // "language-base" to "language_base_plugin.html", - // "lifecycle-base" to "lifecycle_base_plugin.html", - - "maven" to "maven_plugin.html", - "maven-publish" to "publishing_maven.html", - - "microsoft-visual-cpp-compiler" to "native_software.html#native_binaries:tool_chain", - - "native-component" to "native_software.html#sec:native_software_model", - "native-component-model" to "native_software.html#sec:native_software_model", - - "objective-c" to "native_software.html#sec:objectivec_sources", - "objective-c-lang" to "native_software.html#sec:objectivec_sources", - - "objective-cpp" to "native_software.html#sec:objectivecpp_sources", - "objective-cpp-lang" to "native_software.html#sec:objectivecpp_sources", - - "osgi" to "osgi_plugin.html", - - "play" to "play_plugin.html", - "play-application" to "play_plugin.html", - "play-cofeescript" to "play_plugin.html", - "play-ide" to "play_plugin.html", - "play-javascript" to "play_plugin.html", - - "pmd" to "pmd_plugin.html", - - "project-report" to "project_reports_plugin.html", - "project-reports" to "project_reports_plugin.html", - - // "publishing" to "publishing_plugin.html", - - "reporting-base" to "standard_plugins.html#sec:base_plugins", - - // "rhino" to "rhino_plugin.html", - - "scala" to "scala_plugin.html", - "scala-base" to "standard_plugins.html#sec:base_plugins", - - // "scala-lang" to "scala_lang_plugin.html", - - "signing" to "signing_plugin.html", - - "standard-tool-chains" to "native_software.html#native_binaries:tool_chain", - - "visual-studio" to "native_software.html#native_binaries:visual_studio", - - "war" to "war_plugin.html", - - "windows-resource-script" to "native_software.html#native_binaries:windows-resources", - "windows-resources" to "native_software.html#native_binaries:windows-resources") -} - - -private -data class PluginEntry(val pluginId: String, val implementationClass: String) - - -private -fun pluginEntriesFrom(jar: File): List = - JarFile(jar).use { jarFile -> - jarFile.entries().asSequence().filter { - it.isFile && it.name.startsWith("META-INF/gradle-plugins/") - }.map { pluginEntry -> - val pluginProperties = jarFile.getInputStream(pluginEntry).use { Properties().apply { load(it) } } - val id = pluginEntry.name.substringAfterLast("/").substringBeforeLast(".properties") - val implementationClass = pluginProperties.getProperty("implementation-class") - PluginEntry(id, implementationClass) - }.toList() - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/ZipInputStreamEntry.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/ZipInputStreamEntry.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/codegen/ZipInputStreamEntry.kt (revision 0) @@ -1,26 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.codegen - -import java.util.zip.ZipEntry - - -internal -val ZipEntry.isFile: Boolean - get() = !isDirectory - - Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/Either.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/Either.kt (revision 50b5597fc507970bfa6f2d7b8555bcc5b97e5866) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/Either.kt (revision 0) @@ -1,51 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.concurrent - - -/** - * Represents values with two possibilities. - */ -internal -sealed class Either { - - abstract fun fold(left: (L) -> T, right: (R) -> T): T - - data class Left(val value: L) : Either() { - override fun fold(left: (L) -> T, right: (R) -> T): T = left(value) - } - - data class Right(val value: R) : Either() { - override fun fold(left: (L) -> T, right: (R) -> T): T = right(value) - } -} - - -/** - * Constructs a [Either.Left] value. - */ -internal -fun left(value: L): Either = Either.Left(value) - - -/** - * Constructs a [Either.Right] value. - */ -internal -fun right(value: R): Either = Either.Right(value) - - Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/future.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/future.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/future.kt (revision 0) @@ -1,82 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.concurrent - -import java.util.concurrent.CountDownLatch -import java.util.concurrent.Future -import java.util.concurrent.TimeUnit -import java.util.concurrent.TimeoutException - -import kotlin.coroutines.experimental.Continuation -import kotlin.coroutines.experimental.CoroutineContext -import kotlin.coroutines.experimental.EmptyCoroutineContext -import kotlin.coroutines.experimental.startCoroutine - - -/** - * Starts and exposes the given suspending [computation] as a [Future] value. - * - * The [computation] executes synchronously until its first suspension point. - */ -internal -fun future(context: CoroutineContext = EmptyCoroutineContext, computation: suspend () -> T): Future = - FutureContinuation(context).also { k -> - computation.startCoroutine(completion = k) - } - - -private -class FutureContinuation(override val context: CoroutineContext) : Future, Continuation { - - private - var outcome: Either? = null - - private - val outcomeLatch = CountDownLatch(1) - - override fun isCancelled(): Boolean = false - - override fun cancel(mayInterruptIfRunning: Boolean): Boolean = false - - override fun isDone(): Boolean = outcome != null - - override fun get(): T { - outcomeLatch.await() - return getOrThrow() - } - - override fun get(timeout: Long, unit: TimeUnit): T = - if (outcomeLatch.await(timeout, unit)) getOrThrow() - else throw TimeoutException() - - private - fun getOrThrow() = outcome!!.fold({ throw it }, { it }) - - override fun resume(value: T) { - resumeWith(right(value)) - } - - override fun resumeWithException(exception: Throwable) { - resumeWith(left(exception)) - } - - private - fun resumeWith(outcome: Either) { - this.outcome = outcome - outcomeLatch.countDown() - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/tapi.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/tapi.kt (revision 05c6e9e4957fa24d056555a5b6a10c9499bed582) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/concurrent/tapi.kt (revision 0) @@ -1,48 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.concurrent - -import org.gradle.tooling.GradleConnectionException -import org.gradle.tooling.ResultHandler - -import kotlin.coroutines.experimental.Continuation -import kotlin.coroutines.experimental.suspendCoroutine - - -/** - * Universal Tooling API wrapper. - * - * Suspends on a TAPI [computation] until it completes on the given [ResultHandler]. - * - * Execution will continue on the TAPI executor thread. - */ -internal -suspend inline fun tapi(crossinline computation: (ResultHandler) -> Unit): T = - suspendCoroutine { k: Continuation -> - computation(k.asResultHandler()) - } - - -internal -fun Continuation.asResultHandler(): ResultHandler = - object : ResultHandler { - override fun onComplete(result: T) = - resume(result) - - override fun onFailure(failure: GradleConnectionException) = - resumeWithException(failure) - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledInitScript.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledInitScript.kt (revision 5d704f53ce8ac61d04df2e6e25f2ad9f76e0803a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledInitScript.kt (revision 0) @@ -1,42 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.precompile - -import org.gradle.api.invocation.Gradle - -import org.gradle.kotlin.dsl.GradleDsl -import org.gradle.kotlin.dsl.InitScriptApi -import org.gradle.kotlin.dsl.fileOperationsFor - -import kotlin.script.extensions.SamWithReceiverAnnotations -import kotlin.script.templates.ScriptTemplateDefinition - - -/** - * Script template definition for precompiled Kotlin script targeting [Gradle] instances. - * - * @see PrecompiledProjectScript - */ -@ScriptTemplateDefinition( - resolver = PrecompiledScriptDependenciesResolver::class, - scriptFilePattern = "^.+\\.init\\.gradle\\.kts$") -@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") -@GradleDsl -abstract class PrecompiledInitScript(target: Gradle) : InitScriptApi(target) { - - override val operations by lazy { fileOperationsFor(gradle, null) } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledProjectScript.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledProjectScript.kt (revision 8b436eaf7ae03436be2150283def3488ccb98990) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledProjectScript.kt (revision 0) @@ -1,86 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.precompile - -import org.gradle.api.Project - -import org.gradle.kotlin.dsl.GradleDsl -import org.gradle.kotlin.dsl.ScriptHandlerScope - -import org.gradle.plugin.use.PluginDependenciesSpec -import org.gradle.plugin.use.PluginDependencySpec - -import kotlin.script.extensions.SamWithReceiverAnnotations -import kotlin.script.templates.ScriptTemplateDefinition - - -/** - * Script template definition for precompiled Kotlin scripts targeting [Project] instances. - * - * A precompiled script is a script compiled as part of a regular Kotlin source-set and distributed - * in the usual way, java class files packaged in some library, meant to be consumed as a binary - * Gradle plugin. - * - * The Gradle plugin id by which the precompiled script can be referenced is derived from its name - * and package declaration - if any - in the following fashion: - * - * ```kotlin - * fun pluginIdFor(script: File, packageName: String?) = - * (packageName?.let { "$it." } ?: "") + script.nameWithoutExtension - * ``` - * - * Thus, the script `src/main/kotlin/code-quality.gradle.kts` would be exposed as the `code-quality` - * plugin (assuming it has no package declaration) whereas the script - * `src/main/kotlin/gradlebuild/code-quality.gradle.kts` would be exposed as the `gradlebuild.code-quality` - * plugin, again assuming it has the matching package declaration. - */ -@ScriptTemplateDefinition( - resolver = PrecompiledScriptDependenciesResolver::class, - scriptFilePattern = "^.*\\.gradle\\.kts$") -@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") -@GradleDsl -abstract class PrecompiledProjectScript(project: Project) : Project by project { - - /** - * Configures the build script classpath for this project. - * - * @see [Project.buildscript] - */ - @Suppress("unused") - open fun buildscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit) { - throw IllegalStateException("The `buildscript` block is not supported on Kotlin script plugins, please use the `plugins` block or project level dependencies.") - } - - /** - * Configures the plugin dependencies for this project. - * - * @see [PluginDependenciesSpec] - */ - @Suppress("unused") - fun plugins(@Suppress("unused_parameter") block: PluginDependenciesSpec.() -> Unit) { - block( - PluginDependenciesSpec { pluginId -> - project.pluginManager.apply(pluginId) - NullPluginDependencySpec - }) - } - - object NullPluginDependencySpec : PluginDependencySpec { - override fun apply(apply: Boolean) = this - override fun version(version: String?) = this - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledScriptDependenciesResolver.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledScriptDependenciesResolver.kt (revision 8d5805434f66684d85a81e4b68227518495d6292) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledScriptDependenciesResolver.kt (revision 0) @@ -1,54 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.precompile - -import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptDependencies - -import java.util.concurrent.Future - -import kotlin.script.dependencies.ScriptDependenciesResolver -import kotlin.script.dependencies.PseudoFuture -import kotlin.script.dependencies.ScriptContents -import kotlin.script.dependencies.KotlinScriptExternalDependencies -import kotlin.script.dependencies.Environment - - -class PrecompiledScriptDependenciesResolver : ScriptDependenciesResolver { - - object EnvironmentProperties { - const val kotlinDslImplicitImports = "kotlinDslImplicitImports" - } - - override fun resolve( - script: ScriptContents, - environment: Environment?, - report: (ScriptDependenciesResolver.ReportSeverity, String, ScriptContents.Position?) -> Unit, - previousDependencies: KotlinScriptExternalDependencies? - ): Future = - - PseudoFuture( - KotlinBuildScriptDependencies( - imports = implicitImportsFrom(environment), - classpath = emptyList(), - sources = emptyList(), - buildscriptBlockHash = null)) - - private - fun implicitImportsFrom(environment: Environment?) = - (environment?.get(EnvironmentProperties.kotlinDslImplicitImports) as? String)?.split(':') - ?: emptyList() -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledSettingsScript.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledSettingsScript.kt (revision 5d704f53ce8ac61d04df2e6e25f2ad9f76e0803a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/precompile/PrecompiledSettingsScript.kt (revision 0) @@ -1,42 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.precompile - -import org.gradle.api.initialization.Settings - -import org.gradle.kotlin.dsl.GradleDsl -import org.gradle.kotlin.dsl.SettingsScriptApi -import org.gradle.kotlin.dsl.fileOperationsFor - -import kotlin.script.extensions.SamWithReceiverAnnotations -import kotlin.script.templates.ScriptTemplateDefinition - - -/** - * Script template definition for precompiled Kotlin script targeting [Settings] instances. - * - * @see PrecompiledProjectScript - */ -@ScriptTemplateDefinition( - resolver = PrecompiledScriptDependenciesResolver::class, - scriptFilePattern = "^(settings|.+\\.settings)\\.gradle\\.kts$") -@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") -@GradleDsl -abstract class PrecompiledSettingsScript(target: Settings) : SettingsScriptApi(target) { - - override val fileOperations by lazy { fileOperationsFor(settings) } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/BuildServices.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/BuildServices.kt (revision bb670839befd1b5c5d2b2c67299775ed98929134) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/BuildServices.kt (revision 0) @@ -1,98 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.internal.ClassPathRegistry -import org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory - -import org.gradle.cache.internal.GeneratedGradleJarCache - -import org.gradle.internal.logging.progress.ProgressLoggerFactory - -import org.gradle.kotlin.dsl.cache.ScriptCache -import org.gradle.kotlin.dsl.support.EmbeddedKotlinProvider -import org.gradle.kotlin.dsl.support.ImplicitImports - -import org.gradle.plugin.management.internal.autoapply.AutoAppliedPluginHandler -import org.gradle.plugin.use.internal.PluginRequestApplicator - - -internal -object BuildServices { - - @Suppress("unused") - fun createCachingKotlinCompiler( - scriptCache: ScriptCache, - implicitImports: ImplicitImports, - progressLoggerFactory: ProgressLoggerFactory - ) = - - CachingKotlinCompiler(scriptCache, implicitImports, progressLoggerFactory) - - @Suppress("unused") - fun createKotlinScriptClassPathProvider( - classPathRegistry: ClassPathRegistry, - dependencyFactory: DependencyFactory, - jarCache: GeneratedGradleJarCache, - progressLoggerFactory: ProgressLoggerFactory - ) = - - KotlinScriptClassPathProvider( - classPathRegistry, - gradleApiJarsProviderFor(dependencyFactory), - versionedJarCacheFor(jarCache), - StandardJarGenerationProgressMonitorProvider(progressLoggerFactory)) - - @Suppress("unused") - fun createPluginRequestsHandler( - pluginRequestApplicator: PluginRequestApplicator, - autoAppliedPluginHandler: AutoAppliedPluginHandler - ) = - - PluginRequestsHandler(pluginRequestApplicator, autoAppliedPluginHandler) - - @Suppress("unused") - fun createClassPathModeExceptionCollector() = - ClassPathModeExceptionCollector() - - @Suppress("unused") - fun createKotlinScriptFactory( - classPathProvider: KotlinScriptClassPathProvider, - kotlinCompiler: CachingKotlinCompiler, - classloadingCache: KotlinScriptClassloadingCache, - pluginRequestsHandler: PluginRequestsHandler, - embeddedKotlinProvider: EmbeddedKotlinProvider, - classPathModeExceptionCollector: ClassPathModeExceptionCollector - ): KotlinScriptFactory = - - StandardKotlinScriptFactory( - classPathProvider, - kotlinCompiler, - classloadingCache, - pluginRequestsHandler, - embeddedKotlinProvider, - classPathModeExceptionCollector) - - private - fun versionedJarCacheFor(jarCache: GeneratedGradleJarCache): JarCache = - { id, creator -> jarCache["$id-$gradleKotlinDslVersion", creator] } - - private - val gradleKotlinDslVersion by lazy { - this::class.java.`package`.implementationVersion - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/BuildscriptBlockExtraction.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/BuildscriptBlockExtraction.kt (revision 5d704f53ce8ac61d04df2e6e25f2ad9f76e0803a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/BuildscriptBlockExtraction.kt (revision 0) @@ -1,125 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.jetbrains.kotlin.lexer.KotlinLexer -import org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER -import org.jetbrains.kotlin.lexer.KtTokens.LBRACE -import org.jetbrains.kotlin.lexer.KtTokens.RBRACE -import org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET - - -internal -class UnexpectedBlock(val identifier: String, val location: IntRange) : RuntimeException("Unexpected block found.") - - -internal -fun extractBuildscriptBlockFrom(script: String) = - extractTopLevelSectionFrom(script, "buildscript") - - -/** - * Extract a top-level section from the given [script]. The section must be in the form: - * - * [identifier] { anything* } - * - * @return range of found section or null if no top-level section with the given [identifier] could be found - * @throws [UnexpectedBlock] if more than one top-level section with the given [identifier] is found - */ -internal -fun extractTopLevelSectionFrom(script: String, identifier: String): IntRange? { - require('\r' !in script) { - "CR characters are not supported by the Kotlin lexer. Convert the line separators before attempting this operation." - } - KotlinLexer().run { - start(script) - while (tokenType != null) { - nextTopLevelSection(identifier)?.let { - advance() - expectNoMore(identifier) - return it - } - } - return null - } -} - - -private -fun KotlinLexer.expectNoMore(identifier: String) { - nextTopLevelSection(identifier)?.let { - throw UnexpectedBlock(identifier, it) - } -} - - -private -fun KotlinLexer.nextTopLevelSection(identifier: String): IntRange? = - findTopLevelIdentifier(identifier)?.let { sectionStart -> - advance() - skipWhiteSpaceAndComments() - if (tokenType == LBRACE) { - findBlockEnd()?.let { sectionEnd -> - sectionStart..sectionEnd - } - } else null - } - - -private -fun KotlinLexer.skipWhiteSpaceAndComments() { - while (tokenType in WHITE_SPACE_OR_COMMENT_BIT_SET) { - advance() - } -} - - -private -fun KotlinLexer.findTopLevelIdentifier(identifier: String): Int? { - var depth: Int = 0 - while (tokenType != null) { - when (tokenType) { - IDENTIFIER -> - if (depth == 0 && tokenText == identifier) { - return tokenStart - } - LBRACE -> depth += 1 - RBRACE -> depth -= 1 - } - advance() - } - return null -} - - -private -fun KotlinLexer.findBlockEnd(): Int? { - var depth: Int = 0 - while (tokenType != null) { - when (tokenType) { - LBRACE -> depth += 1 - RBRACE -> { - if (depth == 1) { - return tokenStart - } - depth -= 1 - } - } - advance() - } - return null -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/CachingKotlinCompiler.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/CachingKotlinCompiler.kt (revision e1a19b2b552fd1dc08d0455b7def529e5ee670fc) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/CachingKotlinCompiler.kt (revision 0) @@ -1,215 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.cache.CacheOpenException -import org.gradle.cache.PersistentCache -import org.gradle.cache.internal.CacheKeyBuilder.CacheKeySpec - -import org.gradle.internal.classpath.ClassPath -import org.gradle.internal.hash.HashCode -import org.gradle.internal.hash.Hashing -import org.gradle.internal.logging.progress.ProgressLoggerFactory - -import org.gradle.kotlin.dsl.cache.ScriptCache - -import org.gradle.kotlin.dsl.support.ImplicitImports -import org.gradle.kotlin.dsl.support.ScriptCompilationException -import org.gradle.kotlin.dsl.support.compileKotlinScriptToDirectory -import org.gradle.kotlin.dsl.support.loggerFor -import org.gradle.kotlin.dsl.support.messageCollectorFor - -import org.jetbrains.kotlin.script.KotlinScriptDefinition - -import java.io.File - -import kotlin.reflect.KClass - -import kotlin.script.dependencies.Environment -import kotlin.script.dependencies.ScriptContents -import kotlin.script.experimental.dependencies.DependenciesResolver -import kotlin.script.experimental.dependencies.ScriptDependencies - - -internal -data class ScriptBlock( - val displayName: String, - val scriptTemplate: KClass<*>, - val scriptPath: String, - val source: String, - val metadata: T -) { - - val sourceHash: HashCode = Hashing.md5().hashString(source) -} - - -internal -data class CompiledScript( - val location: File, - val className: String, - val metadata: T -) - - -private -val logger = loggerFor() - - -internal -class CachingKotlinCompiler( - private val scriptCache: ScriptCache, - private val implicitImports: ImplicitImports, - private val progressLoggerFactory: ProgressLoggerFactory -) { - - init { - org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback() - } - - private - val cacheKeyPrefix = CacheKeySpec.withPrefix("gradle-kotlin-dsl") - - private - val cacheProperties = mapOf("version" to "6") - - fun compileScriptBlock(scriptBlock: ScriptBlock, classPath: ClassPath): CompiledScript = - - scriptBlock.run { - val scriptFileName = scriptFileNameFor(scriptPath) - val cacheKeySpec = cacheKeyPrefix + scriptTemplate.qualifiedName + scriptFileName + source - return compileScript(cacheKeySpec, classPath, metadata) { cacheDir -> - ScriptCompilationSpec( - displayName, - scriptTemplate, - scriptPath, - cacheFileFor(source, cacheDir, scriptFileName)) - } - } - - private - fun scriptFileNameFor(scriptPath: String) = scriptPath.run { - val index = lastIndexOf('/') - if (index != -1) substring(index + 1, length) else substringAfterLast('\\') - } - - private - fun compileScript( - cacheKeySpec: CacheKeySpec, - classPath: ClassPath, - metadata: T, - compilationSpecFor: (File) -> ScriptCompilationSpec - ): CompiledScript { - - try { - val cacheDir = cacheDirFor(cacheKeySpec + classPath) { - val scriptClassName = - compileScriptTo(classesDirOf(baseDir), compilationSpecFor(baseDir), classPath) - writeClassNameTo(baseDir, scriptClassName) - } - return CompiledScript(classesDirOf(cacheDir), readClassNameFrom(cacheDir), metadata) - } catch (e: CacheOpenException) { - throw e.cause as? ScriptCompilationException ?: e - } - } - - data class ScriptCompilationSpec( - val displayName: String, - val scriptTemplate: KClass, - val originalPath: String, - val scriptFile: File - ) - - private - fun compileScriptTo( - outputDir: File, - spec: ScriptCompilationSpec, - classPath: ClassPath - ): String = - - spec.run { - withProgressLoggingFor(displayName) { - logger.debug( - "Compiling {} from {} with classpath: {}", - scriptTemplate.simpleName, displayName, classPath) - compileKotlinScriptToDirectory( - outputDir, - scriptFile, - scriptDefinitionFromTemplate(scriptTemplate), - classPath.asFiles, - messageCollectorFor(logger) { path -> - if (path == scriptFile.path) originalPath - else path - }) - } - } - - private - fun cacheDirFor(cacheKeySpec: CacheKeySpec, initializer: PersistentCache.() -> Unit): File = - scriptCache.cacheDirFor(cacheKeySpec, properties = cacheProperties, initializer = initializer) - - private - fun writeClassNameTo(cacheDir: File, className: String) = - scriptClassNameFile(cacheDir).writeText(className) - - private - fun readClassNameFrom(cacheDir: File) = - scriptClassNameFile(cacheDir).readText() - - private - fun scriptClassNameFile(cacheDir: File) = File(cacheDir, "script-class-name") - - private - fun classesDirOf(cacheDir: File) = File(cacheDir, "classes") - - private - fun cacheFileFor(text: String, cacheDir: File, fileName: String) = - File(cacheDir, fileName).apply { - writeText(text) - } - - private - fun scriptDefinitionFromTemplate(template: KClass) = - object : KotlinScriptDefinition(template) { - override val dependencyResolver = Resolver - } - - private - val Resolver by lazy { - object : DependenciesResolver { - override fun resolve( - scriptContents: ScriptContents, - environment: Environment - ): DependenciesResolver.ResolveResult = - - DependenciesResolver.ResolveResult.Success( - ScriptDependencies(imports = implicitImports.list), emptyList()) - } - } - - private - fun withProgressLoggingFor(description: String, action: () -> T): T { - val operation = progressLoggerFactory - .newOperation(this::class.java) - .start("Compiling script into cache", "Compiling $description into local compilation cache") - try { - return action() - } finally { - operation.completed() - } - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/CharSequenceExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/CharSequenceExtensions.kt (revision 06e3137aaaae2b7eec92f96e7327de6009ea7531) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/CharSequenceExtensions.kt (revision 0) @@ -1,74 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import kotlin.coroutines.experimental.buildSequence - - -internal -fun CharSequence.linePreservingSubstring(range: IntRange): String = - linePreservingSubstring_(range).second - - -internal -fun CharSequence.linePreservingSubstring_(range: IntRange): Pair { - val lineCount = take(range.start).count { it == '\n' } - return lineCount to "\n".repeat(lineCount) + substring(range) -} - - -internal -fun CharSequence.linePreservingBlankRanges(ranges: List): String = - ranges - .sortedByDescending { it.start } - .fold(this, CharSequence::linePreservingBlankRange) - .toString() - - -private -fun CharSequence.linePreservingBlankRange(range: IntRange): String { - val lineCount = substring(range).count { it == '\n' } - return substring(0, range.start) + "\n".repeat(lineCount) + substring(range.endInclusive + 1) -} - - -/** - * Computes the 1-based line and column numbers from the given [range]. - */ -internal -fun CharSequence.lineAndColumnFromRange(range: IntRange): Pair { - require(range.endInclusive <= lastIndex) - val prefix = take(range.start) - val lineCountBefore = prefix.count { it == '\n' } - val lastNewLineIndex = prefix.lastIndexOf('\n') - return (lineCountBefore + 1) to (range.start - lastNewLineIndex) -} - - -internal -fun CharSequence.splitIncluding(delimiter: Char) = buildSequence { - var startIndex = 0 - while (true) { - val endIndex = indexOf(delimiter, startIndex) + 1 - if (endIndex == 0) break - yield(substring(startIndex, endIndex)) - startIndex = endIndex - } - if (startIndex <= lastIndex) { - yield(substring(startIndex)) - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ClassLoaderHierarchy.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ClassLoaderHierarchy.kt (revision e1a19b2b552fd1dc08d0455b7def529e5ee670fc) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ClassLoaderHierarchy.kt (revision 0) @@ -1,145 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import groovy.json.JsonOutput.toJson - -import org.gradle.api.internal.initialization.AbstractClassLoaderScope -import org.gradle.api.internal.initialization.ClassLoaderScope - -import org.gradle.internal.classloader.ClassLoaderVisitor - -import org.gradle.kotlin.dsl.support.foldHierarchy - -import java.net.URL - -import java.util.* - - -/** - * A formatter for strings that might contain file system paths. - */ -internal -typealias PathStringFormatter = (String) -> String - - -internal -fun classLoaderHierarchyJsonFor( - klass: Class<*>, - targetScope: ClassLoaderScope, - pathFormatter: PathStringFormatter = { it } -) = - - classLoaderHierarchyJsonFor( - hierarchyOf(klass.classLoader), - hierarchyOf(targetScope), - pathFormatter) - - -private -typealias ClassLoaderId = String - - -private -class ClassLoaderNode( - val id: ClassLoaderId, - val label: String, - val classPath: MutableSet = LinkedHashSet(), - val parents: MutableSet = LinkedHashSet() -) - - -private -fun classLoaderHierarchyJsonFor( - classLoaders: List, - scopes: List, - pathFormatter: PathStringFormatter -): String { - - fun labelFor(scope: ClassLoaderScope) = - pathFormatter(if (scope is AbstractClassLoaderScope) scope.path else scope.toString()) - - return toJson( - mapOf( - "classLoaders" to classLoaders.map { - mapOf( - "id" to it.id, - "label" to it.label, - "classPath" to it.classPath.map { pathFormatter(it.toString()) }, - "parents" to it.parents) - }, - "scopes" to scopes.map { - mapOf( - "label" to labelFor(it), - "localClassLoader" to idOf(it.localClassLoader), - "exportClassLoader" to idOf(it.exportClassLoader), - "isLocked" to it.isLocked) - } - )) -} - - -private -fun hierarchyOf(initialScope: ClassLoaderScope): List = - initialScope.foldHierarchy(arrayListOf()) { result, scope -> - result.apply { add(scope) } - } - - -private -fun hierarchyOf(classLoader: ClassLoader): ArrayList { - - val classLoaders = arrayListOf() - val visitedClassLoaders = IdentityHashMap() - val stack = ArrayDeque() - val visitor = object : ClassLoaderVisitor() { - override fun visit(classLoader: ClassLoader) { - if (classLoader in visitedClassLoaders) { - return - } - visitedClassLoaders.put(classLoader, true) - - val record = ClassLoaderNode(idOf(classLoader), classLoader.toString()) - classLoaders.add(record) - - stack.push(record) - super.visit(classLoader) - stack.pop() - } - - override fun visitParent(classLoader: ClassLoader) { - current.parents.add(idOf(classLoader)) - super.visitParent(classLoader) - } - - override fun visitClassPath(classPath: Array) { - current.classPath.addAll(classPath.filterNotNull()) - } - - private - val current: ClassLoaderNode - get() = stack.peek()!! - } - - visitor.visit(classLoader) - return classLoaders -} - - -private -fun idOf(classLoader: ClassLoader): String = - "${classLoader::class.qualifiedName}@${System.identityHashCode(classLoader)}" Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ClassPathModeExceptionCollector.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ClassPathModeExceptionCollector.kt (revision 18c16799f2d8797d297758f95caf82ddefda0425) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ClassPathModeExceptionCollector.kt (revision 0) @@ -1,36 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.provider - -import org.gradle.internal.concurrent.Stoppable - - -open class ClassPathModeExceptionCollector : Stoppable { - - private - val collection = mutableListOf() - - val exceptions: List - get() = collection - - fun collect(error: Exception) { - collection.add(error) - } - - override fun stop() { - collection.clear() - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/GradleUserHomeServices.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/GradleUserHomeServices.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/GradleUserHomeServices.kt (revision 0) @@ -1,27 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.provider - -import org.gradle.cache.internal.CrossBuildInMemoryCacheFactory - - -internal -object GradleUserHomeServices { - - @Suppress("unused") - fun createKotlinScriptClassloadingCache(cacheFactory: CrossBuildInMemoryCacheFactory) = - KotlinScriptClassloadingCache(cacheFactory) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/JarGenerationProgressMonitorProvider.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/JarGenerationProgressMonitorProvider.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/JarGenerationProgressMonitorProvider.kt (revision 0) @@ -1,59 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.kotlin.dsl.support.ProgressMonitor - -import org.gradle.internal.logging.progress.ProgressLogger -import org.gradle.internal.logging.progress.ProgressLoggerFactory -import org.gradle.internal.progress.PercentageProgressFormatter - -import java.io.File - - -interface JarGenerationProgressMonitorProvider { - fun progressMonitorFor(outputJar: File, totalWork: Int): ProgressMonitor -} - - -internal -class StandardJarGenerationProgressMonitorProvider( - val progressLoggerFactory: ProgressLoggerFactory -) : JarGenerationProgressMonitorProvider { - - override fun progressMonitorFor(outputJar: File, totalWork: Int): ProgressMonitor { - val progressLogger = progressLoggerFor(outputJar) - val progressFormatter = PercentageProgressFormatter("Generating", totalWork) - return object : ProgressMonitor { - override fun onProgress() { - progressLogger.progress(progressFormatter.incrementAndGetProgress()) - } - - override fun close() { - progressLogger.completed() - } - } - } - - private - fun progressLoggerFor(outputJar: File): ProgressLogger = - progressLoggerFactory.newOperation(JarGenerationProgressMonitorProvider::class.java).apply { - description = "Gradle Kotlin DSL JARs generation" - loggingHeader = "Generating JAR file '${outputJar.name}'" - started() - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinDslProviderMode.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinDslProviderMode.kt (revision 639ba42575bb086106366cd7757a5456a5eedd8f) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinDslProviderMode.kt (revision 0) @@ -1,27 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.provider - - -internal -object KotlinDslProviderMode { - const val systemPropertyName = "org.gradle.kotlin.dsl.provider.mode" - const val classPathMode = "classpath" -} - - -fun inClassPathMode() = - System.getProperty(KotlinDslProviderMode.systemPropertyName) == KotlinDslProviderMode.classPathMode Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinGradleApiSpecProvider.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinGradleApiSpecProvider.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinGradleApiSpecProvider.kt (revision 0) @@ -1,29 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.initialization.GradleApiSpecProvider - - -class KotlinGradleApiSpecProvider : GradleApiSpecProvider { - - override fun get() = KotlinSpec - - object KotlinSpec : GradleApiSpecProvider.SpecAdapter() { - override fun getExportedPackages() = setOf("kotlin") - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptBasePluginsApplicator.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptBasePluginsApplicator.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptBasePluginsApplicator.kt (revision 0) @@ -1,25 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.Project - - -interface KotlinScriptBasePluginsApplicator { - - fun apply(project: Project) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassPathProvider.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassPathProvider.kt (revision 1e1ce8632e9b3390bcbc06a7b51c602d02102b2f) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassPathProvider.kt (revision 0) @@ -1,241 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.Project - -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.SelfResolvingDependency - -import org.gradle.api.internal.ClassPathRegistry -import org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory -import org.gradle.api.internal.initialization.ClassLoaderScope - -import org.gradle.internal.classloader.ClassLoaderVisitor -import org.gradle.internal.classpath.ClassPath -import org.gradle.internal.classpath.DefaultClassPath - -import org.gradle.kotlin.dsl.codegen.generateApiExtensionsJar -import org.gradle.kotlin.dsl.support.ProgressMonitor -import org.gradle.kotlin.dsl.support.minus -import org.gradle.kotlin.dsl.support.root -import org.gradle.kotlin.dsl.support.serviceOf - -import org.gradle.util.GFileUtils.moveFile - -import java.io.File - -import java.net.URI -import java.net.URISyntaxException -import java.net.URL - -import java.util.concurrent.ConcurrentHashMap - - -fun gradleKotlinDslOf(project: Project): List = - kotlinScriptClassPathProviderOf(project).run { - gradleKotlinDsl.asFiles - } - - -fun kotlinScriptClassPathProviderOf(project: Project) = - project.serviceOf() - - -internal -typealias JarCache = (String, JarGenerator) -> File - - -internal -typealias JarGenerator = (File) -> Unit - - -private -typealias JarGeneratorWithProgress = (File, () -> Unit) -> Unit - - -internal -typealias JarsProvider = () -> Collection - - -class KotlinScriptClassPathProvider( - val classPathRegistry: ClassPathRegistry, - val gradleApiJarsProvider: JarsProvider, - val jarCache: JarCache, - val progressMonitorProvider: JarGenerationProgressMonitorProvider -) { - - /** - * Generated Gradle API jar plus supporting libraries such as groovy-all.jar and generated API extensions. - */ - val gradleKotlinDsl: ClassPath by lazy { - gradleApi + gradleApiExtensions + gradleKotlinDslJars - } - - val gradleApi: ClassPath by lazy { - DefaultClassPath.of(gradleApiJarsProvider()) - } - - /** - * Generated extensions to the Gradle API. - */ - val gradleApiExtensions: ClassPath by lazy { - DefaultClassPath.of(gradleKotlinDslExtensions()) - } - - /** - * gradle-kotlin-dsl.jar plus kotlin libraries. - */ - val gradleKotlinDslJars: ClassPath by lazy { - DefaultClassPath.of(gradleKotlinDslJars()) - } - - fun compilationClassPathOf(scope: ClassLoaderScope): ClassPath = - cachedScopeCompilationClassPath.computeIfAbsent(scope, ::computeCompilationClassPath) - - private - fun computeCompilationClassPath(scope: ClassLoaderScope): ClassPath = - gradleKotlinDsl + exportClassPathFromHierarchyOf(scope) - - private - fun exportClassPathFromHierarchyOf(scope: ClassLoaderScope): ClassPath { - require(scope.isLocked) { - "$scope must be locked before it can be used to compute a classpath!" - } - val fullClassPath = cachedClassLoaderClassPath.of(scope.exportClassLoader) - val rootClassPath = cachedClassLoaderClassPath.of(scope.root.exportClassLoader) - return fullClassPath - rootClassPath - } - - private - fun gradleKotlinDslExtensions(): File = - produceFrom("kotlin-dsl-extensions") { outputFile, onProgress -> - generateApiExtensionsJar(outputFile, gradleJars, onProgress) - } - - private - fun produceFrom(id: String, generate: JarGeneratorWithProgress): File = - jarCache(id) { outputFile -> - progressMonitorFor(outputFile, 1).use { progressMonitor -> - generateAtomically(outputFile, { generate(it, progressMonitor::onProgress) }) - } - } - - private - fun generateAtomically(outputFile: File, generate: JarGenerator) { - val tempFile = tempFileFor(outputFile) - generate(tempFile) - moveFile(tempFile, outputFile) - } - - private - fun progressMonitorFor(outputFile: File, totalWork: Int): ProgressMonitor = - progressMonitorProvider.progressMonitorFor(outputFile, totalWork) - - private - fun tempFileFor(outputFile: File): File = - createTempFile(outputFile.nameWithoutExtension, outputFile.extension).apply { - deleteOnExit() - } - - private - fun gradleKotlinDslJars(): List = - gradleJars.filter { - it.name.let { isKotlinJar(it) || it.startsWith("gradle-kotlin-dsl-") } - } - - private - val gradleJars by lazy { - classPathRegistry.getClassPath(gradleApiNotation.name).asFiles - } - - private - val cachedScopeCompilationClassPath = ConcurrentHashMap() - - private - val cachedClassLoaderClassPath = ClassLoaderClassPathCache() -} - - -internal -fun gradleApiJarsProviderFor(dependencyFactory: DependencyFactory): JarsProvider = - { (dependencyFactory.gradleApi() as SelfResolvingDependency).resolve() } - - -private -fun DependencyFactory.gradleApi(): Dependency = - createDependency(gradleApiNotation) - - -private -val gradleApiNotation = DependencyFactory.ClassPathNotation.GRADLE_API - - -private -fun isKotlinJar(name: String): Boolean = - name.startsWith("kotlin-stdlib-") - || name.startsWith("kotlin-reflect-") - - -private -class ClassLoaderClassPathCache { - - private - val cachedClassPaths = hashMapOf() - - fun of(classLoader: ClassLoader): ClassPath = - cachedClassPaths.getOrPut(classLoader) { - classPathOf(classLoader) - } - - private - fun classPathOf(classLoader: ClassLoader): ClassPath { - val classPathFiles = mutableListOf() - - object : ClassLoaderVisitor() { - override fun visitClassPath(classPath: Array) { - classPath.forEach { url -> - if (url.protocol == "file") { - classPathFiles.add(fileFrom(url)) - } - } - } - - override fun visitParent(classLoader: ClassLoader) { - classPathFiles.addAll(of(classLoader).asFiles) - } - }.visit(classLoader) - - return DefaultClassPath.of(classPathFiles) - } - - private - fun fileFrom(url: URL) = File(toURI(url)) -} - - -private -fun toURI(url: URL): URI = - try { - url.toURI() - } catch (e: URISyntaxException) { - URL( - url.protocol, - url.host, - url.port, - url.file.replace(" ", "%20")).toURI() - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassloadingCache.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassloadingCache.kt (revision 6c113f56ec90b58b830e0fa7af3754cc68c014aa) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassloadingCache.kt (revision 0) @@ -1,133 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.internal.initialization.ClassLoaderScope - -import org.gradle.cache.internal.CrossBuildInMemoryCache -import org.gradle.cache.internal.CrossBuildInMemoryCacheFactory - -import org.gradle.internal.Cast.uncheckedCast -import org.gradle.internal.classpath.DefaultClassPath -import org.gradle.internal.hash.HashCode - -import org.gradle.kotlin.dsl.support.loggerFor - -import java.io.File - -import java.lang.ref.WeakReference - -import javax.inject.Inject - - -internal -data class LoadedScriptClass( - val compiledScript: CompiledScript, - val scriptClass: Class<*> -) - - -private -val logger = loggerFor() - - -internal -class KotlinScriptClassloadingCache @Inject constructor(cacheFactory: CrossBuildInMemoryCacheFactory) { - - private - val cache: CrossBuildInMemoryCache> = cacheFactory.newCache() - - fun loadScriptClass( - scriptBlock: ScriptBlock, - parentClassLoader: ClassLoader, - createClassLoaderScope: () -> ClassLoaderScope, - compile: (ScriptBlock) -> CompiledScript - ): LoadedScriptClass { - - val key = cacheKeyFor(scriptBlock, parentClassLoader) - val cached = cache.get(key) - if (cached != null) { - return uncheckedCast(cached) - } - - val compiledScript = compile(scriptBlock) - - logClassloadingOf(scriptBlock) - val scriptClass = classFrom(compiledScript, createClassLoaderScope()) - - return LoadedScriptClass(compiledScript, scriptClass).also { - cache.put(key, it) - } - } - - private - fun cacheKeyFor(scriptBlock: ScriptBlock, parentClassLoader: ClassLoader) = - ScriptCacheKey(scriptBlock.scriptTemplate.qualifiedName!!, scriptBlock.sourceHash, parentClassLoader) - - private - fun classFrom(compiledScript: CompiledScript<*>, scope: ClassLoaderScope): Class<*> = - classLoaderFor(compiledScript.location, scope) - .loadClass(compiledScript.className) - - private - fun classLoaderFor(location: File, scope: ClassLoaderScope) = - scope - .local(DefaultClassPath.of(location)) - .lock() - .localClassLoader - - private - fun logClassloadingOf(scriptBlock: ScriptBlock) = - logger.debug("Loading {} from {}", scriptBlock.scriptTemplate.simpleName, scriptBlock.displayName) -} - - -private -class ScriptCacheKey( - private val templateId: String, - private val sourceHash: HashCode, - parentClassLoader: ClassLoader -) { - - private - val parentClassLoader = WeakReference(parentClassLoader) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - if (other == null || this::class != other::class) { - return false - } - val that = other as ScriptCacheKey - val thisParentLoader = parentClassLoader.get() - val thatParentLoader = that.parentClassLoader.get() - return thisParentLoader != null - && thatParentLoader != null - && thisParentLoader == thatParentLoader - && templateId == that.templateId - && sourceHash == that.sourceHash - } - - override fun hashCode(): Int { - var result = templateId.hashCode() - result = 31 * result + sourceHash.hashCode() - parentClassLoader.get()?.let { loader -> - result = 31 * result + loader.hashCode() - } - return result - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptCompiler.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptCompiler.kt (revision bb670839befd1b5c5d2b2c67299775ed98929134) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptCompiler.kt (revision 0) @@ -1,505 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.internal.initialization.ClassLoaderScope -import org.gradle.api.internal.initialization.ScriptHandlerInternal -import org.gradle.api.internal.plugins.PluginAwareInternal - -import org.gradle.groovy.scripts.ScriptSource - -import org.gradle.internal.classpath.ClassPath -import org.gradle.internal.exceptions.LocationAwareException - -import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.support.EmbeddedKotlinProvider -import org.gradle.kotlin.dsl.support.ScriptCompilationException -import org.gradle.kotlin.dsl.support.compilerMessageFor -import org.gradle.kotlin.dsl.support.unsafeLazy - -import org.gradle.plugin.management.internal.PluginRequests - -import org.gradle.plugin.use.PluginDependenciesSpec -import org.gradle.plugin.use.internal.PluginRequestCollector - -import org.gradle.util.TextUtil.normaliseLineSeparators - -import java.lang.reflect.InvocationTargetException - -import kotlin.reflect.KClass - - -internal -data class PluginsBlockMetadata(val lineNumber: Int) - - -internal -class KotlinScriptSource(val source: ScriptSource) { - - private - val scriptResource = source.resource!! - - val scriptPath = source.fileName!! - - val script = normaliseLineSeparators(scriptResource.text!!) - - val displayName: String - get() = source.displayName - - fun classLoaderScopeIdFor(stage: String) = - "kotlin-dsl:$scriptPath:$stage" -} - - -internal -class KotlinScriptCompiler( - private val kotlinCompiler: CachingKotlinCompiler, - private val classloadingCache: KotlinScriptClassloadingCache, - private val scriptSource: KotlinScriptSource, - private val scriptTarget: KotlinScriptTarget, - private val scriptHandler: ScriptHandlerInternal, - private val pluginRequestsHandler: PluginRequestsHandler, - private val baseScope: ClassLoaderScope, - private val targetScope: ClassLoaderScope, - private val classPathProvider: KotlinScriptClassPathProvider, - private val embeddedKotlinProvider: EmbeddedKotlinProvider, - private val classPathModeExceptionCollector: ClassPathModeExceptionCollector -) { - - private - val buildscriptBlockCompilationClassPath: Lazy = unsafeLazy { - classPathProvider.compilationClassPathOf(targetScope.parent) - } - - private - val pluginsBlockCompilationClassPath: Lazy = buildscriptBlockCompilationClassPath - - private - val compilationClassPath: ClassPath by unsafeLazy { - classPathProvider.compilationClassPathOf(targetScope) - } - - private - val accessorsClassPath: ClassPath by unsafeLazy { - scriptTarget.accessorsClassPathFor(compilationClassPath).bin - } - - private - val buildscriptBlockRange: IntRange? by unsafeLazy { - extractTopLevelSectionFrom(script, scriptTarget.buildscriptBlockName) - } - - private - val pluginsBlockRange: IntRange? by unsafeLazy { - extractTopLevelSectionFrom(script, "plugins") - } - - fun compile() = - asKotlinScript { - withUnexpectedBlockHandling { - prepareForCompilation() - executeBuildscriptBlock() - executePluginsBlock() - executeScriptBody() - } - } - - fun compileIgnoringErrors(executeScriptBody: Boolean) = - asKotlinScript { - ignoringErrors { prepareForCompilation() } - ignoringErrors { executeBuildscriptBlock() } - ignoringErrors { executePluginsBlock() } - if (executeScriptBody) { - ignoringErrors { executeScriptBody() } - } - } - - private - fun asKotlinScript(script: KotlinScript) = script - - private - fun prepareForCompilation() { - validateExtraSingleOrNoneBlockNames() - scriptTarget.prepare() - } - - private - fun validateExtraSingleOrNoneBlockNames() = - scriptTarget.extraSingleOrNoneBlockNames.forEach { - extractTopLevelSectionFrom(script, it) - } - - private - fun executeScriptBody() = - loadScriptBodyClass().eval(scriptSource) { - scriptTarget.eval(scriptClass) - } - - private - fun executeBuildscriptBlock() = - BuildscriptBlockEvaluator( - scriptSource, - scriptTarget, - buildscriptBlockRange, - buildscriptBlockCompilationClassPath, - baseScope, - kotlinCompiler, - embeddedKotlinProvider, - classloadingCache).evaluate() - - private - fun executePluginsBlock() { - prepareTargetClassLoaderScope() - applyPlugins(pluginRequests()) - } - - private - fun prepareTargetClassLoaderScope() { - targetScope.export(classPathProvider.gradleApiExtensions) - } - - private - fun pluginRequests() = - scriptTarget.pluginsBlockTemplate?.let { template -> - collectPluginRequestsFromPluginsBlock(template) - } - - private - fun collectPluginRequestsFromPluginsBlock(scriptTemplate: KClass<*>): PluginRequests { - val pluginRequestCollector = PluginRequestCollector(scriptSource.source) - executePluginsBlockOn(pluginRequestCollector, scriptTemplate) - return pluginRequestCollector.pluginRequests - } - - private - fun executePluginsBlockOn(pluginRequestCollector: PluginRequestCollector, scriptTemplate: KClass<*>) = - pluginsBlockRange?.let { pluginsRange -> - val loadedPluginsBlockClass = loadPluginsBlockClass(scriptBlockForPlugins(pluginsRange, scriptTemplate)) - executeCompiledPluginsBlockOn(pluginRequestCollector, loadedPluginsBlockClass) - } - - private - fun executeCompiledPluginsBlockOn( - pluginRequestCollector: PluginRequestCollector, - loadedPluginsBlockClass: LoadedScriptClass - ) { - - val pluginDependenciesSpec = pluginRequestCollector.createSpec(loadedPluginsBlockClass.compiledScript.metadata.lineNumber) - loadedPluginsBlockClass.eval(scriptSource) { - instantiate(scriptClass, PluginDependenciesSpec::class, pluginDependenciesSpec) - } - } - - private - fun applyPlugins(pluginRequests: PluginRequests?) = - pluginRequestsHandler.handle( - pluginRequests, scriptHandler, scriptTarget.`object` as PluginAwareInternal, targetScope) - - private - fun withKotlinCompiler(action: CachingKotlinCompiler.() -> T) = - scriptSource.withLocationAwareExceptionHandling { - kotlinCompiler.action() - } - - private - fun scriptBlockForPlugins(pluginsRange: IntRange, scriptTemplate: KClass<*>) = - script.linePreservingSubstring_(pluginsRange).let { (lineNumber, source) -> - ScriptBlock( - "plugins block '$scriptPath'", - scriptTemplate, - scriptPath, - source, - PluginsBlockMetadata(lineNumber)) - } - - private - fun loadPluginsBlockClass(scriptBlock: ScriptBlock) = - classloadingCache.loadScriptClass( - scriptBlock, - baseScope.exportClassLoader, - ::pluginsBlockClassLoaderScope, - ::compilePluginsBlock) - - private - fun compilePluginsBlock(scriptBlock: ScriptBlock) = - withKotlinCompiler { - compileScriptBlock(scriptBlock, pluginsBlockCompilationClassPath.value) - } - - private - fun loadScriptBodyClass() = - classloadingCache.loadScriptClass( - scriptBlockForBody(), - targetScope.localClassLoader, - ::scriptBodyClassLoaderScope, - ::compileScriptBody) - - private - fun scriptBlockForBody() = - ScriptBlock( - scriptSource.displayName, - scriptTarget.scriptTemplate, - scriptPath, - scriptWithoutBuildscriptAndPluginsBlocks, - Unit) - - private - val scriptWithoutBuildscriptAndPluginsBlocks - get() = script.linePreservingBlankRanges(listOfNotNull(buildscriptBlockRange, pluginsBlockRange)) - - private - fun compileScriptBody(scriptBlock: ScriptBlock) = - withKotlinCompiler { - compileScriptBlock(scriptBlock, compilationClassPath + accessorsClassPath) - } - - private - fun scriptBodyClassLoaderScope() = scriptClassLoaderScopeWith(accessorsClassPath) - - private - fun scriptClassLoaderScopeWith(accessorsClassPath: ClassPath) = - targetScope - .createChild(classLoaderScopeIdFor("script")) - .local(accessorsClassPath) - - private - fun pluginsBlockClassLoaderScope() = - baseScopeFor("plugins") - - private - fun baseScopeFor(stage: String) = - baseScope.createChild(classLoaderScopeIdFor(stage)) - - private - fun classLoaderScopeIdFor(stage: String) = - scriptSource.classLoaderScopeIdFor(stage) - - private - inline fun ignoringErrors(action: () -> Unit) = classPathModeExceptionCollector.ignoringErrors(action) - - private - fun instantiate(scriptClass: Class<*>, targetType: KClass<*>, target: T) { - scriptClass.getConstructor(targetType.java).newInstance(target) - } - - private - inline fun withUnexpectedBlockHandling(action: () -> Unit) { - try { - action() - } catch (unexpectedBlock: UnexpectedBlock) { - val (line, column) = script.lineAndColumnFromRange(unexpectedBlock.location) - val message = compilerMessageFor(scriptPath, line, column, unexpectedBlockMessage(unexpectedBlock)) - throw IllegalStateException(message, unexpectedBlock) - } - } - - private - fun unexpectedBlockMessage(block: UnexpectedBlock) = - "Unexpected `${block.identifier}` block found. Only one `${block.identifier}` block is allowed per script." - - private - val scriptPath - get() = scriptSource.scriptPath - - private - val script - get() = scriptSource.script -} - - -private -class BuildscriptBlockEvaluator( - val scriptSource: KotlinScriptSource, - val scriptTarget: KotlinScriptTarget, - val buildscriptBlockRange: IntRange?, - val classPath: Lazy, - val baseScope: ClassLoaderScope, - val kotlinCompiler: CachingKotlinCompiler, - val embeddedKotlinProvider: EmbeddedKotlinProvider, - val classloadingCache: KotlinScriptClassloadingCache -) { - - fun evaluate() { - scriptTarget.buildscriptBlockTemplate?.let { template -> - setupEmbeddedKotlinForBuildscript() - buildscriptBlockRange?.let { buildscriptRange -> - executeBuildscriptBlockFrom(buildscriptRange, template) - } - } - } - - private - fun compileBuildscriptBlock(scriptBlock: ScriptBlock) = - withKotlinCompiler { - compileScriptBlock(scriptBlock, classPath.value) - } - - private - fun buildscriptBlockClassLoaderScope() = - baseScopeFor("buildscript") - - private - fun baseScopeFor(stage: String) = - baseScope.createChild(classLoaderScopeIdFor(stage)) - - private - fun classLoaderScopeIdFor(stage: String) = - scriptSource.classLoaderScopeIdFor(stage) - - private - fun loadBuildscriptBlockClass(scriptBlock: ScriptBlock) = - classloadingCache.loadScriptClass( - scriptBlock, - baseScope.exportClassLoader, - ::buildscriptBlockClassLoaderScope, - ::compileBuildscriptBlock) - - private - fun executeBuildscriptBlockFrom(buildscriptRange: IntRange, scriptTemplate: KClass<*>) = - loadBuildscriptBlockClass(scriptBlockForBuildscript(buildscriptRange, scriptTemplate)) - .eval(scriptSource) { - scriptTarget.eval(scriptClass) - } - - private - fun scriptBlockForBuildscript(buildscriptRange: IntRange, scriptTemplate: KClass<*>) = - ScriptBlock( - "$buildscriptBlockName block '$scriptPath'", - scriptTemplate, - scriptPath, - script.linePreservingSubstring(buildscriptRange), - Unit) - - private - fun setupEmbeddedKotlinForBuildscript() = - embeddedKotlinProvider.run { - val scriptHandler = scriptTarget.scriptHandler - addRepositoryTo(scriptHandler.repositories) - pinDependenciesOn( - scriptHandler.configurations["classpath"], - "stdlib-jdk8", "reflect") - } - - private - fun withKotlinCompiler(action: CachingKotlinCompiler.() -> T): T = - scriptSource.withLocationAwareExceptionHandling { - action(kotlinCompiler) - } - - private - val scriptPath - get() = scriptSource.scriptPath - - private - val script - get() = scriptSource.script - - private - val buildscriptBlockName - get() = scriptTarget.buildscriptBlockName -} - - -private -inline fun ClassPathModeExceptionCollector.ignoringErrors(action: () -> Unit) = - try { - action() - } catch (e: Exception) { - e.printStackTrace() - collect(e) - } - - -private -inline fun KotlinScriptSource.withLocationAwareExceptionHandling(action: () -> T): T = - try { - action() - } catch (e: ScriptCompilationException) { - throw LocationAwareException(e, source, e.firstErrorLine) - } - - -private -inline fun LoadedScriptClass.eval(scriptSource: KotlinScriptSource, action: LoadedScriptClass.() -> Unit) = - withContextClassLoader(scriptClass.classLoader) { - withLocationAwareExceptionHandling(scriptSource, action) - } - - -private -inline fun LoadedScriptClass.withLocationAwareExceptionHandling( - scriptSource: KotlinScriptSource, - action: LoadedScriptClass.() -> Unit -) = - try { - action() - } catch (e: Throwable) { - val targetException = maybeUnwrapInvocationTargetException(e) - val locationAware = locationAwareExceptionFor(targetException, scriptSource.source) - throw locationAware ?: targetException - } - - -private -fun LoadedScriptClass<*>.locationAwareExceptionFor( - original: Throwable, - scriptSource: ScriptSource -): LocationAwareException? { - - val scriptClassName = compiledScript.className - val scriptClassNameInnerPrefix = "$scriptClassName$" - - fun scriptStackTraceElement(element: StackTraceElement) = - element.className?.run { - equals(scriptClassName) || startsWith(scriptClassNameInnerPrefix) - } == true - - tailrec fun inferLocationFrom(exception: Throwable): LocationAwareException? { - - if (exception is LocationAwareException) { - return exception - } - - exception.stackTrace.find(::scriptStackTraceElement)?.run { - return LocationAwareException(original, scriptSource, lineNumber.takeIf { it >= 0 }) - } - - val cause = exception.cause ?: return null - return inferLocationFrom(cause) - } - - return inferLocationFrom(original) -} - - -private -fun maybeUnwrapInvocationTargetException(e: Throwable) = - if (e is InvocationTargetException) e.targetException - else e - - -private -inline fun withContextClassLoader(classLoader: ClassLoader, block: () -> Unit) { - val currentThread = Thread.currentThread() - val previous = currentThread.contextClassLoader - try { - currentThread.contextClassLoader = classLoader - block() - } finally { - currentThread.contextClassLoader = previous - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptFactory.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptFactory.kt (revision bb670839befd1b5c5d2b2c67299775ed98929134) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptFactory.kt (revision 0) @@ -1,104 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.initialization.dsl.ScriptHandler -import org.gradle.api.internal.initialization.ClassLoaderScope -import org.gradle.api.internal.initialization.ScriptHandlerInternal - -import org.gradle.groovy.scripts.ScriptSource - -import org.gradle.kotlin.dsl.support.EmbeddedKotlinProvider - -import java.util.* - - -interface KotlinScriptFactory { - - fun kotlinScriptFor( - target: Any, - scriptSource: ScriptSource, - scriptHandler: ScriptHandler, - targetScope: ClassLoaderScope, - baseScope: ClassLoaderScope, - topLevelScript: Boolean, - options: EnumSet - ): KotlinScript -} - - -enum class KotlinScriptOption { - IgnoreErrors, - SkipBody -} - - -typealias KotlinScript = () -> Unit - - -internal -class StandardKotlinScriptFactory( - private val classPathProvider: KotlinScriptClassPathProvider, - private val kotlinCompiler: CachingKotlinCompiler, - private val classloadingCache: KotlinScriptClassloadingCache, - private val pluginRequestsHandler: PluginRequestsHandler, - private val embeddedKotlinProvider: EmbeddedKotlinProvider, - private val classPathModeExceptionCollector: ClassPathModeExceptionCollector -) : KotlinScriptFactory { - - override fun kotlinScriptFor( - target: Any, - scriptSource: ScriptSource, - scriptHandler: ScriptHandler, - targetScope: ClassLoaderScope, - baseScope: ClassLoaderScope, - topLevelScript: Boolean, - options: EnumSet - ): KotlinScript { - - val scriptTarget = kotlinScriptTargetFor(target, scriptSource, scriptHandler, baseScope, topLevelScript) - val kotlinScriptSource = KotlinScriptSource(scriptSource) - return compilerFor(scriptTarget, kotlinScriptSource, scriptHandler, targetScope, baseScope).run { - if (KotlinScriptOption.IgnoreErrors in options) - compileIgnoringErrors(executeScriptBody = KotlinScriptOption.SkipBody !in options) - else - compile() - } - } - - private - fun compilerFor( - scriptTarget: KotlinScriptTarget, - scriptSource: KotlinScriptSource, - scriptHandler: ScriptHandler, - targetScope: ClassLoaderScope, - baseScope: ClassLoaderScope - ) = - - KotlinScriptCompiler( - kotlinCompiler, - classloadingCache, - scriptSource, - scriptTarget, - scriptHandler as ScriptHandlerInternal, - pluginRequestsHandler, - baseScope, - targetScope, - classPathProvider, - embeddedKotlinProvider, - classPathModeExceptionCollector) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptPlugin.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptPlugin.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptPlugin.kt (revision 0) @@ -1,38 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.configuration.ScriptPlugin -import org.gradle.groovy.scripts.ScriptSource -import org.gradle.kotlin.dsl.support.loggerFor - - -class KotlinScriptPlugin( - private val scriptSource: ScriptSource, - private val script: (Any) -> Unit -) : ScriptPlugin { - - private - val logger = loggerFor() - - override fun getSource() = scriptSource - - override fun apply(target: Any) { - logger.debug("Applying Kotlin script to {}", target) - script(target) - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptPluginFactory.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptPluginFactory.kt (revision 7119b76408e0dc8545d7ee25c03359ba2fa607af) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptPluginFactory.kt (revision 0) @@ -1,62 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.initialization.dsl.ScriptHandler -import org.gradle.api.internal.initialization.ClassLoaderScope - -import org.gradle.configuration.ScriptPlugin -import org.gradle.configuration.ScriptPluginFactory - -import org.gradle.groovy.scripts.ScriptSource - -import java.util.* - -import javax.inject.Inject - - -class KotlinScriptPluginFactory @Inject internal constructor( - private val kotlinScriptFactory: KotlinScriptFactory -) : ScriptPluginFactory { - - override fun create( - scriptSource: ScriptSource, - scriptHandler: ScriptHandler, - targetScope: ClassLoaderScope, - baseScope: ClassLoaderScope, - topLevelScript: Boolean - ): ScriptPlugin = - - KotlinScriptPlugin(scriptSource) { target -> - - kotlinScriptFactory - .kotlinScriptFor( - target, - scriptSource, - scriptHandler, - targetScope, - baseScope, - topLevelScript, - kotlinScriptOptions()) - .invoke() - } - - private - fun kotlinScriptOptions(): EnumSet = - if (inClassPathMode()) EnumSet.of(KotlinScriptOption.IgnoreErrors) - else EnumSet.noneOf(KotlinScriptOption::class.java) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptTarget.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptTarget.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptTarget.kt (revision 0) @@ -1,179 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.Project -import org.gradle.api.initialization.Settings -import org.gradle.api.initialization.dsl.ScriptHandler -import org.gradle.api.internal.GradleInternal -import org.gradle.api.internal.initialization.ClassLoaderScope -import org.gradle.api.internal.project.ProjectInternal -import org.gradle.api.invocation.Gradle - -import org.gradle.groovy.scripts.ScriptSource - -import org.gradle.internal.classpath.ClassPath - -import org.gradle.kotlin.dsl.KotlinBuildScript -import org.gradle.kotlin.dsl.KotlinInitScript -import org.gradle.kotlin.dsl.KotlinSettingsScript -import org.gradle.kotlin.dsl.accessors.AccessorsClassPath -import org.gradle.kotlin.dsl.accessors.accessorsClassPathFor -import org.gradle.kotlin.dsl.support.KotlinBuildscriptBlock -import org.gradle.kotlin.dsl.support.KotlinInitscriptBlock -import org.gradle.kotlin.dsl.support.KotlinPluginsBlock -import org.gradle.kotlin.dsl.support.KotlinScriptHost -import org.gradle.kotlin.dsl.support.KotlinSettingsBuildscriptBlock -import org.gradle.kotlin.dsl.support.serviceOf - -import java.lang.IllegalArgumentException - -import kotlin.reflect.KClass - - -internal -fun kotlinScriptTargetFor( - target: Any, - scriptSource: ScriptSource, - scriptHandler: ScriptHandler, - baseScope: ClassLoaderScope, - topLevelScript: Boolean -): KotlinScriptTarget = - - when (target) { - is Project -> projectScriptTarget(target, scriptSource, scriptHandler, baseScope, topLevelScript) - is Settings -> settingsScriptTarget(target, scriptSource, scriptHandler, baseScope) - is Gradle -> gradleInitScriptTarget(target, scriptHandler, scriptSource, baseScope) - else -> unsupportedTarget(target) - } - - -private -fun unsupportedTarget(target: Any): Nothing = - throw IllegalArgumentException("Unsupported target ${target::class.qualifiedName}: $target") - - -private -fun settingsScriptTarget( - settings: Settings, - scriptSource: ScriptSource, - scriptHandler: ScriptHandler, - baseScope: ClassLoaderScope -) = - - KotlinScriptTarget( - host = KotlinScriptHost(settings, scriptSource, serviceRegistryOf(settings), baseScope, scriptHandler), - scriptTemplate = KotlinSettingsScript::class, - buildscriptBlockTemplate = KotlinSettingsBuildscriptBlock::class, - extraSingleOrNoneBlockNames = listOf("pluginManagement")) - - -private -fun projectScriptTarget( - project: Project, - scriptSource: ScriptSource, - scriptHandler: ScriptHandler, - baseScope: ClassLoaderScope, - topLevelScript: Boolean -): KotlinScriptTarget = - - KotlinScriptTarget( - host = KotlinScriptHost(project, scriptSource, serviceRegistryOf(project), baseScope, scriptHandler), - scriptTemplate = KotlinBuildScript::class, - buildscriptBlockTemplate = KotlinBuildscriptBlock::class, - pluginsBlockTemplate = KotlinPluginsBlock::class.takeIf { topLevelScript }, - accessorsClassPath = accessorsClassPathProviderFor(project, topLevelScript), - onPrepare = { - afterEvaluate { - serviceOf().apply(this) - } - }) - - -internal -fun gradleInitScriptTarget( - gradle: Gradle, - scriptHandler: ScriptHandler, - scriptSource: ScriptSource, - baseScope: ClassLoaderScope -): KotlinScriptTarget = - - KotlinScriptTarget( - host = KotlinScriptHost(gradle, scriptSource, serviceRegistryOf(gradle), baseScope, scriptHandler), - scriptTemplate = KotlinInitScript::class, - buildscriptBlockTemplate = KotlinInitscriptBlock::class, - buildscriptBlockName = "initscript") - - -private -fun accessorsClassPathProviderFor(project: Project, topLevelScript: Boolean): AccessorsClassPathProvider = - if (topLevelScript) { classPath -> accessorsClassPathFor(project, classPath) } - else emptyAccessorsClassPathProvider - - -internal -typealias AccessorsClassPathProvider = (ClassPath) -> AccessorsClassPath - - -private -val emptyAccessorsClassPathProvider: AccessorsClassPathProvider = { AccessorsClassPath.empty } - - -internal -data class KotlinScriptTarget( - val host: KotlinScriptHost, - val scriptTemplate: KClass<*>, - val buildscriptBlockTemplate: KClass<*>?, - val pluginsBlockTemplate: KClass<*>? = null, - val accessorsClassPath: AccessorsClassPathProvider = emptyAccessorsClassPathProvider, - val buildscriptBlockName: String = "buildscript", - val extraSingleOrNoneBlockNames: List = emptyList(), - private val onPrepare: T.() -> Unit = {} -) { - - val `object` - get() = host.target - - val scriptHandler - get() = host.scriptHandler - - fun prepare() = - `object`.onPrepare() - - fun accessorsClassPathFor(classPath: ClassPath) = - accessorsClassPath(classPath) - - fun eval(scriptClass: Class<*>) { - scriptClass - .getConstructor(KotlinScriptHost::class.java) - .newInstance(host) - } -} - - -private -fun serviceRegistryOf(project: Project) = - (project as ProjectInternal).services - - -private -fun serviceRegistryOf(settings: Settings) = - serviceRegistryOf(settings.gradle) - - -private -fun serviceRegistryOf(gradle: Gradle) = - (gradle as GradleInternal).services Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/PluginRequestsHandler.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/PluginRequestsHandler.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/PluginRequestsHandler.kt (revision 0) @@ -1,59 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.internal.initialization.ClassLoaderScope -import org.gradle.api.internal.initialization.ScriptHandlerInternal -import org.gradle.api.internal.plugins.PluginAwareInternal - -import org.gradle.plugin.management.internal.DefaultPluginRequests -import org.gradle.plugin.management.internal.PluginRequests -import org.gradle.plugin.management.internal.autoapply.AutoAppliedPluginHandler - -import org.gradle.plugin.use.internal.PluginRequestApplicator - -import javax.inject.Inject - - -internal -class PluginRequestsHandler @Inject constructor( - private val pluginRequestApplicator: PluginRequestApplicator, - private val autoAppliedPluginHandler: AutoAppliedPluginHandler -) { - - fun handle( - pluginRequests: PluginRequests?, - scriptHandler: ScriptHandlerInternal, - target: PluginAwareInternal, - targetScope: ClassLoaderScope - ) { - - val effectivePluginRequests = pluginRequests - ?.let { withAutoAppliedPluginsFor(target, it) } - ?: DefaultPluginRequests.EMPTY - - pluginRequestApplicator.applyPlugins( - effectivePluginRequests, - scriptHandler, - target.pluginManager, - targetScope) - } - - private - fun withAutoAppliedPluginsFor(target: Any, pluginRequests: PluginRequests): PluginRequests = - autoAppliedPluginHandler.mergeWithAutoAppliedPlugins(pluginRequests, target) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ScriptApi.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ScriptApi.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/provider/ScriptApi.kt (revision 0) @@ -1,81 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.provider - -import org.gradle.api.PathValidation -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.ConfigurableFileTree -import org.gradle.api.file.CopySpec -import org.gradle.api.file.DeleteSpec -import org.gradle.api.file.FileTree -import org.gradle.api.logging.Logger -import org.gradle.api.logging.LoggingManager -import org.gradle.api.resources.ResourceHandler -import org.gradle.api.tasks.WorkResult -import org.gradle.process.ExecResult -import org.gradle.process.ExecSpec -import org.gradle.process.JavaExecSpec - -import java.io.File -import java.net.URI - - -/** - * Base contract for all Gradle Kotlin DSL scripts. - * - * This is the Kotlin flavored equivalent of [org.gradle.api.Script]. - * - * It is not implemented directly by script templates to overcome ambiguous conflicts and Kotlin language - * limitations. See each script template for actual implementations. - * - * `ScriptApiTest` validates that each script template provide compatible methods/properties. - * - * Members here must not use default parameters values. - * Documentation should go to the actual implementations so that it shows up in IDEs properly. - */ -@Suppress("unused") -internal -interface ScriptApi { - - val logger: Logger - val logging: LoggingManager - val resources: ResourceHandler - - fun relativePath(path: Any): String - fun uri(path: Any): URI - - fun file(path: Any): File - fun file(path: Any, validation: PathValidation): File - fun files(vararg paths: Any): ConfigurableFileCollection - fun files(paths: Any, configuration: ConfigurableFileCollection.() -> Unit): ConfigurableFileCollection - - fun fileTree(baseDir: Any): ConfigurableFileTree - fun fileTree(baseDir: Any, configuration: ConfigurableFileTree.() -> Unit): ConfigurableFileTree - fun zipTree(zipPath: Any): FileTree - fun tarTree(tarPath: Any): FileTree - - fun copy(configuration: CopySpec.() -> Unit): WorkResult - fun copySpec(): CopySpec - fun copySpec(configuration: CopySpec.() -> Unit): CopySpec - - fun mkdir(path: Any): File - - fun delete(vararg paths: Any): Boolean - fun delete(configuration: DeleteSpec.() -> Unit): WorkResult - - fun exec(configuration: ExecSpec.() -> Unit): ExecResult - fun javaexec(configuration: JavaExecSpec.() -> Unit): ExecResult -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/CompactTree.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/CompactTree.kt (revision 4d1723e63330228ec136b302d8724bc424407132) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/CompactTree.kt (revision 0) @@ -1,81 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.resolver - -import org.gradle.kotlin.dsl.provider.splitIncluding - -import java.io.File - - -internal -fun compactStringFor(files: Iterable) = - compactStringFor(files.map { it.path }, File.separatorChar) - - -internal -fun compactStringFor(paths: Iterable, separator: Char) = - CompactTree.Companion.of(paths.map { it.splitIncluding(separator).toList() }).toString() - - -private -sealed class CompactTree { - - companion object { - - fun of(paths: Iterable>): CompactTree = - paths - .filter { it.isNotEmpty() } - .groupBy({ it[0] }, { it.drop(1) }) - .map { (label, remaining) -> - val subTree = CompactTree.Companion.of(remaining) - when (subTree) { - is CompactTree.Empty -> CompactTree.Label(label) - is CompactTree.Label -> CompactTree.Label( - label + subTree.label - ) - is CompactTree.Branch -> CompactTree.Edge( - Label(label), subTree - ) - is CompactTree.Edge -> CompactTree.Edge( - Label(label + subTree.label), subTree.tree - ) - } - }.let { - when (it.size) { - 0 -> CompactTree.Empty - 1 -> it.first() - else -> CompactTree.Branch(it) - } - } - } - - object Empty : CompactTree() { - override fun toString() = "ø" - } - - data class Label(val label: String) : CompactTree() { - override fun toString() = label - } - - data class Branch(val edges: List) : CompactTree() { - override fun toString() = edges.joinToString(separator = ", ", prefix = "{", postfix = "}") - } - - data class Edge(val label: CompactTree.Label, val tree: CompactTree) : CompactTree() { - override fun toString() = "$label$tree" - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ExtractGradleSourcesTransform.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ExtractGradleSourcesTransform.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ExtractGradleSourcesTransform.kt (revision 0) @@ -1,55 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.resolver - -import org.gradle.api.artifacts.transform.ArtifactTransform - -import org.gradle.kotlin.dsl.support.unzipTo - -import java.io.File - - -/** - * This dependency transform is responsible for extracting the sources from - * a downloaded ZIP of the Gradle sources, and will return the list of main sources - * subdirectories for all subprojects. - */ -class ExtractGradleSourcesTransform : ArtifactTransform() { - - override fun transform(input: File): List { - unzipTo(outputDirectory, input) - return sourceDirectories() - } - - private - fun sourceDirectories() = - unzippedSubProjectsDir()?.let { - subDirsOf(it).flatMap { subProject -> - subDirsOf(File(subProject, "src/main")) - } - } ?: emptyList() - - private - fun unzippedSubProjectsDir(): File? = - unzippedDistroDir()?.let { - File(it, "subprojects") - } - - private - fun unzippedDistroDir(): File? = - outputDirectory.listFiles().singleOrNull() -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/KotlinBuildScriptDependenciesResolver.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/KotlinBuildScriptDependenciesResolver.kt (revision 851183815f29aed6752e77949782a31535519e3b) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/KotlinBuildScriptDependenciesResolver.kt (revision 0) @@ -1,287 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.resolver - -import org.gradle.kotlin.dsl.tooling.models.KotlinBuildScriptModel - -import org.gradle.kotlin.dsl.concurrent.future - -import java.io.File - -import java.net.URI - -import java.security.MessageDigest - -import java.util.Arrays.equals - -import kotlin.script.dependencies.KotlinScriptExternalDependencies -import kotlin.script.dependencies.ScriptContents -import kotlin.script.dependencies.ScriptContents.Position -import kotlin.script.dependencies.ScriptDependenciesResolver -import kotlin.script.dependencies.ScriptDependenciesResolver.ReportSeverity - - -internal -typealias Environment = Map - - -private -typealias Report = (ReportSeverity, String, Position?) -> Unit - - -private -fun Report.warning(message: String) = - invoke(ReportSeverity.WARNING, message, null) - - -private -fun Report.error(message: String) = - invoke(ReportSeverity.ERROR, message, null) - - -class KotlinBuildScriptDependenciesResolver : ScriptDependenciesResolver { - - override fun resolve( - script: ScriptContents, - environment: Map?, - /** - * Shows a message in the IDE. - * - * To report whole file errors (e.g. failure to query for dependencies), one can just pass a - * null position so the error/warning will be shown in the top panel of the editor - * - * Also there is a FATAL Severity - in this case the highlighting of the file will be - * switched off (may be it is useful for some errors). - */ - report: (ReportSeverity, String, Position?) -> Unit, - previousDependencies: KotlinScriptExternalDependencies? - ) = future { - - try { - log(ResolutionRequest(script.file, environment, previousDependencies)) - val action = ResolverCoordinator.selectNextActionFor(script, environment, previousDependencies) - when (action) { - is ResolverAction.Return -> { - action.dependencies - } - is ResolverAction.ReturnPrevious -> { - log(ResolvedToPrevious(script.file, previousDependencies)) - previousDependencies - } - is ResolverAction.RequestNew -> { - assembleDependenciesFrom( - script.file, - environment!!, - report, - previousDependencies, - action.buildscriptBlockHash) - } - } - } catch (e: Exception) { - if (previousDependencies == null) report.error("Script dependencies resolution failed") - else report.warning("Script dependencies resolution failed, using previous dependencies") - log(ResolutionFailure(script.file, e)) - previousDependencies - } - } - - private - suspend fun assembleDependenciesFrom( - scriptFile: File?, - environment: Environment, - report: Report, - previousDependencies: KotlinScriptExternalDependencies?, - buildscriptBlockHash: ByteArray? - ): KotlinScriptExternalDependencies { - - val request = modelRequestFrom(scriptFile, environment) - log(SubmittedModelRequest(scriptFile, request)) - - val response = fetchKotlinBuildScriptModelFor(request) - log(ReceivedModelResponse(scriptFile, response)) - - return when { - response.exceptions.isEmpty() -> - dependenciesFrom(response, buildscriptBlockHash).also { - log(ResolvedDependencies(scriptFile, it)) - } - previousDependencies != null && previousDependencies.classpath.count() > response.classPath.size -> - previousDependencies.also { - report.warning("There were some errors during script dependencies resolution, using previous dependencies") - log(ResolvedToPreviousWithErrors(scriptFile, previousDependencies, response.exceptions)) - } - else -> - dependenciesFrom(response, buildscriptBlockHash).also { - report.warning("There were some errors during script dependencies resolution, some dependencies might be missing") - log(ResolvedDependenciesWithErrors(scriptFile, it, response.exceptions)) - } - } - } - - private - fun modelRequestFrom(scriptFile: File?, environment: Environment): KotlinBuildScriptModelRequest { - - @Suppress("unchecked_cast") - fun stringList(key: String) = - (environment[key] as? List) ?: emptyList() - - fun path(key: String) = - (environment[key] as? String)?.let(::File) - - val importedProjectRoot = environment["projectRoot"] as File - return KotlinBuildScriptModelRequest( - projectDir = scriptFile?.let { projectRootOf(it, importedProjectRoot) } ?: importedProjectRoot, - scriptFile = scriptFile, - gradleInstallation = gradleInstallationFrom(environment), - gradleUserHome = path("gradleUserHome"), - javaHome = path("gradleJavaHome"), - options = stringList("gradleOptions"), - jvmOptions = stringList("gradleJvmOptions")) - } - - private - fun gradleInstallationFrom(environment: Environment): GradleInstallation = - (environment["gradleHome"] as? File)?.let(GradleInstallation::Local) - ?: (environment["gradleUri"] as? URI)?.let(GradleInstallation::Remote) - ?: (environment["gradleVersion"] as? String)?.let(GradleInstallation::Version) - ?: GradleInstallation.Wrapper - - private - fun dependenciesFrom( - response: KotlinBuildScriptModel, - hash: ByteArray? - ) = - - KotlinBuildScriptDependencies( - response.classPath, - response.sourcePath, - response.implicitImports, - hash) - - private - fun log(event: ResolverEvent) = - ResolverEventLogger.log(event) -} - - -/** - * The resolver can either return the previous result - * or request new dependency information from Gradle. - */ -internal -sealed class ResolverAction { - object ReturnPrevious : ResolverAction() - class RequestNew(val buildscriptBlockHash: ByteArray?) : ResolverAction() - class Return(val dependencies: KotlinScriptExternalDependencies?) : ResolverAction() -} - - -internal -object ResolverCoordinator { - - /** - * Decides which action the resolver should take based on the given [script] and [environment]. - */ - fun selectNextActionFor( - script: ScriptContents, - environment: Environment?, - previousDependencies: KotlinScriptExternalDependencies? - ): ResolverAction { - - if (environment == null) { - return ResolverAction.ReturnPrevious - } - - val buildscriptBlockHash = buildscriptBlockHashFor(script, environment) - if (sameBuildscriptBlockHashAs(previousDependencies, buildscriptBlockHash)) { - return ResolverAction.ReturnPrevious - } - - return ResolverAction.RequestNew(buildscriptBlockHash) - } - - private - fun sameBuildscriptBlockHashAs(previousDependencies: KotlinScriptExternalDependencies?, hash: ByteArray?) = - hash?.let { nonNullHash -> buildscriptBlockHashOf(previousDependencies)?.let { equals(it, nonNullHash) } } - ?: false - - private - fun buildscriptBlockHashOf(previousDependencies: KotlinScriptExternalDependencies?) = - (previousDependencies as? KotlinBuildScriptDependencies)?.buildscriptBlockHash - - private - fun buildscriptBlockHashFor(script: ScriptContents, environment: Environment): ByteArray? { - - @Suppress("unchecked_cast") - val getScriptSectionTokens = environment["getScriptSectionTokens"] as? ScriptSectionTokensProvider - return when (getScriptSectionTokens) { - null -> null - else -> - MessageDigest.getInstance("MD5").run { - val text = script.text ?: script.file?.readText() - text?.let { nonNullText -> - fun updateWith(section: String) = - getScriptSectionTokens(nonNullText, section).forEach { - update(it.toString().toByteArray()) - } - updateWith("buildscript") - updateWith("plugins") - } - digest() - } - } - } -} - - -internal -typealias ScriptSectionTokensProvider = (CharSequence, String) -> Sequence - - -internal -class KotlinBuildScriptDependencies( - override val classpath: Iterable, - override val sources: Iterable, - override val imports: Iterable, - val buildscriptBlockHash: ByteArray? -) : KotlinScriptExternalDependencies - - -internal -fun projectRootOf(scriptFile: File, importedProjectRoot: File): File { - - // TODO remove hardcoded reference to settings.gradle once there's a public TAPI client api for that - fun isProjectRoot(dir: File) = - File(dir, "settings.gradle.kts").isFile - || File(dir, "settings.gradle").isFile - || dir.name == "buildSrc" - - tailrec fun test(dir: File): File = - when { - dir == importedProjectRoot -> importedProjectRoot - isProjectRoot(dir) -> dir - else -> { - val parentDir = dir.parentFile - when (parentDir) { - null, dir -> scriptFile.parentFile // external project - else -> test(parentDir) - } - } - } - - return test(scriptFile.parentFile) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/KotlinBuildScriptModelRequest.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/KotlinBuildScriptModelRequest.kt (revision e0454a3b0e8af715ec53f5afa478df96663d0652) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/KotlinBuildScriptModelRequest.kt (revision 0) @@ -1,123 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.resolver - -import org.gradle.kotlin.dsl.concurrent.tapi -import org.gradle.kotlin.dsl.provider.KotlinDslProviderMode -import org.gradle.kotlin.dsl.tooling.models.KotlinBuildScriptModel - -import org.gradle.tooling.GradleConnector -import org.gradle.tooling.ModelBuilder - -import java.io.File - - -internal -sealed class GradleInstallation { - - data class Local(val dir: java.io.File) : GradleInstallation() - - data class Remote(val uri: java.net.URI) : GradleInstallation() - - data class Version(val number: String) : GradleInstallation() - - object Wrapper : GradleInstallation() -} - - -internal -data class KotlinBuildScriptModelRequest( - val projectDir: java.io.File, - val scriptFile: java.io.File? = null, - val gradleInstallation: GradleInstallation = GradleInstallation.Wrapper, - val gradleUserHome: java.io.File? = null, - val javaHome: java.io.File? = null, - val options: List = emptyList(), - val jvmOptions: List = emptyList() -) - - -internal -typealias ModelBuilderCustomization = ModelBuilder.() -> Unit - - -internal -suspend fun fetchKotlinBuildScriptModelFor( - request: KotlinBuildScriptModelRequest, - modelBuilderCustomization: ModelBuilderCustomization = {} -): KotlinBuildScriptModel { - - val connection = projectConnectionFor(request) - try { - return tapi { connection.modelBuilderFor(request).apply(modelBuilderCustomization).get(it) } - } finally { - // Run close on a separate thread as TAPI doesn't allow closing the connection from an executor thread - kotlin.concurrent.thread { connection.close() } - } -} - - -private -fun projectConnectionFor(request: KotlinBuildScriptModelRequest): org.gradle.tooling.ProjectConnection = - connectorFor(request).connect() - - -private -fun org.gradle.tooling.ProjectConnection.modelBuilderFor(request: KotlinBuildScriptModelRequest) = - model(KotlinBuildScriptModel::class.java).apply { - setJavaHome(request.javaHome) - setJvmArguments(request.jvmOptions + modelSpecificJvmOptions) - request.scriptFile?.let { - withArguments(request.options + "-P$kotlinBuildScriptModelTarget=${it.canonicalPath}") - } ?: withArguments(request.options) - } - - -private -val modelSpecificJvmOptions = - listOf("-D${KotlinDslProviderMode.systemPropertyName}=${KotlinDslProviderMode.classPathMode}") - - -const val kotlinBuildScriptModelTarget = "org.gradle.kotlin.dsl.provider.script" - - -internal -fun connectorFor(request: KotlinBuildScriptModelRequest): org.gradle.tooling.GradleConnector = - connectorFor(request.projectDir, request.gradleInstallation) - .useGradleUserHomeDir(request.gradleUserHome) - - -internal -fun connectorFor(projectDir: File, gradleInstallation: GradleInstallation): GradleConnector = - GradleConnector - .newConnector() - .forProjectDirectory(projectDir) - .let { connector -> - applyGradleInstallationTo(connector, gradleInstallation) - } - - -private -fun applyGradleInstallationTo(connector: GradleConnector, gradleInstallation: GradleInstallation): org.gradle.tooling.GradleConnector = - gradleInstallation.run { - when (this) { - is GradleInstallation.Local -> connector.useInstallation(dir) - is GradleInstallation.Remote -> connector.useDistribution(uri) - is GradleInstallation.Version -> connector.useGradleVersion(number) - GradleInstallation.Wrapper -> connector.useBuildDistribution() - } - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ResolverEvent.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ResolverEvent.kt (revision e1a19b2b552fd1dc08d0455b7def529e5ee670fc) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ResolverEvent.kt (revision 0) @@ -1,93 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.resolver - -import kotlin.script.dependencies.KotlinScriptExternalDependencies - -import org.gradle.kotlin.dsl.tooling.models.KotlinBuildScriptModel - -import java.io.File - - -internal -sealed class ResolverEvent - - -internal -data class ResolutionRequest( - val scriptFile: File?, - val environment: Map?, - val previousDependencies: KotlinScriptExternalDependencies? -) : ResolverEvent() - - -internal -data class ResolutionFailure( - val scriptFile: File?, - val failure: Exception -) : ResolverEvent() - - -internal -data class ResolutionProgress( - val scriptFile: File?, - val description: String -) : ResolverEvent() - - -internal -data class ResolvedToPrevious( - val scriptFile: File?, - val previousDependencies: KotlinScriptExternalDependencies? -) : ResolverEvent() - - -internal -data class SubmittedModelRequest( - val scriptFile: File?, - val request: KotlinBuildScriptModelRequest -) : ResolverEvent() - - -internal -data class ReceivedModelResponse( - val scriptFile: File?, - val response: KotlinBuildScriptModel -) : ResolverEvent() - - -internal -data class ResolvedDependencies( - val scriptFile: File?, - val dependencies: KotlinScriptExternalDependencies -) : ResolverEvent() - - -internal -data class ResolvedDependenciesWithErrors( - val scriptFile: File?, - val dependencies: KotlinScriptExternalDependencies, - val exceptions: List -) : ResolverEvent() - - -internal -data class ResolvedToPreviousWithErrors( - val scriptFile: File?, - val dependencies: KotlinScriptExternalDependencies, - val exceptions: List -) : ResolverEvent() Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ResolverEventLogger.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ResolverEventLogger.kt (revision 136fed996c616e5de9a7e6a883032ccb3508c558) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/ResolverEventLogger.kt (revision 0) @@ -1,210 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.resolver - -import org.gradle.internal.os.OperatingSystem -import org.gradle.kotlin.dsl.support.userHome - -import org.gradle.kotlin.dsl.tooling.models.KotlinBuildScriptModel - -import java.io.BufferedWriter -import java.io.File -import java.io.FileWriter -import java.io.PrintWriter -import java.io.StringWriter - -import java.text.SimpleDateFormat - -import java.util.* -import java.util.concurrent.ArrayBlockingQueue -import java.util.concurrent.TimeUnit - -import kotlin.concurrent.thread -import kotlin.reflect.KProperty1 -import kotlin.reflect.full.declaredMemberProperties - - -private -const val offerTimeoutMillis = 50L - - -private -const val pollTimeoutMillis = 5_000L - - -internal -object ResolverEventLogger { - - fun log(event: ResolverEvent) { - q.offer(now() to event, offerTimeoutMillis, TimeUnit.MILLISECONDS) - ensureAliveConsumer() - } - - private - val q = ArrayBlockingQueue>(64) - - private - val outputFile by lazy { - File(outputDir(), "resolver-${timestampForFileName()}.log") - } - - private - var consumer: Thread? = null - - private - fun ensureAliveConsumer() = synchronized(ResolverEventLogger) { - if (consumer?.isAlive != true) { - consumer = newConsumerThread() - } - } - - private - fun newConsumerThread() = thread { - - val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") - - bufferedAppendWriter().use { writer -> - - fun write(timestamp: Date, e: ResolverEvent) { - try { - writer.write("${format.format(timestamp)} - ${prettyPrint(e)}\n\n") - } catch (e: Exception) { - e.printStackTrace(PrintWriter(writer)) - } finally { - writer.flush() - } - } - - while (true) { - val (timestamp, event) = q.poll(pollTimeoutMillis, TimeUnit.MILLISECONDS) ?: break - write(timestamp, event) - } - } - } - - private - fun bufferedAppendWriter() = - BufferedWriter(FileWriter(outputFile, true)) - - private - fun timestampForFileName() = - SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS").format(now()) - - private - fun outputDir() = - File(userHome(), logDirForOperatingSystem()).apply { mkdirs() } - - private - fun logDirForOperatingSystem() = - OperatingSystem.current().run { - when { - isMacOsX -> "Library/Logs/gradle-kotlin-dsl" - isWindows -> "Application Data/gradle-kotlin-dsl/log" - else -> ".gradle-kotlin-dsl/log" - } - } - - private - fun now() = GregorianCalendar.getInstance().time - - private - fun prettyPrint(e: ResolverEvent): String = e.run { - when (this) { - is SubmittedModelRequest -> - prettyPrint( - "SubmittedModelRequest", - sequenceOf( - "scriptFile" to scriptFile, - "request" to prettyPrintAny(request, indentation = 2))) - - is ReceivedModelResponse -> - prettyPrint( - "ReceivedModelResponse", - sequenceOf( - "scriptFile" to scriptFile, - "response" to prettyPrint(response, indentation = 2))) - - is ResolutionFailure -> - prettyPrint( - "ResolutionFailure", - sequenceOf( - "scriptFile" to scriptFile, - "failure" to stringForException(failure, indentation = 2))) - else -> - prettyPrintAny(this) - } - } - - private - fun prettyPrintAny(any: Any, indentation: Int? = null) = - prettyPrint( - any::class.simpleName, - any::class - .declaredMemberProperties - .asSequence() - .filterIsInstance>() - .map { it.name to it.get(any) }, - indentation) - - private - fun prettyPrint(model: KotlinBuildScriptModel, indentation: Int?) = model.run { - prettyPrint( - "KotlinBuildScriptModel", - sequenceOf( - "classPath" to compactStringFor(classPath), - "sourcePath" to compactStringFor(sourcePath), - "implicitImports" to compactStringFor(implicitImports, '.'), - "exceptions" to stringForExceptions(exceptions, indentation)), - indentation) - } - - private - fun prettyPrint(className: String?, properties: Sequence>, indentation: Int? = null) = - "$className(${prettyPrint(properties, indentation)})" - - private - fun prettyPrint(properties: Sequence>, indentation: Int?) = - indentationStringFor(indentation).let { - properties.joinToString(prefix = "\n$it", separator = ",\n$it") { (name, value) -> - "$name = $value" - } - } - - private - fun stringForExceptions(exceptions: List, indentation: Int?) = - if (exceptions.isNotEmpty()) - indentationStringFor(indentation).let { - exceptions.joinToString(prefix = "[\n$it\t", separator = ",\n$it\t", postfix = "]") { exception -> - stringForException(exception, indentation) - } - } - else "NO ERROR" - - private - fun stringForException(exception: Exception, indentation: Int?) = - indentationStringFor(indentation).let { - StringWriter().also { writer -> exception.printStackTrace(PrintWriter(writer)) }.toString() - .prependIndent(it) - } - - private - fun indentationStringFor(indentation: Int?) = - when (indentation) { - null, 1 -> "\t" - else -> "\t\t" - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/SourceDistributionProvider.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/SourceDistributionProvider.kt (revision b6347db349872b3232f0242eef2e13e5c7ffd8e9) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/SourceDistributionProvider.kt (revision 0) @@ -1,174 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.resolver - -import org.gradle.api.Project -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.repositories.ArtifactRepository -import org.gradle.api.artifacts.repositories.IvyArtifactRepository -import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout -import org.gradle.api.artifacts.transform.VariantTransform -import org.gradle.api.attributes.Attribute - -import org.gradle.kotlin.dsl.create - -import java.io.File - -import java.lang.Integer.max - - -interface SourceDistributionProvider { - fun sourceDirs(): Collection -} - - -class SourceDistributionResolver(val project: Project) : SourceDistributionProvider { - - companion object { - val artifactType = Attribute.of("artifactType", String::class.java) - val zipType = "zip" - val sourceDirectory = "src-directory" - } - - override fun sourceDirs(): Collection = - try { - collectSourceDirs() - } catch (ex: Exception) { - project.logger.warn("Unexpected exception while resolving Gradle distribution sources: ${ex.message}", ex) - emptyList() - } - - private - fun collectSourceDirs() = - withSourceRepository { - registerTransforms() - transientConfigurationForSourcesDownload().files - } - - private - fun withSourceRepository(produce: () -> T): T = - createSourceRepository().let { - try { - produce() - } finally { - repositories.remove(it) - } - } - - private - fun registerTransforms() = - registerTransform { - from.attribute(artifactType, zipType) - to.attribute(artifactType, sourceDirectory) - artifactTransform(ExtractGradleSourcesTransform::class.java) - } - - private - fun transientConfigurationForSourcesDownload() = - detachedConfigurationFor(gradleSourceDependency()).apply { - attributes.attribute(artifactType, sourceDirectory) - } - - private - fun detachedConfigurationFor(dependency: Dependency) = - configurations.detachedConfiguration(dependency) - - private - fun gradleSourceDependency() = dependencies.create( - group = "gradle", - name = "gradle", - version = dependencyVersion(gradleVersion), - configuration = null, - classifier = "src", - ext = "zip") - - private - fun createSourceRepository() = ivy { - val repoName = repositoryNameFor(gradleVersion) - name = "Gradle $repoName" - setUrl("https://services.gradle.org/$repoName") - metadataSources { sources -> - sources.artifact() - } - layout("pattern") { - val layout = it as IvyPatternRepositoryLayout - if (isSnapshot(gradleVersion)) { - layout.ivy("/dummy") // avoids a lookup that interferes with version listing - } - layout.artifact("[module]-[revision](-[classifier])(.[ext])") - } - }.also { - // push the repository first in the list, for performance - makeItFirstInTheList(it) - } - - private - fun repositoryNameFor(gradleVersion: String) = - if (isSnapshot(gradleVersion)) "distributions-snapshots" else "distributions" - - private - fun dependencyVersion(gradleVersion: String) = - if (isSnapshot(gradleVersion)) toVersionRange(gradleVersion) else gradleVersion - - private - fun isSnapshot(gradleVersion: String) = gradleVersion.contains('+') - - private - fun toVersionRange(gradleVersion: String) = - "(${previousMinor(gradleVersion)}, $gradleVersion]" - - private - fun previousMinor(gradleVersion: String): String = - gradleVersion - .split('.') - .take(2) - .map { it.takeWhile { it != '-' }.toInt() } - .mapIndexed { i, v -> if (i == 0) v else max(v - 1, 0) } - .joinToString(".") { it.toString() } - - private - fun makeItFirstInTheList(repository: ArtifactRepository) { - repositories.apply { - remove(repository) - addFirst(repository) - } - } - - private - fun registerTransform(configure: VariantTransform.() -> Unit) = - dependencies.registerTransform { configure(it) } - - private - fun ivy(configure: IvyArtifactRepository.() -> Unit) = - repositories.ivy { configure(it) } - - private - val repositories - get() = project.repositories - - private - val configurations - get() = project.configurations - - private - val dependencies - get() = project.dependencies - - private - val gradleVersion - get() = project.gradle.gradleVersion -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/SourcePathProvider.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/SourcePathProvider.kt (revision cf6cd8a75dd1edbb2a86cbfe9634fc682550df0b) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/resolver/SourcePathProvider.kt (revision 0) @@ -1,77 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.resolver - -import org.gradle.internal.classpath.ClassPath - -import org.gradle.kotlin.dsl.support.filter - -import java.io.File - - -const val buildSrcSourceRootsFilePath = "build/source-roots/buildSrc/source-roots.txt" - - -object SourcePathProvider { - - fun sourcePathFor( - classPath: ClassPath, - projectDir: File, - gradleHomeDir: File?, - sourceDistributionResolver: SourceDistributionProvider - ): ClassPath { - - val gradleKotlinDslJar = classPath.filter { it.name.startsWith("gradle-kotlin-dsl-") } - val projectBuildSrcRoots = buildSrcRootsOf(projectDir) - val gradleSourceRoots = gradleHomeDir?.let { sourceRootsOf(it, sourceDistributionResolver) } ?: emptyList() - - return gradleKotlinDslJar + projectBuildSrcRoots + gradleSourceRoots - } - - /** - * Returns source directories from buildSrc if any. - */ - private - fun buildSrcRootsOf(projectRoot: File): Collection = - projectRoot.resolve("buildSrc/$buildSrcSourceRootsFilePath") - .takeIf { it.isFile } - ?.readLines() - ?.map { projectRoot.resolve("buildSrc/$it") } - ?: buildSrcRootsFallbackFor(projectRoot) - - private - fun buildSrcRootsFallbackFor(projectRoot: File) = - subDirsOf(File(projectRoot, "buildSrc/src/main")) - - private - fun sourceRootsOf(gradleInstallation: File, sourceDistributionResolver: SourceDistributionProvider): Collection = - gradleInstallationSources(gradleInstallation) ?: downloadedSources(sourceDistributionResolver) - - private - fun gradleInstallationSources(gradleInstallation: File) = - File(gradleInstallation, "src").takeIf { it.exists() }?.let { subDirsOf(it) } - - private - fun downloadedSources(sourceDistributionResolver: SourceDistributionProvider) = - sourceDistributionResolver.sourceDirs() -} - - -internal -fun subDirsOf(dir: File): Collection = - if (dir.isDirectory) dir.listFiles().filter { it.isDirectory } - else emptyList() Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/services/KotlinScriptServiceRegistry.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/services/KotlinScriptServiceRegistry.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/services/KotlinScriptServiceRegistry.kt (revision 0) @@ -1,39 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.services - -import org.gradle.internal.service.ServiceRegistration -import org.gradle.internal.service.scopes.AbstractPluginServiceRegistry - - -internal -class KotlinScriptServiceRegistry : AbstractPluginServiceRegistry() { - - override fun registerBuildServices(registration: ServiceRegistration) { - registration.addProvider(org.gradle.kotlin.dsl.cache.BuildServices) - registration.addProvider(org.gradle.kotlin.dsl.provider.BuildServices) - } - - override fun registerGlobalServices(registration: ServiceRegistration) { - registration.addProvider(org.gradle.kotlin.dsl.support.GlobalServices) - } - - override fun registerGradleUserHomeServices(registration: ServiceRegistration) { - registration.addProvider(org.gradle.kotlin.dsl.support.GradleUserHomeServices) - registration.addProvider(org.gradle.kotlin.dsl.provider.GradleUserHomeServices) - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ClassLoaderScopeExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ClassLoaderScopeExtensions.kt (revision b67e44737e3384e36a06add5d858d9273fd77bb1) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ClassLoaderScopeExtensions.kt (revision 0) @@ -1,49 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.api.internal.initialization.ClassLoaderScope - - -internal -val ClassLoaderScope.root - get() = foldHierarchy(this) { _, scope -> scope } - - -internal -inline fun ClassLoaderScope.foldHierarchy(initial: T, operation: (T, ClassLoaderScope) -> T): T { - var result = initial - traverseHierarchy { result = operation(result, it) } - return result -} - - -internal -inline fun ClassLoaderScope.traverseHierarchy(action: (ClassLoaderScope) -> Unit) { - action(this) - traverseAncestors(action) -} - - -internal -inline fun ClassLoaderScope.traverseAncestors(action: (ClassLoaderScope) -> Unit) { - var scope = this - while (scope.parent != scope) { - scope = scope.parent - action(scope) - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ClassPathExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ClassPathExtensions.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ClassPathExtensions.kt (revision 0) @@ -1,32 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.internal.classpath.ClassPath -import org.gradle.internal.classpath.DefaultClassPath - -import java.io.File - - -internal -fun ClassPath.filter(predicate: (File) -> Boolean): ClassPath = - DefaultClassPath.of(asFiles.filter(predicate)) - - -internal -operator fun ClassPath.minus(other: ClassPath): ClassPath = - DefaultClassPath.of(asFiles - other.asFiles) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/EmbeddedKotlinProvider.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/EmbeddedKotlinProvider.kt (revision 2ace916d78478c29232fea5086c326ba58da4d21) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/EmbeddedKotlinProvider.kt (revision 0) @@ -1,184 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.support - -import org.gradle.api.artifacts.ClientModule -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.ModuleVersionSelector -import org.gradle.api.artifacts.dsl.DependencyHandler -import org.gradle.api.artifacts.dsl.RepositoryHandler -import org.gradle.api.internal.classpath.ModuleRegistry - -import org.gradle.cache.CacheRepository -import org.gradle.cache.PersistentCache - -import org.gradle.kotlin.dsl.embeddedKotlinVersion - -import java.io.File - -import java.net.URI -import java.util.* - - -private -const val embeddedRepositoryCacheKeyVersion = 2 - - -private -data class EmbeddedModule( - val group: String, - val name: String, - val version: String, - val dependencies: List = emptyList() -) { - - val notation = "$group:$name:$version" - val jarRepoPath = "${group.replace(".", "/")}/$name/$version/$name-$version.jar" -} - - -private -val embeddedModules: List by lazy { - - fun embeddedKotlin(name: String, dependencies: List = emptyList()) = - EmbeddedModule("org.jetbrains.kotlin", "kotlin-$name", embeddedKotlinVersion, dependencies) - - // TODO:pm could be generated at build time - val annotations = EmbeddedModule("org.jetbrains", "annotations", "13.0") - val stdlib = embeddedKotlin("stdlib", listOf(annotations)) - val stdlibJdk7 = embeddedKotlin("stdlib-jdk7", listOf(stdlib)) - val stdlibJdk8 = embeddedKotlin("stdlib-jdk8", listOf(stdlibJdk7)) - val reflect = embeddedKotlin("reflect", listOf(stdlib)) - val compilerEmbeddable = embeddedKotlin("compiler-embeddable") - val scriptRuntime = embeddedKotlin("script-runtime") - val samWithReceiverCompilerPlugin = embeddedKotlin("sam-with-receiver-compiler-plugin") - listOf( - annotations, - stdlib, stdlibJdk7, stdlibJdk8, - reflect, - compilerEmbeddable, - scriptRuntime, - samWithReceiverCompilerPlugin) -} - - -class EmbeddedKotlinProvider constructor( - private val cacheRepository: CacheRepository, - private val moduleRegistry: ModuleRegistry -) { - - fun addRepositoryTo(repositories: RepositoryHandler) { - - repositories.maven { repo -> - repo.name = "Embedded Kotlin Repository" - repo.url = embeddedKotlinRepositoryURI() - repo.metadataSources { sources -> - sources.artifact() - } - } - } - - fun addDependenciesTo( - dependencies: DependencyHandler, - configuration: String, - vararg kotlinModules: String - ) { - - embeddedKotlinModulesFor(kotlinModules).forEach { embeddedKotlinModule -> - dependencies.add(configuration, clientModuleFor(dependencies, embeddedKotlinModule)) - } - } - - fun pinDependenciesOn(configuration: Configuration, vararg kotlinModules: String) { - val pinnedDependencies = transitiveClosureOf(embeddedKotlinModulesFor(kotlinModules)) - configuration.resolutionStrategy.eachDependency { details -> - pinnedDependencies.findWithSameGroupAndNameAs(details.requested)?.let { pinned -> - details.useTarget(pinned.notation) - } - } - } - - private - fun embeddedKotlinModulesFor(kotlinModules: Array) = - kotlinModules.map { embeddedKotlinModuleFor(it) } - - private - fun transitiveClosureOf(modules: Collection): Set = - identitySetOf().apply { - val q = ArrayDeque(modules) - while (q.isNotEmpty()) { - val module = q.removeFirst() - if (add(module)) { - q.addAll(module.dependencies) - } - } - } - - private - fun identitySetOf(): MutableSet = - Collections.newSetFromMap(IdentityHashMap()) - - private - fun embeddedKotlinRepositoryURI(): URI = - embeddedKotlinRepositoryDir().toURI() - - private - fun embeddedKotlinRepositoryDir(): File = - cacheFor(repoDirCacheKey()).withInitializer { cache -> - copyEmbeddedKotlinModulesTo(cache) - }.open().use { cache -> - repoDirFrom(cache) - } - - private - fun cacheFor(cacheKey: String) = - cacheRepository.cache(cacheKey) - - private - fun copyEmbeddedKotlinModulesTo(cache: PersistentCache) { - embeddedModules.forEach { module -> - fileFor(module).copyTo(File(repoDirFrom(cache), module.jarRepoPath)) - } - } - - private - fun fileFor(module: EmbeddedModule) = - moduleRegistry.getExternalModule(module.name).classpath.asFiles.first() - - private - fun repoDirCacheKey() = - "embedded-kotlin-repo-$embeddedKotlinVersion-$embeddedRepositoryCacheKeyVersion" - - private - fun repoDirFrom(cache: PersistentCache) = - File(cache.baseDir, "repo") - - private - fun clientModuleFor(dependencies: DependencyHandler, embeddedModule: EmbeddedModule): ClientModule = - (dependencies.module(embeddedModule.notation) as ClientModule).apply { - embeddedModule.dependencies.forEach { dependency -> - addDependency(clientModuleFor(dependencies, dependency)) - } - } - - private - fun embeddedKotlinModuleFor(kotlinModule: String) = - embeddedModules.first { it.group == "org.jetbrains.kotlin" && it.name == "kotlin-$kotlinModule" } - - private - fun Iterable.findWithSameGroupAndNameAs(requested: ModuleVersionSelector) = - find { it.name == requested.name && it.group == requested.group } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Exceptions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Exceptions.kt (revision b1f99e3384d28e602942979051dd3c5ea7deac00) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Exceptions.kt (revision 0) @@ -1,31 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.api.NamedDomainObjectCollection - -import kotlin.reflect.KClass - - -fun illegalElementType(container: NamedDomainObjectCollection<*>, name: String, expectedType: KClass<*>, actualType: KClass<*>) = - IllegalArgumentException( - "Element '$name' of type '${actualType.java.name}' from container '$container' cannot be cast to '${expectedType.qualifiedName}'.") - - -internal -fun internalError(): Nothing = - throw InternalError("This should not happen, please report at https://github.com/gradle/kotlin-dsl/issues/new") Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GlobalServices.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GlobalServices.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GlobalServices.kt (revision 0) @@ -1,27 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.support - -import org.gradle.configuration.ImportsReader - - -internal -object GlobalServices { - - @Suppress("unused") - fun createImplicitImports(importsReader: ImportsReader) = - ImplicitImports(importsReader) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GradleExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GradleExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GradleExtensions.kt (revision 0) @@ -1,23 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.support - -import org.gradle.api.internal.GradleInternal -import org.gradle.api.invocation.Gradle - - -inline fun Gradle.serviceOf(): T = - (gradle as GradleInternal).services.get() Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GradleUserHomeServices.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GradleUserHomeServices.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/GradleUserHomeServices.kt (revision 0) @@ -1,28 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.support - -import org.gradle.api.internal.classpath.ModuleRegistry -import org.gradle.cache.CacheRepository - - -internal -object GradleUserHomeServices { - - @Suppress("unused") - fun createEmbeddedKotlinRepositoryProvider(cacheRepository: CacheRepository, moduleRegistry: ModuleRegistry) = - EmbeddedKotlinProvider(cacheRepository, moduleRegistry) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/IO.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/IO.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/IO.kt (revision 0) @@ -1,23 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import java.io.File - - -internal -fun userHome() = File(System.getProperty("user.home")) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ImplicitImports.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ImplicitImports.kt (revision 389d10f1bb075eadb338c5b5bb5d31bdd48e0c93) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ImplicitImports.kt (revision 0) @@ -1,43 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.configuration.ImportsReader - - -/** - * Holds the list of imports implicitly added to every Kotlin build script. - */ -class ImplicitImports(private val importsReader: ImportsReader) { - - val list by lazy { - gradleImports() + gradleKotlinDslImports() - } - - private - fun gradleImports() = - importsReader.simpleNameToFullClassNamesMapping.values.map { it.first() } - - private - fun gradleKotlinDslImports() = - listOf( - "org.gradle.kotlin.dsl.*", - // TODO: infer list of types below at build time by inspecting the Gradle API - "java.util.concurrent.TimeUnit", - "java.math.BigDecimal", - "java.io.File") -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinBuildscriptBlock.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinBuildscriptBlock.kt (revision 5ea6409528484042e5b7fce8d35cf1dd7c41487e) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinBuildscriptBlock.kt (revision 0) @@ -1,72 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.api.Project -import org.gradle.api.initialization.Settings -import org.gradle.api.invocation.Gradle - -import org.gradle.kotlin.dsl.KotlinBuildScript -import org.gradle.kotlin.dsl.KotlinInitScript -import org.gradle.kotlin.dsl.KotlinSettingsScript -import org.gradle.kotlin.dsl.ScriptHandlerScope - - -/** - * Base class for `buildscript` block evaluation on scripts targeting Project. - */ -abstract class KotlinBuildscriptBlock(host: KotlinScriptHost) : KotlinBuildScript(host) { - - /** - * Configures the build script classpath for this project. - * - * @see [Project.buildscript] - */ - override fun buildscript(block: ScriptHandlerScope.() -> Unit) { - buildscript.configureWith(block) - } -} - - -/** - * Base class for `buildscript` block evaluation on scripts targeting Settings. - */ -abstract class KotlinSettingsBuildscriptBlock(host: KotlinScriptHost) : KotlinSettingsScript(host) { - - /** - * Configures the build script classpath for settings. - * - * @see [Settings.buildscript] - */ - override fun buildscript(block: ScriptHandlerScope.() -> Unit) { - buildscript.configureWith(block) - } -} - - -/** - * Base class for `initscript` block evaluation on scripts targeting Gradle. - */ -abstract class KotlinInitscriptBlock(host: KotlinScriptHost) : KotlinInitScript(host) { - - /** - * Configures the classpath of the init script. - */ - override fun initscript(block: ScriptHandlerScope.() -> Unit) { - initscript.configureWith(block) - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinCompiler.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinCompiler.kt (revision 5d704f53ce8ac61d04df2e6e25f2ad9f76e0803a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinCompiler.kt (revision 0) @@ -1,330 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.common.messages.MessageUtil - -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileBunchOfSources -import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot - -import org.jetbrains.kotlin.codegen.CompilationException - -import org.jetbrains.kotlin.com.intellij.openapi.Disposable -import org.jetbrains.kotlin.com.intellij.openapi.project.Project -import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer.dispose -import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer.newDisposable - -import org.jetbrains.kotlin.config.addKotlinSourceRoot -import org.jetbrains.kotlin.config.addKotlinSourceRoots -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.CompilerConfigurationKey -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.config.JVMConfigurationKeys.OUTPUT_DIRECTORY -import org.jetbrains.kotlin.config.JVMConfigurationKeys.OUTPUT_JAR -import org.jetbrains.kotlin.config.JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY - -import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor.Companion.registerExtension -import org.jetbrains.kotlin.name.NameUtils - -import org.jetbrains.kotlin.samWithReceiver.CliSamWithReceiverComponentContributor - -import org.jetbrains.kotlin.script.KotlinScriptDefinition - -import org.jetbrains.kotlin.utils.PathUtil -import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult - -import org.slf4j.Logger - -import java.io.File - - -internal -fun compileKotlinScriptToDirectory( - outputDirectory: File, - scriptFile: File, - scriptDef: KotlinScriptDefinition, - classPath: List, - messageCollector: LoggingMessageCollector -): String = - - withRootDisposable { rootDisposable -> - - withCompilationExceptionHandler(messageCollector) { - - val configuration = compilerConfigurationFor(messageCollector).apply { - addKotlinSourceRoot(scriptFile.canonicalPath) - put(RETAIN_OUTPUT_IN_MEMORY, false) - put(OUTPUT_DIRECTORY, outputDirectory) - setModuleName("buildscript") - addScriptDefinition(scriptDef) - classPath.forEach { addJvmClasspathRoot(it) } - } - val environment = kotlinCoreEnvironmentFor(configuration, rootDisposable).apply { - HasImplicitReceiverCompilerPlugin.apply(project) - } - - compileBunchOfSources(environment) - || throw ScriptCompilationException(messageCollector.errors) - - NameUtils.getScriptNameForFile(scriptFile.name).asString() - } - } - - -private -object HasImplicitReceiverCompilerPlugin { - - fun apply(project: Project) { - registerExtension(project, samWithReceiverComponentContributor) - } - - val samWithReceiverComponentContributor = - CliSamWithReceiverComponentContributor( - listOf("org.gradle.api.HasImplicitReceiver")) -} - - -internal -fun compileToJar( - outputJar: File, - sourceFiles: Iterable, - logger: Logger, - classPath: Iterable = emptyList() -): Boolean = - - compileTo(OUTPUT_JAR, outputJar, sourceFiles, logger, classPath) - - -internal -fun compileToDirectory( - outputDirectory: File, - sourceFiles: Iterable, - logger: Logger, - classPath: Iterable = emptyList() -): Boolean = - - compileTo(OUTPUT_DIRECTORY, outputDirectory, sourceFiles, logger, classPath) - - -private -fun compileTo( - outputConfigurationKey: CompilerConfigurationKey, - output: File, - sourceFiles: Iterable, - logger: Logger, - classPath: Iterable -): Boolean { - - withRootDisposable { disposable -> - withMessageCollectorFor(logger) { messageCollector -> - val configuration = compilerConfigurationFor(messageCollector).apply { - addKotlinSourceRoots(sourceFiles.map { it.canonicalPath }) - put(outputConfigurationKey, output) - setModuleName(output.nameWithoutExtension) - classPath.forEach { addJvmClasspathRoot(it) } - addJvmClasspathRoot(kotlinStdlibJar) - } - val environment = kotlinCoreEnvironmentFor(configuration, disposable) - return compileBunchOfSources(environment) - } - } -} - - -private -val kotlinStdlibJar: File - get() = PathUtil.getResourcePathForClass(Unit::class.java) - - -private -inline fun withRootDisposable(action: (Disposable) -> T): T { - val rootDisposable = newDisposable() - try { - return action(rootDisposable) - } finally { - dispose(rootDisposable) - } -} - - -private -inline fun withMessageCollectorFor(log: Logger, action: (MessageCollector) -> T): T { - val messageCollector = messageCollectorFor(log) - withCompilationExceptionHandler(messageCollector) { - return action(messageCollector) - } -} - - -private -inline fun withCompilationExceptionHandler(messageCollector: MessageCollector, action: () -> T): T { - try { - return action() - } catch (ex: CompilationException) { - messageCollector.report( - CompilerMessageSeverity.EXCEPTION, - ex.localizedMessage, - MessageUtil.psiElementToMessageLocation(ex.element)) - - throw IllegalStateException("Internal compiler error: ${ex.localizedMessage}", ex) - } -} - - -private -fun compilerConfigurationFor(messageCollector: MessageCollector): CompilerConfiguration = - CompilerConfiguration().apply { - put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) - } - - -private -fun CompilerConfiguration.setModuleName(name: String) { - put(CommonConfigurationKeys.MODULE_NAME, name) -} - - -private -fun CompilerConfiguration.addScriptDefinition(scriptDef: KotlinScriptDefinition) { - add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDef) -} - - -private -fun kotlinCoreEnvironmentFor(configuration: CompilerConfiguration, rootDisposable: Disposable) = - KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) - - -internal -fun messageCollectorFor(log: Logger, pathTranslation: (String) -> String = { it }): LoggingMessageCollector = - LoggingMessageCollector(log, pathTranslation) - - -internal -data class ScriptCompilationError(val message: String, val location: CompilerMessageLocation?) - - -internal -data class ScriptCompilationException(val errors: List) : RuntimeException() { - - init { - require(errors.isNotEmpty()) - } - - val firstErrorLine - get() = errors.firstNotNullResult { it.location?.line } - - override val message: String - get() = ( - listOf("Script compilation $errorPlural:") - + indentedErrorMessages() - + "${errors.size} $errorPlural") - .joinToString("\n\n") - - private - fun indentedErrorMessages() = - errors.map(::errorMessage).map(::prependIndent) - - private - fun errorMessage(error: ScriptCompilationError): String = - error.location?.let { location -> - errorAt(location, error.message) - } ?: error.message - - private - fun errorAt(location: CompilerMessageLocation, message: String): String { - val columnIndent = " ".repeat(5 + maxLineNumberStringLength + 1 + location.column) - return "Line ${lineNumber(location)}: ${location.lineContent}\n" + - "^ $message".lines().joinToString( - prefix = columnIndent, - separator = "\n$columnIndent $indent") - } - - private - fun lineNumber(location: CompilerMessageLocation) = - location.line.toString().padStart(maxLineNumberStringLength, '0') - - private - fun prependIndent(it: String) = it.prependIndent(indent) - - private - val errorPlural - get() = if (errors.size > 1) "errors" else "error" - - private - val maxLineNumberStringLength: Int by lazy { - errors.mapNotNull { it.location?.line }.max().toString().length - } -} - - -private -const val indent = " " - - -internal -class LoggingMessageCollector( - private val log: Logger, - private val pathTranslation: (String) -> String -) : MessageCollector { - - val errors = arrayListOf() - - override fun hasErrors() = errors.isNotEmpty() - - override fun clear() = errors.clear() - - override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) { - - fun msg() = - location?.run { - path.let(pathTranslation).let { path -> - when { - line >= 0 && column >= 0 -> compilerMessageFor(path, line, column, message) - else -> "$path: $message" - } - } - } ?: message - - fun taggedMsg() = - "${severity.presentableName[0]}: ${msg()}" - - when (severity) { - CompilerMessageSeverity.ERROR, CompilerMessageSeverity.EXCEPTION -> { - errors += ScriptCompilationError(message, location) - log.error { taggedMsg() } - } - in CompilerMessageSeverity.VERBOSE -> log.trace { msg() } - CompilerMessageSeverity.STRONG_WARNING -> log.info { taggedMsg() } - CompilerMessageSeverity.WARNING -> log.info { taggedMsg() } - CompilerMessageSeverity.INFO -> log.info { msg() } - else -> log.debug { taggedMsg() } - } - } -} - - -internal -fun compilerMessageFor(path: String, line: Int, column: Int, message: String) = - "$path:$line:$column: $message" Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinPluginsBlock.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinPluginsBlock.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinPluginsBlock.kt (revision 0) @@ -1,30 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.plugin.use.PluginDependenciesSpec - - -/** - * Base class for `plugins` block evaluation. - */ -abstract class KotlinPluginsBlock(val pluginDependencies: PluginDependenciesSpec) { - - inline fun plugins(configuration: PluginDependenciesSpec.() -> Unit) { - pluginDependencies.configuration() - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinScriptHost.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinScriptHost.kt (revision 92329459a346fd2bc6aa06ae3503bb49a6886b73) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinScriptHost.kt (revision 0) @@ -1,60 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.api.Action -import org.gradle.api.initialization.dsl.ScriptHandler -import org.gradle.api.internal.initialization.ClassLoaderScope -import org.gradle.api.internal.plugins.DefaultObjectConfigurationAction -import org.gradle.api.plugins.ObjectConfigurationAction - -import org.gradle.groovy.scripts.ScriptSource - -import org.gradle.internal.service.ServiceRegistry - -import org.gradle.kotlin.dsl.fileOperationsFor -import org.gradle.kotlin.dsl.invoke - - -class KotlinScriptHost( - val target: T, - private val scriptSource: ScriptSource, - private val serviceRegistry: ServiceRegistry, - private val baseScope: ClassLoaderScope, - val scriptHandler: ScriptHandler -) { - - internal - val operations by unsafeLazy { - fileOperationsFor(serviceRegistry, scriptSource.resource.location.file?.parentFile) - } - - internal - fun applyObjectConfigurationAction(configure: Action) { - createObjectConfigurationAction().also { configure(it) }.execute() - } - - private - fun createObjectConfigurationAction() = - DefaultObjectConfigurationAction( - operations.fileResolver, - serviceRegistry.get(), - serviceRegistry.get(), - baseScope, - serviceRegistry.get(), - target) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinScriptType.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinScriptType.kt (revision 09a1b085071a377ea436ebea1dcd300ee87ba8ed) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/KotlinScriptType.kt (revision 0) @@ -1,68 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import java.io.File - - -fun kotlinScriptTypeFor(candidate: File): KotlinScriptType? = - KotlinScriptTypeMatch.forFile(candidate)?.scriptType - - -enum class KotlinScriptType { - INIT, SETTINGS, PROJECT -} - - -data class KotlinScriptTypeMatch( - val scriptType: KotlinScriptType, - val match: Match -) { - - companion object { - - fun forFile(file: File): KotlinScriptTypeMatch? = - forName(file.name) - - fun forName(name: String): KotlinScriptTypeMatch? = - candidates.firstOrNull { it.match.matches(name) } - - private - val candidates = - listOf( - KotlinScriptTypeMatch(KotlinScriptType.SETTINGS, Match.Whole("settings.gradle.kts")), - KotlinScriptTypeMatch(KotlinScriptType.SETTINGS, Match.Suffix(".settings.gradle.kts")), - KotlinScriptTypeMatch(KotlinScriptType.INIT, Match.Suffix(".init.gradle.kts")), - KotlinScriptTypeMatch(KotlinScriptType.PROJECT, Match.Suffix(".gradle.kts"))) - } -} - - -sealed class Match { - - abstract val value: String - - abstract fun matches(candidate: String): Boolean - - data class Whole(override val value: String) : Match() { - override fun matches(candidate: String) = candidate == value - } - - data class Suffix(override val value: String) : Match() { - override fun matches(candidate: String) = candidate.endsWith(value) - } -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Logger.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Logger.kt (revision 05c6e9e4957fa24d056555a5b6a10c9499bed582) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Logger.kt (revision 0) @@ -1,49 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - - -internal -inline fun loggerFor(): Logger = - LoggerFactory.getLogger(T::class.java) - - -internal -inline fun Logger.trace(msg: () -> String) { - if (isTraceEnabled) trace(msg()) -} - - -internal -inline fun Logger.debug(msg: () -> String) { - if (isDebugEnabled) debug(msg()) -} - - -internal -inline fun Logger.info(msg: () -> String) { - if (isInfoEnabled) info(msg()) -} - - -internal -inline fun Logger.error(msg: () -> String) { - if (isErrorEnabled) error(msg()) -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Maps.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Maps.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/Maps.kt (revision 0) @@ -1,35 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - - -internal -fun excludeMapFor(group: String?, module: String?): Map = - mapOfNonNullValuesOf( - "group" to group, - "module" to module) - - -internal -fun mapOfNonNullValuesOf(vararg entries: Pair): Map = - mutableMapOf().apply { - for ((k, v) in entries) { - if (v != null) { - put(k, v) - } - } - } Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ProgressMonitor.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ProgressMonitor.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ProgressMonitor.kt (revision 0) @@ -1,24 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import java.io.Closeable - - -interface ProgressMonitor : Closeable { - fun onProgress() -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ProjectExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ProjectExtensions.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ProjectExtensions.kt (revision 0) @@ -1,24 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.api.Project -import org.gradle.api.internal.project.ProjectInternal - - -inline fun Project.serviceOf(): T = - (this as ProjectInternal).services.get() Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ScriptHandlerExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ScriptHandlerExtensions.kt (revision 5ea6409528484042e5b7fce8d35cf1dd7c41487e) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ScriptHandlerExtensions.kt (revision 0) @@ -1,25 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.support - -import org.gradle.api.initialization.dsl.ScriptHandler -import org.gradle.kotlin.dsl.ScriptHandlerScope - - -internal -fun ScriptHandler.configureWith(block: ScriptHandlerScope.() -> Unit) { - ScriptHandlerScope(this).block() -} Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ServiceRegistryExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ServiceRegistryExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/ServiceRegistryExtensions.kt (revision 0) @@ -1,22 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.support - -import org.gradle.internal.service.ServiceRegistry - - -inline fun ServiceRegistry.get(): T = - this[T::class.java]!! Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/SettingsExtensions.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/SettingsExtensions.kt (revision e0bc1d7d927cf5a6505ed319fe68c1532b076cc0) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/SettingsExtensions.kt (revision 0) @@ -1,22 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.kotlin.dsl.support - -import org.gradle.api.initialization.Settings - - -inline fun Settings.serviceOf(): T = - gradle.serviceOf() Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/unsafeLazy.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/unsafeLazy.kt (revision 92329459a346fd2bc6aa06ae3503bb49a6886b73) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/unsafeLazy.kt (revision 0) @@ -1,26 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - - -/** - * Thread unsafe version of [lazy]. - * - * @see LazyThreadSafetyMode.NONE - */ -internal -fun unsafeLazy(initializer: () -> T): Lazy = lazy(LazyThreadSafetyMode.NONE, initializer) Index: provider/src/main/kotlin/org/gradle/kotlin/dsl/support/zip.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/kotlin/dsl/support/zip.kt (revision 1e6d8271e1b0840e2c55f81e1ccbbb0c56e2cb3e) +++ provider/src/main/kotlin/org/gradle/kotlin/dsl/support/zip.kt (revision 0) @@ -1,86 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.support - -import org.gradle.util.TextUtil.normaliseFileSeparators - -import java.io.File -import java.io.InputStream -import java.io.OutputStream - -import java.util.zip.ZipEntry -import java.util.zip.ZipFile -import java.util.zip.ZipOutputStream - - -fun zipTo(zipFile: File, baseDir: File) { - val files = baseDir.walkTopDown().filter { it.isFile } - zipTo(zipFile, baseDir, files) -} - - -fun zipTo(zipFile: File, baseDir: File, files: Sequence) { - val entries = files.map { file -> - val path = file.relativeTo(baseDir).path - val bytes = file.readBytes() - normaliseFileSeparators(path) to bytes - } - zipTo(zipFile, entries) -} - - -fun zipTo(zipFile: File, entries: Sequence>) { - zipTo(zipFile.outputStream(), entries) -} - - -fun zipTo(outputStream: OutputStream, entries: Sequence>) { - ZipOutputStream(outputStream).use { zos -> - entries.forEach { entry -> - val (path, bytes) = entry - zos.putNextEntry(ZipEntry(path).apply { size = bytes.size.toLong() }) - zos.write(bytes) - zos.closeEntry() - } - } -} - - -internal -fun unzipTo(outputDirectory: File, zipFile: File) { - ZipFile(zipFile).use { zip -> - for (entry in zip.entries()) { - unzipEntryTo(outputDirectory, zip, entry) - } - } -} - - -private -fun unzipEntryTo(outputDirectory: File, zip: ZipFile, entry: ZipEntry) { - val output = File(outputDirectory, entry.name) - if (entry.isDirectory) { - output.mkdirs() - } else { - zip.getInputStream(entry).use { it.copyTo(output) } - } -} - - -private -fun InputStream.copyTo(file: File): Long = - file.outputStream().use { copyTo(it) } Index: provider/src/main/kotlin/org/gradle/script/lang/kotlin/KotlinBuildScript.kt =================================================================== diff -u -N --- provider/src/main/kotlin/org/gradle/script/lang/kotlin/KotlinBuildScript.kt (revision 4fc15ec02526e4543fbcb4ce5d7acc2bebd5562b) +++ provider/src/main/kotlin/org/gradle/script/lang/kotlin/KotlinBuildScript.kt (revision 0) @@ -1,41 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.gradle.script.lang.kotlin - -import org.gradle.api.Project - -import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptDependenciesResolver - -import org.gradle.kotlin.dsl.GradleDsl -import org.gradle.kotlin.dsl.support.KotlinScriptHost - -import kotlin.script.extensions.SamWithReceiverAnnotations -import kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments -import kotlin.script.templates.ScriptTemplateDefinition - - -/** - * Base class for Kotlin build scripts. - */ -@ScriptTemplateDefinition( - resolver = KotlinBuildScriptDependenciesResolver::class, - scriptFilePattern = ".*\\.gradle\\.kts") -@ScriptTemplateAdditionalCompilerArguments(["-Xjsr305=strict"]) -@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") -@GradleDsl -abstract class KotlinBuildScript( - host: KotlinScriptHost -) : org.gradle.kotlin.dsl.KotlinBuildScript(host) Index: provider/src/main/resources/META-INF/services/org.gradle.initialization.GradleApiSpecProvider =================================================================== diff -u -N --- provider/src/main/resources/META-INF/services/org.gradle.initialization.GradleApiSpecProvider (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/main/resources/META-INF/services/org.gradle.initialization.GradleApiSpecProvider (revision 0) @@ -1 +0,0 @@ -org.gradle.kotlin.dsl.provider.KotlinGradleApiSpecProvider Index: provider/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry =================================================================== diff -u -N --- provider/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry (revision 0) @@ -1 +0,0 @@ -org.gradle.kotlin.dsl.services.KotlinScriptServiceRegistry Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/ComponentSelectionRulesTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/ComponentSelectionRulesTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/ComponentSelectionRulesTest.kt (revision 0) @@ -1,64 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify - -import org.gradle.api.Action -import org.gradle.api.artifacts.ComponentSelection -import org.gradle.api.artifacts.ComponentSelectionRules -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.ConfigurationContainer -import org.gradle.api.artifacts.ResolutionStrategy - -import org.junit.Test - -import org.mockito.invocation.InvocationOnMock - - -class ComponentSelectionRulesTest { - - @Test - fun `Action method overloads are correctly selected`() { - - val componentSelection = mock() - val componentSelectionRules = mock { - on { all(any>()) }.thenAnswer { - it.executeActionOn(componentSelection) - } - } - val resolutionStrategy = mock { - on { componentSelection(any>()) }.thenAnswer { - it.executeActionOn(componentSelectionRules) - } - } - val conf = mock { - on { resolutionStrategy(any>()) }.thenAnswer { - it.executeActionOn(resolutionStrategy) - } - } - val configurations = mock { - on { maybeCreate("conf") } doReturn conf - } - - configurations { - "conf" { - resolutionStrategy { - it.componentSelection { - it.all { selection -> - selection.reject("all") - } - } - } - } - } - verify(componentSelection).reject("all") - } - - private - fun InvocationOnMock.executeActionOn(element: E): Any? { - getArgument>(0).execute(element) - return mock - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensionsTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensionsTest.kt (revision 0) @@ -1,28 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify - -import org.gradle.api.file.ConfigurableFileCollection - -import org.hamcrest.CoreMatchers.sameInstance -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class ConfigurableFileCollectionExtensionsTest { - - @Test - fun `assignment to delegated property means #setFrom`() { - - val fileCollection = mock() - var delegatedProperty by fileCollection - - val value = mock() - delegatedProperty = value - - verify(fileCollection).setFrom(value) - assertThat(delegatedProperty, sameInstance(fileCollection)) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensionsTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensionsTest.kt (revision 0) @@ -1,25 +0,0 @@ -package org.gradle.kotlin.dsl - -import org.gradle.api.artifacts.Configuration - -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever - -import org.hamcrest.CoreMatchers.sameInstance -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class ConfigurationExtensionsTest { - - @Test - fun `given group and module, 'exclude' extension will build corresponding map`() { - - val configuration: Configuration = mock() - whenever(configuration.exclude(mapOf("group" to "org.gradle", "module" to "test"))).thenReturn(configuration) - assertThat( - configuration.exclude(group = "org.gradle", module = "test"), - sameInstance(configuration)) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensionsTest.kt (revision 1cf5ef2cb2f03fe60348ca27cdf17d7868b815ea) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensionsTest.kt (revision 0) @@ -1,36 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.inOrder -import com.nhaarman.mockito_kotlin.mock -import org.apache.tools.ant.filters.HeadFilter - -import org.apache.tools.ant.filters.StripJavaComments - -import org.gradle.api.file.ContentFilterable - -import org.junit.Test - - -class ContentFilterableExtensionsTest { - - @Test - fun `filter extensions`() { - val filterable = mock().apply { - filter() - filter("lines" to 25, "skip" to 1) - filter(mapOf("lines" to 52, "skip" to 2)) - filter(StripJavaComments::class) - filter(HeadFilter::class, "lines" to 25, "skip" to 3) - filter(HeadFilter::class, mapOf("lines" to 52, "skip" to 4)) - } - inOrder(filterable) { - verify(filterable).filter(StripJavaComments::class.java) - verify(filterable).filter(mapOf("lines" to 25, "skip" to 1), HeadFilter::class.java) - verify(filterable).filter(mapOf("lines" to 52, "skip" to 2), HeadFilter::class.java) - verify(filterable).filter(StripJavaComments::class.java) - verify(filterable).filter(mapOf("lines" to 25, "skip" to 3), HeadFilter::class.java) - verify(filterable).filter(mapOf("lines" to 52, "skip" to 4), HeadFilter::class.java) - verifyNoMoreInteractions() - } - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/DelegatedGradlePropertiesExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/DelegatedGradlePropertiesExtensionsTest.kt (revision 27e7819c2ddd11d38b06b33cb7c22bec8f509294) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/DelegatedGradlePropertiesExtensionsTest.kt (revision 0) @@ -1,224 +0,0 @@ -package org.gradle.kotlin.dsl - -import org.gradle.api.Project -import org.gradle.api.InvalidUserCodeException -import org.gradle.api.initialization.Settings - -import org.gradle.api.internal.DynamicObjectAware -import org.gradle.internal.metaobject.DynamicObject -import org.gradle.internal.metaobject.DynamicInvokeResult - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.inOrder -import com.nhaarman.mockito_kotlin.mock - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.nullValue - -import org.junit.Assert.assertThat -import org.junit.Assert.fail -import org.junit.Test - - -class DelegatedGradlePropertiesExtensionsTest { - - @Test - fun `non-nullable delegated property access of existing non-null gradle property`() { - - withMockForSettings(existing = "p" to 42) { - - val p: Int by settings - assertThat(p, equalTo(42)) - } - - withMockForProject(existing = "p" to 42) { - - val p: Int by project - assertThat(p, equalTo(42)) - } - } - - @Test - fun `non-nullable delegated property access of existing null gradle property throws`() { - - withMockForSettings(existing = "p" to null) { - - val p: Any by settings - try { - p.toString() - fail("InvalidUserCodeException not thrown") - } catch (ex: InvalidUserCodeException) { - assertThat(ex.message, equalTo("Cannot get non-null property 'p' on settings as it is null")) - } - } - - withMockForProject(existing = "p" to null) { - - val p: Any by project - try { - p.toString() - fail("InvalidUserCodeException not thrown") - } catch (ex: InvalidUserCodeException) { - assertThat(ex.message, equalTo("Cannot get non-null property 'p' on project as it is null")) - } - } - } - - @Test - fun `non-nullable delegated property access of non-existing gradle property throws`() { - - withMockForSettings(absent = "p") { - - val p: Any by settings - try { - p.toString() - fail("InvalidUserCodeException not thrown") - } catch (ex: InvalidUserCodeException) { - assertThat(ex.message, equalTo("Cannot get non-null property 'p' on settings as it does not exist")) - } - } - - withMockForProject(absent = "p") { - - val p: Any by project - try { - p.toString() - fail("InvalidUserCodeException not thrown") - } catch (ex: InvalidUserCodeException) { - assertThat(ex.message, equalTo("Cannot get non-null property 'p' on project as it does not exist")) - } - } - } - - @Test - fun `nullable delegated property access of existing non-null gradle property`() { - - withMockForSettings(existing = "p" to 42) { - - val p: Int? by settings - assertThat(p, equalTo(42)) - } - - withMockForProject(existing = "p" to 42) { - - val p: Int? by project - assertThat(p, equalTo(42)) - } - } - - @Test - fun `nullable delegated property access of existing null gradle property`() { - - withMockForSettings(existing = "p" to null) { - - val p: Int? by settings - assertThat(p, nullValue()) - } - - withMockForProject(existing = "p" to null) { - - val p: Int? by project - assertThat(p, nullValue()) - } - } - - @Test - fun `nullable delegated property access of non-existing gradle property`() { - - withMockForSettings(absent = "p") { - - val p: Int? by settings - assertThat(p, nullValue()) - } - - withMockForProject(absent = "p") { - - val p: Int? by project - assertThat(p, nullValue()) - } - } - - private - fun withMockForSettings(existing: Pair? = null, absent: String? = null, action: DynamicDelegatedPropertiesMock.SettingsMock.() -> Unit) { - mockForSettings(existing, absent).run { - action() - verifyTryGetProperty(existing, absent) - } - } - - private - fun withMockForProject(existing: Pair? = null, absent: String? = null, action: DynamicDelegatedPropertiesMock.ProjectMock.() -> Unit) { - mockForProject(existing, absent).run { - action() - verifyTryGetProperty(existing, absent) - } - } - - private - fun mockForSettings(existing: Pair? = null, absent: String? = null): DynamicDelegatedPropertiesMock.SettingsMock = - dynamicObjectMockFor(existing, absent).let { dynamicObject -> - DynamicDelegatedPropertiesMock.SettingsMock( - mock(name = "settings") { - on { asDynamicObject } doReturn dynamicObject - }, - dynamicObject) - } - - private - fun mockForProject(existing: Pair? = null, absent: String? = null): DynamicDelegatedPropertiesMock.ProjectMock = - dynamicObjectMockFor(existing, absent).let { dynamicObject -> - DynamicDelegatedPropertiesMock.ProjectMock( - mock(name = "project") { - on { asDynamicObject } doReturn dynamicObject - }, - dynamicObject) - } - - private - interface DynamicAwareSettingsMockType : Settings, DynamicObjectAware - - private - interface DynamicAwareProjectMockType : Project, DynamicObjectAware - - private - sealed class DynamicDelegatedPropertiesMock(private val target: T, private val dynamicObject: DynamicObject) { - - fun verifyTryGetProperty(existing: Pair?, absent: String?) { - existing?.let { - verifyTryGetProperty(existing.first) - } - absent?.let { - verifyTryGetProperty(absent) - } - } - - private - fun verifyTryGetProperty(propertyName: String) = - inOrder(target, dynamicObject) { - verify(target as DynamicObjectAware).asDynamicObject - verify(dynamicObject).tryGetProperty(propertyName) - verifyNoMoreInteractions() - } - - class SettingsMock(val settings: Settings, dynamicObject: DynamicObject) : DynamicDelegatedPropertiesMock(settings, dynamicObject) - class ProjectMock(val project: Project, dynamicObject: DynamicObject) : DynamicDelegatedPropertiesMock(project, dynamicObject) - } - - private - fun dynamicObjectMockFor(existing: Pair?, absent: String?) = - mock { - existing?.let { (name, value) -> - val existingMock = mock { - on { this.isFound } doReturn true - on { this.value } doReturn value - } - on { tryGetProperty(name) } doReturn existingMock - } - absent?.let { - val absentMock = mock { - on { this.isFound } doReturn false - } - on { tryGetProperty(absent) } doReturn absentMock - } - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensionsTest.kt (revision 823cb09ed220778532237269d3d863b0b01a81c3) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensionsTest.kt (revision 0) @@ -1,245 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify -import com.nhaarman.mockito_kotlin.whenever - -import org.gradle.api.Project -import org.gradle.api.artifacts.ClientModule -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.ExternalModuleDependency -import org.gradle.api.artifacts.ProjectDependency -import org.gradle.api.artifacts.dsl.DependencyHandler - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.sameInstance -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class DependencyHandlerExtensionsTest { - - @Test - fun `given group, name, version, configuration, classifier and ext, 'create' extension will build corresponding map`() { - - val expectedModuleMap = mapOf( - "group" to "g", - "name" to "n", - "version" to "v", - "configuration" to "cfg", - "classifier" to "cls", - "ext" to "x") - - val dependencies: DependencyHandler = mock() - val dependency: ExternalModuleDependency = mock() - whenever(dependencies.create(expectedModuleMap)).thenReturn(dependency) - - assertThat( - dependencies.create( - group = "g", - name = "n", - version = "v", - configuration = "cfg", - classifier = "cls", - ext = "x"), - sameInstance(dependency)) - } - - @Test - fun `given group and module, 'exclude' extension will build corresponding map`() { - - val dependencies = DependencyHandlerScope(mock()) - val dependency: ExternalModuleDependency = mock() - val events = mutableListOf() - whenever(dependencies.create("dependency")).then { - events.add("created") - dependency - } - whenever(dependency.exclude(mapOf("group" to "g", "module" to "m"))).then { - events.add("configured") - dependency - } - whenever(dependencies.add("configuration", dependency)).then { - events.add("added") - dependency - } - - dependencies { - - "configuration"("dependency") { - val configuredDependency = - exclude(group = "g", module = "m") - assertThat( - configuredDependency, - sameInstance(dependency)) - } - } - - assertThat( - events, - equalTo(listOf("created", "configured", "added"))) - } - - @Test - fun `given path and configuration, 'project' extension will build corresponding map`() { - - val dependencies = DependencyHandlerScope(mock()) - val dependency: ProjectDependency = mock() - val events = mutableListOf() - val expectedProjectMap = mapOf("path" to ":project", "configuration" to "default") - whenever(dependencies.project(expectedProjectMap)).then { - events.add("created") - dependency - } - whenever(dependencies.add("configuration", dependency)).then { - events.add("added") - dependency - } - val project: Project = mock() - whenever(dependency.dependencyProject).thenReturn(project) - - dependencies { - - "configuration"(project(path = ":project", configuration = "default")) { - events.add("configured") - assertThat( - dependencyProject, - sameInstance(project)) - } - } - - assertThat( - events, - equalTo(listOf("created", "configured", "added"))) - } - - @Test - fun `given configuration name and dependency notation, it will add the dependency`() { - - val dependencyHandler = mock { - on { add(any(), any()) } doReturn mock() - } - - val dependencies = DependencyHandlerScope(dependencyHandler) - dependencies { - "configuration"("notation") - } - - verify(dependencyHandler).add("configuration", "notation") - } - - @Test - fun `given configuration and dependency notation, it will add the dependency to the named configuration`() { - - val dependencyHandler = mock { - on { add(any(), any()) } doReturn mock() - } - val configuration = mock { - on { name } doReturn "c" - } - - val dependencies = DependencyHandlerScope(dependencyHandler) - dependencies { - configuration("notation") - } - - verify(dependencyHandler).add("c", "notation") - } - - @Test - fun `client module configuration`() { - - val clientModule = mock() - - val commonsCliDependency = mock(name = "commonsCliDependency") - - val antModule = mock(name = "antModule") - val antLauncherDependency = mock(name = "antLauncherDependency") - val antJUnitDependency = mock(name = "antJUnitDependency") - - val dependencies = mock { - on { module("org.codehaus.groovy:groovy:2.4.7") } doReturn clientModule - - on { create("commons-cli:commons-cli:1.0") } doReturn commonsCliDependency - - val antModuleNotation = mapOf("group" to "org.apache.ant", "name" to "ant", "version" to "1.9.6") - on { module(antModuleNotation) } doReturn antModule - on { create("org.apache.ant:ant-launcher:1.9.6@jar") } doReturn antLauncherDependency - on { create("org.apache.ant:ant-junit:1.9.6") } doReturn antJUnitDependency - - on { add("runtime", clientModule) } doReturn clientModule - } - - dependencies.apply { - val groovy = module("org.codehaus.groovy:groovy:2.4.7") { - - // Configures the module itself - isTransitive = false - - dependency("commons-cli:commons-cli:1.0") { - // Configures the external module dependency - isTransitive = false - } - - module(group = "org.apache.ant", name = "ant", version = "1.9.6") { - // Configures the inner module dependencies - dependencies( - "org.apache.ant:ant-launcher:1.9.6@jar", - "org.apache.ant:ant-junit:1.9.6") - } - } - add("runtime", groovy) - } - - verify(clientModule).isTransitive = false - verify(clientModule).addDependency(commonsCliDependency) - verify(clientModule).addDependency(antModule) - - verify(commonsCliDependency).isTransitive = false - - verify(antModule).addDependency(antLauncherDependency) - verify(antModule).addDependency(antJUnitDependency) - } - - @Test - fun `dependency on configuration using string notation doesn't cause IllegalStateException`() { - - val dependencyHandler = mock { - on { add(any(), any()) }.thenReturn(null) - } - - val baseConfig = mock() - - val dependencies = DependencyHandlerScope(dependencyHandler) - dependencies { - "configuration"(baseConfig) - } - - verify(dependencyHandler).add("configuration", baseConfig) - } - - @Test - fun `dependency on configuration doesn't cause IllegalStateException`() { - - val dependencyHandler = mock { - on { add(any(), any()) }.thenReturn(null) - } - - val configuration = mock() { - on { name } doReturn "configuration" - } - - val baseConfig = mock() - - val dependencies = DependencyHandlerScope(dependencyHandler) - dependencies { - configuration(baseConfig) - } - - verify(dependencyHandler).add("configuration", baseConfig) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensionsTest.kt (revision 65dca3fe4770ed11c3955b6768a3f096d21bb141) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensionsTest.kt (revision 0) @@ -1,98 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.eq -import com.nhaarman.mockito_kotlin.inOrder -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.whenever - -import org.gradle.api.Action -import org.gradle.api.NamedDomainObjectContainer -import org.gradle.api.Task -import org.gradle.api.plugins.ExtensionAware -import org.gradle.api.plugins.ExtensionContainer -import org.gradle.testing.jacoco.plugins.JacocoTaskExtension - -import org.junit.Test - - -class ExtensionAwareExtensionsTest { - - @Test - fun `can get task extensions`() { - - val task = mock() - val extensionContainer = mock() - val extension = mock() - val extensionType = typeOf() - - whenever(task.extensions) - .thenReturn(extensionContainer) - whenever(extensionContainer.getByType(eq(extensionType))) - .thenReturn(extension) - - task.the() - - inOrder(extensionContainer) { - verify(extensionContainer).getByType(eq(extensionType)) - verifyNoMoreInteractions() - } - } - - @Test - fun `can configure task extensions`() { - - val task = mock() - val extensionContainer = mock() - val extensionType = typeOf() - - whenever(task.extensions) - .thenReturn(extensionContainer) - - task.configure {} - - inOrder(extensionContainer) { - verify(extensionContainer).configure(eq(extensionType), any>()) - verifyNoMoreInteractions() - } - } - - @Test - fun `can get generic extension by type`() { - - val extensionAware = mock() - val extensions = mock() - val extension = mock>>() - val extensionType = typeOf>>() - - whenever(extensionAware.extensions) - .thenReturn(extensions) - whenever(extensions.getByType(eq(extensionType))) - .thenReturn(extension) - - extensionAware.the>>() - - inOrder(extensions) { - verify(extensions).getByType(eq(extensionType)) - verifyNoMoreInteractions() - } - } - - @Test - fun `can configure generic extension by type`() { - - val extensionAware = mock() - val extensions = mock() - val extensionType = typeOf>>() - - whenever(extensionAware.extensions) - .thenReturn(extensions) - - extensionAware.configure>> {} - - inOrder(extensions) { - verify(extensions).configure(eq(extensionType), any>>>()) - verifyNoMoreInteractions() - } - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensionsTest.kt (revision 93bb68c708d5558a595045641c1434f7ff1b3f33) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensionsTest.kt (revision 0) @@ -1,104 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.inOrder -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify - -import org.gradle.api.plugins.ExtraPropertiesExtension - -import org.hamcrest.CoreMatchers.nullValue - -import org.junit.Assert.assertThat -import org.junit.Test - - -class ExtraPropertiesExtensionsTest { - - @Test - fun `can initialize extra property via delegate provider`() { - - val extra = mock { - on { get("property") } doReturn 42 - } - - val property by extra(42) - - // property is set eagerly - verify(extra).set("property", 42) - - // And to prove the type is inferred correctly - use(property) - } - - @Test - fun `can initialize extra property using lambda expression`() { - - val extra = mock { - on { get("property") } doReturn 42 - } - - val property by extra { 42 } - - // property is set eagerly - verify(extra).set("property", 42) - - // And to prove the type is inferred correctly - use(property) - } - - @Test - fun `can initialize extra property to null via delegate provider`() { - - val extra = mock { - on { get("property") } doReturn (null as Int?) - } - - run { - val property by extra(null) - - // property is set eagerly - verify(extra).set("property", null) - - // And to prove the type is inferred correctly - use(property) - } - - run { - val property: Int? by extra - inOrder(extra) { - verify(extra).get("property") - verifyNoMoreInteractions() - } - assertThat(property, nullValue()) - } - } - - @Test - fun `can initialize extra property to null using lambda expression`() { - - val extra = mock() - - run { - val property by extra { null as Int? } - - // property is set eagerly - verify(extra).set("property", null) - - // And to prove the type is inferred correctly - use(property) - } - - run { - val property: Int? by extra - inOrder(extra) { - verify(extra).get("property") - verifyNoMoreInteractions() - } - assertThat(property, nullValue()) - } - } - - private - fun use(@Suppress("unused_parameter") property: Int?) = Unit -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/GroovyInteroperabilityTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/GroovyInteroperabilityTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/GroovyInteroperabilityTest.kt (revision 0) @@ -1,238 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.eq -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify - -import groovy.lang.Closure -import groovy.lang.GroovyObject - -import org.gradle.internal.Cast -import org.gradle.util.ConfigureUtil - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.sameInstance -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull -import org.junit.Test - - -class GroovyInteroperabilityTest { - - @Test - fun `can use closure with single argument call`() { - val list = arrayListOf() - closureOf> { add(42) }.call(list) - assertEquals(42, list.first()) - } - - @Test - fun `can use closure with single nullable argument call`() { - var passedIntoClosure: Any? = "Something non null" - closureOf { passedIntoClosure = this }.call(null) - assertNull(passedIntoClosure) - } - - @Test - fun `can use closure with delegate call`() { - val list = arrayListOf() - delegateClosureOf> { add(42) }.apply { - delegate = list - call() - } - assertEquals(42, list.first()) - } - - @Test - fun `can use closure with a null delegate call`() { - var passedIntoClosure: Any? = "Something non null" - delegateClosureOf { passedIntoClosure = this }.apply { - delegate = null - call() - } - assertNull(passedIntoClosure) - } - - @Test - fun `can adapt parameterless function using KotlinClosure0`() { - - fun closure(function: () -> String) = KotlinClosure0(function) - - assertEquals( - "GROOVY", - closure { "GROOVY" }.call()) - } - - @Test - fun `can adapt parameterless null returning function using KotlinClosure0`() { - fun closure(function: () -> String?) = KotlinClosure0(function) - - assertEquals( - null, - closure { null }.call()) - } - - @Test - fun `can adapt unary function using KotlinClosure1`() { - - fun closure(function: String.() -> String) = KotlinClosure1(function) - - assertEquals( - "GROOVY", - closure { toUpperCase() }.call("groovy")) - } - - @Test - fun `can adapt unary null receiving function using KotlinClosure1`() { - fun closure(function: String?.() -> String?) = KotlinClosure1(function) - - assertEquals( - null, - closure { null }.call(null)) - } - - @Test - fun `can adapt binary function using KotlinClosure2`() { - - fun closure(function: (String, String) -> String) = KotlinClosure2(function) - - assertEquals( - "foobar", - closure { x, y -> x + y }.call("foo", "bar")) - } - - @Test - fun `can adapt binary null receiving function using KotlinClosure2`() { - - fun closure(function: (String?, String?) -> String?) = KotlinClosure2(function) - - assertEquals( - null, - closure { _, _ -> null }.call(null, null)) - } - - @Test - fun `can invoke Closure`() { - - val invocations = mutableListOf() - - val c0 = - object : Closure(null, null) { - @Suppress("unused") - fun doCall() = invocations.add("c0") - } - - val c1 = - object : Closure(null, null) { - @Suppress("unused") - fun doCall(x: Any) = invocations.add("c1($x)") - } - - val c2 = - object : Closure(null, null) { - @Suppress("unused") - fun doCall(x: Any, y: Any) = invocations.add("c2($x, $y)") - } - - assert(c0()) - assert(c1(42)) - assert(c2(11, 33)) - - assertThat( - invocations, - equalTo(listOf("c0", "c1(42)", "c2(11, 33)"))) - } - - @Test - fun `#configureWithGroovy can dispatch keyword arguments against GroovyObject`() { - - val expectedInvokeResult = Any() - val delegate = mock { - on { invokeMethod(any(), any()) } doReturn expectedInvokeResult - } - - @Suppress("UnnecessaryVariable") - val expectedDelegate = delegate - val expectedBuilderResult = Any() - val builderResult = delegate.withGroovyBuilder { - val invokeResult = "withKeywordArguments"("string" to "42", "int" to 42) - assertThat(invokeResult, sameInstance(expectedInvokeResult)) - assertThat(this.delegate, sameInstance(expectedDelegate)) - expectedBuilderResult - } - assertThat(builderResult, sameInstance(expectedBuilderResult)) - - val expectedKeywordArguments = mapOf("string" to "42", "int" to 42) - verify(delegate).invokeMethod("withKeywordArguments", arrayOf(expectedKeywordArguments)) - } - - @Test - fun `#configureWithGroovy allow nested invocations against GroovyObject`() { - - val expectedNestedInvokeResult = Any() - val nestedDelegate = mock { - on { invokeMethod(any(), any()) } doReturn expectedNestedInvokeResult - } - - val expectedInvokeResult = Any() - val delegate = mock { - on { invokeMethod(eq("nest"), any()) }.thenAnswer { - val varargs = Cast.uncheckedCast>(it.getArgument(1)) - val closure = Cast.uncheckedCast?>(varargs[0]) - ConfigureUtil - .configureUsing(closure) - .execute(nestedDelegate) - expectedInvokeResult - } - } - - @Suppress("UnnecessaryVariable") - val expectedDelegate = delegate - val expectedBuilderResult = Any() - val builderResult = delegate.withGroovyBuilder { - val invokeResult = "nest" { - assertThat(this.delegate, sameInstance(nestedDelegate)) - val nestedInvokeResult = "nestedInvocation"() - assertThat(nestedInvokeResult, sameInstance(expectedNestedInvokeResult)) - } - assertThat(invokeResult, sameInstance(expectedInvokeResult)) - assertThat(this.delegate, sameInstance(expectedDelegate)) - expectedBuilderResult - } - assertThat(builderResult, sameInstance(expectedBuilderResult)) - - verify(delegate).invokeMethod(eq("nest"), any()) - verify(nestedDelegate).invokeMethod("nestedInvocation", emptyArray()) - } - - interface NonGroovyObject { - fun withKeywordArguments(args: Map): Any? - } - - @Test - fun `#configureWithGroovy can dispatch keyword arguments against non GroovyObject`() { - - val expectedInvokeResult = Any() - val delegate = mock { - on { withKeywordArguments(any()) } doReturn expectedInvokeResult - } - - @Suppress("UnnecessaryVariable") - val expectedDelegate = delegate - val expectedBuilderResult = Any() - val builderResult = delegate.withGroovyBuilder { - val invokeResult = "withKeywordArguments"("string" to "42", "int" to 42) - assertThat(invokeResult, sameInstance(expectedInvokeResult)) - assertThat(this.delegate, sameInstance(expectedDelegate)) - expectedBuilderResult - } - assertThat(builderResult, sameInstance(expectedBuilderResult)) - - val expectedKeywordArguments = mapOf("string" to "42", "int" to 42) - verify(delegate).withKeywordArguments(expectedKeywordArguments) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensionsTest.kt (revision d943f40c7787f59011df625ccd385b1be25e9eae) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensionsTest.kt (revision 0) @@ -1,263 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock - -import org.gradle.api.NamedDomainObjectCollection -import org.gradle.api.NamedDomainObjectContainer -import org.gradle.api.PolymorphicDomainObjectContainer - -import org.gradle.kotlin.dsl.fixtures.assertFailsWith -import org.gradle.kotlin.dsl.fixtures.matches - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.nullValue -import org.hamcrest.CoreMatchers.sameInstance -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - -import java.util.regex.Pattern - - -class NamedDomainObjectCollectionExtensionsTest { - - data class DomainObject(var foo: String? = null) - - @Test - fun `can access existing element via indexer`() { - - val element = DomainObject() - val container = mock> { - on { getByName("domainObject") } doReturn element - } - assertThat( - container["domainObject"], - sameInstance(element)) - } - - @Test - fun `can access existing element via delegated property`() { - - val element = DomainObject() - val container = mock> { - on { getByName("domainObject") } doReturn element - } - val domainObject by container - - assertThat( - domainObject.foo, // just to prove domainObject's type is inferred correctly - nullValue()) - - assertThat( - domainObject, - sameInstance(element)) - } - - @Test - fun `can access existing element by getting`() { - - val element = DomainObject() - val container = mock> { - on { getByName("domainObject") } doReturn element - } - - container { // invoke syntax - val domainObject by getting - assertThat(domainObject, sameInstance(element)) - } - - container.apply { // regular syntax - val domainObject by getting - assertThat(domainObject, sameInstance(element)) - } - } - - @Test - fun `can configure existing element by getting`() { - - val element = DomainObject() - val container = mock> { - on { getByName("domainObject") } doReturn element - } - - container { // invoke syntax - @Suppress("unused_variable") - val domainObject by getting { foo = "foo" } - assertThat(element.foo, equalTo("foo")) - } - - container.apply { // regular syntax - @Suppress("unused_variable") - val domainObject by getting { foo = "bar" } - assertThat(element.foo, equalTo("bar")) - } - } - - @Test - fun `can add element by creating`() { - - val fooObject = DomainObject() - val barObject = DomainObject() - val container = mock> { - on { create("foo") } doReturn fooObject - on { getByName("foo") } doReturn fooObject - on { create("bar") } doReturn barObject - on { getByName("bar") } doReturn barObject - } - - container { // invoke syntax - val foo by creating - assertThat(foo.foo, nullValue()) - } - - container.apply { // regular syntax - val bar by creating - assertThat(bar.foo, nullValue()) - } - } - - @Test - fun `can add and configure element by creating`() { - - val fooObject = DomainObject() - val barObject = DomainObject() - val container = mock> { - on { create("foo") } doReturn fooObject - on { getByName("foo") } doReturn fooObject - on { create("bar") } doReturn barObject - on { getByName("bar") } doReturn barObject - } - - container { // invoke syntax - val foo by creating { foo = "foo" } - assertThat(foo.foo, equalTo("foo")) - } - - container.apply { // regular syntax - val bar by creating { foo = "bar" } - assertThat(bar.foo, equalTo("bar")) - } - } - - @Test - fun `can access existing typed element by getting`() { - - val element = DomainObject() - val container = mock> { - on { getByName("domainObject") } doReturn element - } - - container { // invoke syntax - val domainObject: DomainObject by getting - assertThat(domainObject, sameInstance(element)) - } - - container.apply { // regular syntax - val domainObject: DomainObject by getting - assertThat(domainObject, sameInstance(element)) - } - } - - @Test - fun `can access existing element by getting with type`() { - - val element = DomainObject() - val container = mock> { - on { getByName("domainObject") } doReturn element - } - - container { // invoke syntax - val domainObject by getting(DomainObject::class) - assertThat(domainObject, sameInstance(element)) - } - - container.apply { // regular syntax - val domainObject by getting(DomainObject::class) - assertThat(domainObject, sameInstance(element)) - } - } - - @Test - fun `can configure existing typed element by getting`() { - - val element = DomainObject() - val container = mock> { - on { getByName("domainObject") } doReturn element - } - - container { // invoke syntax - @Suppress("unused_variable") - val domainObject by getting(DomainObject::class) { foo = "foo" } - assertThat(element.foo, equalTo("foo")) - } - - container.apply { // regular syntax - @Suppress("unused_variable") - val domainObject by getting(DomainObject::class) { foo = "bar" } - assertThat(element.foo, equalTo("bar")) - } - } - - @Test - fun `can add typed element by creating`() { - - val fooObject = DomainObject() - val barObject = DomainObject() - val container = mock> { - on { create("foo", DomainObject::class.java) } doReturn fooObject - on { getByName("foo") } doReturn fooObject - on { create("bar", DomainObject::class.java) } doReturn barObject - on { getByName("bar") } doReturn barObject - } - - container { // invoke syntax - val foo by creating(DomainObject::class) - assertThat(foo.foo, nullValue()) - } - - container.apply { // regular syntax - val bar by creating(DomainObject::class) - assertThat(bar.foo, nullValue()) - } - } - - @Test - fun `can add and configure typed element by creating`() { - - val fooObject = DomainObject() - val barObject = DomainObject() - val container = mock> { - on { create("foo", DomainObject::class.java) } doReturn fooObject - on { getByName("foo") } doReturn fooObject - on { create("bar", DomainObject::class.java) } doReturn barObject - on { getByName("bar") } doReturn barObject - } - - container { // invoke syntax - val foo by creating(DomainObject::class) { foo = "foo" } - assertThat(foo.foo, equalTo("foo")) - } - - container.apply { // regular syntax - val bar by creating(DomainObject::class) { foo = "bar" } - assertThat(bar.foo, equalTo("bar")) - } - } - - @Test - fun `accessing existing element with wrong type gives proper error message`() { - - val container = mock> { - on { getByName("domainObject") } doReturn Object() - } - val domainObject: DomainObject by container - - val error = assertFailsWith(IllegalArgumentException::class) { - println(domainObject) - } - assertThat( - error.message, - matches("Element 'domainObject' of type 'java\\.lang\\.Object' from container '${Pattern.quote(container.toString())}' cannot be cast to '${Pattern.quote(DomainObject::class.qualifiedName)}'\\.")) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensionsTest.kt (revision 77224e2e1b7a9d00b29d08cc4230f3fd2d964621) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensionsTest.kt (revision 0) @@ -1,330 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.* - -import org.gradle.api.NamedDomainObjectContainer -import org.gradle.api.PolymorphicDomainObjectContainer -import org.gradle.api.Action -import org.gradle.api.Task -import org.gradle.api.tasks.Delete -import org.gradle.api.tasks.JavaExec -import org.gradle.api.tasks.TaskContainer - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.sameInstance -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class NamedDomainObjectContainerExtensionsTest { - - data class DomainObject(var foo: String? = null, var bar: Boolean? = null) - - @Test - fun `can use monomorphic container api`() { - - val alice = DomainObject() - val bob = DomainObject() - val john = DomainObject() - val container = mock> { - on { getByName("alice") } doReturn alice - on { create("bob") } doReturn bob - on { maybeCreate("john") } doReturn john - } - - // regular syntax - container.getByName("alice") { - it.foo = "alice-foo" - } - container.create("bob") { - it.foo = "bob-foo" - } - container.maybeCreate("john") - - // invoke syntax - container { - getByName("alice") { - it.foo = "alice-foo" - } - create("bob") { - it.foo = "bob-foo" - } - maybeCreate("john") - } - } - - @Test - fun `can use polymorphic container api`() { - - val alice = DomainObjectBase.Foo() - val bob = DomainObjectBase.Bar() - val default = DomainObjectBase.Default() - val container = mock> { - on { getByName("alice") } doReturn alice - on { maybeCreate("alice", DomainObjectBase.Foo::class.java) } doReturn alice - on { create(argThat { equals("bob") }, argThat { equals(DomainObjectBase.Bar::class.java) }, any>()) } doReturn bob - on { create("john", DomainObjectBase.Default::class.java) } doReturn default - } - - // regular syntax - container.getByName("alice") { - foo = "alice-foo-2" - } - container.maybeCreate("alice") - container.create("bob") { - bar = true - } - container.create("john") - - // invoke syntax - container { - getByName("alice") { - foo = "alice-foo-2" - } - maybeCreate("alice") - create("bob") { - bar = true - } - create("john") - } - } - - @Test - fun `can configure monomorphic container`() { - - val alice = DomainObject() - val bob = DomainObject() - val container = mock> { - on { maybeCreate("alice") } doReturn alice - on { maybeCreate("bob") } doReturn bob - } - - container { - "alice" { - foo = "alice-foo" - } - "alice" { - // will configure the same object as the previous block - bar = true - } - "bob" { - foo = "bob-foo" - bar = false - } - } - - assertThat( - alice, - equalTo(DomainObject("alice-foo", true))) - - assertThat( - bob, - equalTo(DomainObject("bob-foo", false))) - } - - sealed class DomainObjectBase { - data class Foo(var foo: String? = null) : DomainObjectBase() - data class Bar(var bar: Boolean? = null) : DomainObjectBase() - data class Default(val isDefault: Boolean = true) : DomainObjectBase() - } - - @Test - fun `can configure polymorphic container`() { - - val alice = DomainObjectBase.Foo() - val bob = DomainObjectBase.Bar() - val default: DomainObjectBase = DomainObjectBase.Default() - val container = mock> { - on { maybeCreate("alice", DomainObjectBase.Foo::class.java) } doReturn alice - on { maybeCreate("bob", DomainObjectBase.Bar::class.java) } doReturn bob - on { maybeCreate("jim") } doReturn default - on { maybeCreate("steve") } doReturn default - } - - container { - val a = "alice"(DomainObjectBase.Foo::class) { - foo = "foo" - } - val b = "bob"(type = DomainObjectBase.Bar::class) - val j = "jim" {} - val s = "steve"() // can invoke without a block, but must invoke - - assertThat(a, sameInstance(alice)) - assertThat(b, sameInstance(bob)) - assertThat(j, sameInstance(default)) - assertThat(s, sameInstance(default)) - } - - assertThat( - alice, - equalTo(DomainObjectBase.Foo("foo"))) - - assertThat( - bob, - equalTo(DomainObjectBase.Bar())) - } - - @Test - fun `can create and configure tasks`() { - - val clean = mock() - val tasks = mock { - on { create(argThat { equals("clean") }, argThat { equals(Delete::class.java) }, any>()) } doReturn clean - on { getByName("clean") } doReturn clean - on { maybeCreate("clean", Delete::class.java) } doReturn clean - } - - tasks { - create("clean") { - delete("some") - } - getByName("clean") { - delete("stuff") - } - "clean"(type = Delete::class) { - delete("things") - } - } - - tasks.getByName("clean") { - delete("build") - } - - inOrder(clean) { - verify(clean).delete("stuff") - verify(clean).delete("things") - verify(clean).delete("build") - } - } - - @Test - fun `can create element in monomorphic container via delegated property`() { - - val container = mock> { - on { create("domainObject") } doReturn DomainObject() - } - - @Suppress("unused_variable") - val domainObject by container.creating - - verify(container).create("domainObject") - } - - @Test - fun `can create and configure element in monomorphic container via delegated property`() { - - val element = DomainObject() - val container = mock> { - on { create("domainObject") } doReturn element - on { getByName("domainObject") } doReturn element - } - - val domainObject by container.creating { - foo = "domain-foo" - bar = true - } - - verify(container).create("domainObject") - assertThat( - domainObject, - equalTo(DomainObject("domain-foo", true))) - } - - @Test - fun `can create and configure element in polymorphic container via delegated property`() { - - val element = DomainObjectBase.Foo() - val container = mock> { - on { create("domainObject", DomainObjectBase.Foo::class.java) } doReturn element - on { getByName("domainObject") } doReturn element - } - - val domainObject by container.creating(type = DomainObjectBase.Foo::class) { - foo = "domain-foo" - } - - verify(container).create("domainObject", DomainObjectBase.Foo::class.java) - assertThat( - domainObject.foo, - equalTo("domain-foo")) - } - - @Test - fun `can create element in polymorphic container via delegated property`() { - - val container = mock> { - on { create("domainObject", DomainObjectBase.Foo::class.java) } doReturn DomainObjectBase.Foo() - } - - @Suppress("unused_variable") - val domainObject by container.creating(DomainObjectBase.Foo::class) - - verify(container).create("domainObject", DomainObjectBase.Foo::class.java) - } - - @Test - fun `can create element within configuration block via delegated property`() { - val tasks = mock { - on { create("hello") } doReturn mock() - } - - tasks { - @Suppress("unused_variable") - val hello by creating - } - verify(tasks).create("hello") - } - - @Test - fun `can get element of specific type within configuration block via delegated property`() { - val tasks = mock { - on { getByName("hello") } doReturn mock() - } - - @Suppress("unused_variable") - tasks { - val hello: JavaExec by getting - val ref = hello // forces the element to be accessed - } - verify(tasks).getByName("hello") - } - - @Test - fun `can create element of specific type within configuration block via delegated property`() { - - val container = mock> { - on { create("domainObject", DomainObjectBase.Foo::class.java) } doReturn DomainObjectBase.Foo() - } - - container { - - @Suppress("unused_variable") - val domainObject by creating(type = DomainObjectBase.Foo::class) - } - - verify(container).create("domainObject", DomainObjectBase.Foo::class.java) - } - - @Test - fun `can create and configure element of specific type within configuration block via delegated property`() { - - val element = DomainObjectBase.Foo() - val container = mock> { - on { create("domainObject", DomainObjectBase.Foo::class.java) } doReturn element - } - - container { - - @Suppress("unused_variable") - val domainObject by creating(DomainObjectBase.Foo::class) { - foo = "domain-foo" - } - } - - verify(container).create("domainObject", DomainObjectBase.Foo::class.java) - assertThat( - element.foo, - equalTo("domain-foo")) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensionsTest.kt (revision b4ccc6603ced6f46d755b78290dfa92660e47978) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensionsTest.kt (revision 0) @@ -1,180 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.inOrder -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify - -import org.gradle.api.Action -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.initialization.Settings -import org.gradle.api.invocation.Gradle -import org.gradle.api.plugins.ObjectConfigurationAction -import org.gradle.api.plugins.PluginAware - -import org.junit.Test - - -class PluginAwareExtensionsTest { - - @Test - fun `non reified apply extension on PluginAware`() { - assertNonReifiedApplyExtension() - } - - @Test - fun `non reified apply extension on Project`() { - assertNonReifiedApplyExtension() - } - - @Test - fun `non reified apply extension on Settings`() { - assertNonReifiedApplyExtension() - } - - @Test - fun `non reified apply extension on Gradle`() { - assertNonReifiedApplyExtension() - } - - @Test - fun `reified apply extension`() { - - newPluginAwareMock().run { - target.apply() - verify(configurationAction).plugin(AnyPlugin::class.java) - } - newPluginAwareMock().run { - target.apply() - verify(configurationAction).plugin(GradlePlugin::class.java) - } - newPluginAwareMock().run { - target.apply() - verify(configurationAction).plugin(SettingsPlugin::class.java) - } - newPluginAwareMock().run { - target.apply() - verify(configurationAction).plugin(ProjectPlugin::class.java) - } - } - - @Test - fun `reified apply to extension`() { - val arbitraryTarget = "something" - - newPluginAwareMock().run { - target.apply(to = arbitraryTarget) - inOrder(configurationAction) { - verify(configurationAction).plugin(AnyPlugin::class.java) - verify(configurationAction).to(arbitraryTarget) - } - } - newPluginAwareMock().run { - target.apply(to = arbitraryTarget) - inOrder(configurationAction) { - verify(configurationAction).plugin(AnyPlugin::class.java) - verify(configurationAction).to(arbitraryTarget) - } - } - newPluginAwareMock().run { - target.apply(to = arbitraryTarget) - inOrder(configurationAction) { - verify(configurationAction).plugin(AnyPlugin::class.java) - verify(configurationAction).to(arbitraryTarget) - } - } - newPluginAwareMock().run { - target.apply(to = arbitraryTarget) - inOrder(configurationAction) { - verify(configurationAction).plugin(AnyPlugin::class.java) - verify(configurationAction).to(arbitraryTarget) - } - } - } -} - - -private -inline fun assertNonReifiedApplyExtension() { - - val arbitraryTarget = "something" - - newPluginAwareMock().run { - target.apply(from = "script.gradle") - verify(configurationAction).from("script.gradle") - } - newPluginAwareMock().run { - target.apply(from = "script.gradle", to = arbitraryTarget) - inOrder(configurationAction) { - verify(configurationAction).from("script.gradle") - verify(configurationAction).to(arbitraryTarget) - } - } - newPluginAwareMock().run { - target.apply(plugin = "some-id") - verify(configurationAction).plugin("some-id") - } - newPluginAwareMock().run { - target.apply(plugin = "some-id", to = arbitraryTarget) - inOrder(configurationAction) { - verify(configurationAction).plugin("some-id") - verify(configurationAction).to(arbitraryTarget) - } - } - newPluginAwareMock().run { - target.apply(from = "script.gradle", plugin = "some-id") - inOrder(configurationAction) { - verify(configurationAction).plugin("some-id") - verify(configurationAction).from("script.gradle") - } - } - newPluginAwareMock().run { - target.apply(from = "script.gradle", plugin = "some-id", to = arbitraryTarget) - inOrder(configurationAction) { - verify(configurationAction).plugin("some-id") - verify(configurationAction).from("script.gradle") - verify(configurationAction).to(arbitraryTarget) - } - } -} - - -private -class PluginAwareMock(val target: T, val configurationAction: ObjectConfigurationAction) - - -private -inline fun newPluginAwareMock(): PluginAwareMock { - val configurationAction = mock() - val target = mock { - on { apply(any>()) }.then { - (it.getArgument(0) as Action).execute(configurationAction) - } - } - return PluginAwareMock(target, configurationAction) -} - - -private -class GradlePlugin : Plugin { - override fun apply(target: Gradle) = Unit -} - - -private -class SettingsPlugin : Plugin { - override fun apply(target: Settings) = Unit -} - - -private -class ProjectPlugin : Plugin { - override fun apply(target: Project) = Unit -} - - -private -class AnyPlugin : Plugin { - override fun apply(target: Any) = Unit -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScopeTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScopeTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScopeTest.kt (revision 0) @@ -1,96 +0,0 @@ -package org.gradle.kotlin.dsl - -import org.gradle.groovy.scripts.StringScriptSource - -import org.gradle.plugin.management.internal.PluginRequestInternal -import org.gradle.plugin.management.internal.autoapply.AutoAppliedBuildScanPlugin -import org.gradle.plugin.use.PluginDependenciesSpec -import org.gradle.plugin.use.internal.PluginRequestCollector - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class PluginDependenciesSpecScopeTest { - - @Test - fun `given a single id, it should create a single request with no version`() { - expecting(plugin(id = "plugin-id")) { - id("plugin-id") - } - } - - @Test - fun `given a single id and apply value, it should create a single request with no version`() { - listOf(true, false).forEach { applyValue -> - expecting(plugin(id = "plugin-id", isApply = applyValue)) { - id("plugin-id") apply applyValue - } - } - } - - @Test - fun `given a single id and version, it should create a single request`() { - expecting(plugin(id = "plugin-id", version = "1.0")) { - id("plugin-id") version "1.0" - } - } - - @Test - fun `given two ids and a single version, it should create two requests`() { - expecting(plugin(id = "plugin-a", version = "1.0"), plugin(id = "plugin-b")) { - id("plugin-a") version "1.0" - id("plugin-b") - } - } - - @Test - fun `given build-scan plugin accessor, it should create a single request matching the auto-applied plugin version`() { - expecting(plugin(id = "com.gradle.build-scan", version = AutoAppliedBuildScanPlugin.VERSION)) { - `build-scan` - } - } - - @Test - fun `given build-scan plugin accessor with version, it should create a single request with given version`() { - expecting(plugin(id = "com.gradle.build-scan", version = "1.7.1")) { - `build-scan` version "1.7.1" - } - } - - @Test - fun `given kotlin plugin accessor, it should create a single request with no version`() { - expecting(plugin(id = "org.jetbrains.kotlin.jvm", version = null)) { - kotlin("jvm") - } - } - - @Test - fun `given kotlin plugin accessor with version, it should create a single request with given version`() { - expecting(plugin(id = "org.jetbrains.kotlin.jvm", version = "1.1.1")) { - kotlin("jvm") version "1.1.1" - } - } -} - - -fun expecting(vararg expected: Plugin, block: PluginDependenciesSpec.() -> Unit) { - assertThat( - plugins(block).map { Plugin(it.id.id, it.version, it.isApply) }, - equalTo(expected.asList())) -} - - -fun plugins(block: PluginDependenciesSpecScope.() -> Unit): List = - PluginRequestCollector(StringScriptSource("script", "")).run { - PluginDependenciesSpecScope(createSpec(1)).block() - pluginRequests.toList() - } - - -fun plugin(id: String, version: String? = null, isApply: Boolean = true) = Plugin(id, version, isApply) - - -data class Plugin(val id: String, val version: String?, val isApply: Boolean) Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/ProjectExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/ProjectExtensionsTest.kt (revision c6efbaca26f925c27812ed560d665290b0f5c773) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/ProjectExtensionsTest.kt (revision 0) @@ -1,181 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.eq -import com.nhaarman.mockito_kotlin.inOrder -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify -import com.nhaarman.mockito_kotlin.whenever - -import org.gradle.api.Action -import org.gradle.api.NamedDomainObjectContainer -import org.gradle.api.Project -import org.gradle.api.UnknownDomainObjectException -import org.gradle.api.plugins.Convention -import org.gradle.api.plugins.JavaPluginConvention -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.reflect.TypeOf - -import org.junit.Assert.fail -import org.junit.Test - - -class ProjectExtensionsTest { - - @Test - fun `can configure deferred configurable extension`() { - - val project = mock() - val convention = mock() - val extensionType = typeOf() - - whenever(project.convention) - .thenReturn(convention) - - project.configure { - fail("configuration action should be deferred") - } - - verify(convention).configure(eq(extensionType), any()) - } - - @Test - fun `can get generic project extension by type`() { - - val project = mock() - val convention = mock() - val extension = mock>>() - val extensionType = typeOf>>() - - whenever(project.convention) - .thenReturn(convention) - whenever(convention.findByType(eq(extensionType))) - .thenReturn(extension) - - project.the>>() - - inOrder(convention) { - verify(convention).findByType(eq(extensionType)) - verifyNoMoreInteractions() - } - } - - @Test - fun `can configure generic project extension by type`() { - - val project = mock() - val convention = mock() - val extension = mock>>() - val extensionType = typeOf>>() - - whenever(project.convention) - .thenReturn(convention) - whenever(convention.findByType(eq(extensionType))) - .thenReturn(extension) - - project.configure>> {} - - inOrder(convention) { - verify(convention).findByType(eq(extensionType)) - verifyNoMoreInteractions() - } - } - - @Test - fun `can get convention by type`() { - - val project = mock() - val convention = mock() - val javaConvention = mock() - - whenever(project.convention) - .thenReturn(convention) - whenever(convention.findPlugin(eq(JavaPluginConvention::class.java))) - .thenReturn(javaConvention) - - project.the() - - inOrder(convention) { - verify(convention).findByType(any>()) - verify(convention).findPlugin(eq(JavaPluginConvention::class.java)) - verifyNoMoreInteractions() - } - } - - @Test - fun `can configure convention by type`() { - - val project = mock() - val convention = mock() - val javaConvention = mock() - - whenever(project.convention) - .thenReturn(convention) - whenever(convention.findByType(any>())) - .thenReturn(null) - whenever(convention.findPlugin(eq(JavaPluginConvention::class.java))) - .thenReturn(javaConvention) - - project.configure {} - - inOrder(convention) { - verify(convention).findByType(any>()) - verify(convention).findPlugin(eq(JavaPluginConvention::class.java)) - verifyNoMoreInteractions() - } - } - - @Test - fun `the() falls back to throwing getByType when not found`() { - - val project = mock() - val convention = mock() - val conventionType = typeOf() - - whenever(project.convention) - .thenReturn(convention) - whenever(convention.getByType(eq(conventionType))) - .thenThrow(UnknownDomainObjectException::class.java) - - try { - project.the() - fail("UnknownDomainObjectException not thrown") - } catch (ex: UnknownDomainObjectException) { - // expected - } - - inOrder(convention) { - verify(convention).findByType(eq(conventionType)) - verify(convention).findPlugin(eq(JavaPluginConvention::class.java)) - verify(convention).getByType(eq(conventionType)) - verifyNoMoreInteractions() - } - } - - @Test - fun `configure() falls back to throwing configure when not found`() { - - val project = mock() - val convention = mock() - val conventionType = typeOf() - - whenever(project.convention) - .thenReturn(convention) - whenever(convention.configure(eq(conventionType), any>())) - .thenThrow(UnknownDomainObjectException::class.java) - - try { - project.configure {} - fail("UnknownDomainObjectException not thrown") - } catch (ex: UnknownDomainObjectException) { - // expected - } - - inOrder(convention) { - verify(convention).findByType(eq(conventionType)) - verify(convention).findPlugin(eq(JavaPluginConvention::class.java)) - verify(convention).configure(eq(conventionType), any>()) - verifyNoMoreInteractions() - } - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/RepositoryHandlerExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/RepositoryHandlerExtensionsTest.kt (revision 05c6e9e4957fa24d056555a5b6a10c9499bed582) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/RepositoryHandlerExtensionsTest.kt (revision 0) @@ -1,99 +0,0 @@ -package org.gradle.kotlin.dsl - -import com.nhaarman.mockito_kotlin.* -import org.gradle.api.Action - -import org.gradle.api.artifacts.dsl.RepositoryHandler -import org.gradle.api.artifacts.repositories.IvyArtifactRepository -import org.gradle.api.artifacts.repositories.MavenArtifactRepository - -import org.junit.Test -import org.mockito.invocation.InvocationOnMock - - -class RepositoryHandlerExtensionsTest { - - @Test - fun `#maven(String)`() { - - val repository = mock() - val repositories = mavenRepositoryHandlerMockFor(repository) - - val url = Any() - repositories { - maven(url = url) - } - - verify(repository, only()).setUrl(url) - } - - @Test - fun `#maven(String, Action) sets url before invoking configuration action`() { - - val repository = mock() - val repositories = mavenRepositoryHandlerMockFor(repository) - - val url = Any() - repositories { - maven(url = url) { - verify(repository).setUrl(url) - name = "repo name" - } - } - - verify(repository).name = "repo name" - } - - @Test - fun `#ivy(String)`() { - - val repository = mock() - val repositories = ivyRepositoryHandlerMockFor(repository) - - val url = Any() - repositories { - ivy(url = url) - } - - verify(repository, only()).setUrl(url) - } - - @Test - fun `#ivy(String, Action) sets url before invoking configuration action`() { - - val repository = mock() - val repositories = ivyRepositoryHandlerMockFor(repository) - - val url = Any() - repositories { - ivy(url = url) { - verify(repository).setUrl(url) - name = "repo name" - } - } - - verify(repository).name = "repo name" - } - - private - inline operator fun RepositoryHandler.invoke(action: RepositoryHandler.() -> Unit) = apply(action) - - private - fun mavenRepositoryHandlerMockFor(repository: MavenArtifactRepository) = mock { - on { maven(any>()) }.then { - it.configureWithAction(repository) - } - } - - private - fun ivyRepositoryHandlerMockFor(repository: IvyArtifactRepository) = mock { - on { ivy(any>()) }.then { - it.configureWithAction(repository) - } - } - - private - fun InvocationOnMock.configureWithAction(repository: T): T = repository.also { - getArgument>(0).execute(it) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/SpecExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/SpecExtensionsTest.kt (revision ef3f20787f09a560b3bb6de4edfd74cde7790089) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/SpecExtensionsTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl - -import org.gradle.api.specs.Spec -import org.junit.Assert.assertTrue -import org.junit.Test - - -class SpecExtensionsTest { - - @Test - fun `can use function invocation syntax on Spec instances`() { - - val spec = Spec { it } - assertTrue(spec(true)) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/TaskContainerExtensionsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/TaskContainerExtensionsTest.kt (revision 249212884e83db41f40ae6a753562a43770bd6cd) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/TaskContainerExtensionsTest.kt (revision 0) @@ -1,23 +0,0 @@ -package org.gradle.kotlin.dsl - -import org.gradle.api.DefaultTask -import org.gradle.api.tasks.TaskContainer - -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify - -import org.junit.Test - - -class TaskContainerExtensionsTest { - - @Test - fun `can create tasks with injected constructor arguments`() { - - val tasks = mock() - - tasks.create("my", "foo", "bar") - - verify(tasks).create("my", DefaultTask::class.java, "foo", "bar") - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/GenerateProjectSchemaTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/GenerateProjectSchemaTest.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/GenerateProjectSchemaTest.kt (revision 0) @@ -1,174 +0,0 @@ -package org.gradle.kotlin.dsl.accessors - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Test - - -class GenerateProjectSchemaTest : AbstractIntegrationTest() { - - @Test - fun `writes multi-project schema to gradle slash project dash schema dot json`() { - - withSettings(""" - include("sub-java") - include("sub-groovy") - include("sub-kotlin-dsl") - """) - - withBuildScript(""" - plugins { - base - `kotlin-dsl` apply false - } - subprojects { - apply(plugin = "java") - } - project(":sub-groovy") { - apply(plugin = "groovy") - } - project(":sub-kotlin-dsl") { - apply(plugin = "org.gradle.kotlin.kotlin-dsl") - } - """) - - build("kotlinDslAccessorsSnapshot") - - val generatedSchema = - loadMultiProjectSchemaFrom( - existing("gradle/project-schema.json")) - - val expectedSchema = - mapOf( - ":" to baseProjectSchema, - ":sub-groovy" to groovyProjectSchema, - ":sub-java" to javaProjectSchema, - ":sub-kotlin-dsl" to kotlinDslProjectSchema) - - assertThat( - generatedSchema, - equalTo(expectedSchema)) - } -} - - -private -val baseProjectSchema = ProjectSchema( - extensions = listOf( - ProjectSchemaEntry( - "org.gradle.api.Project", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension"), - ProjectSchemaEntry( - "org.gradle.api.Project", - "defaultArtifacts", - "org.gradle.api.internal.plugins.DefaultArtifactPublicationSet"), - ProjectSchemaEntry( - "org.gradle.api.internal.plugins.DefaultArtifactPublicationSet", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension")), - conventions = listOf( - ProjectSchemaEntry( - "org.gradle.api.Project", - "base", - "org.gradle.api.plugins.BasePluginConvention")), - configurations = listOf("archives", "default")) - - -private -fun javaExtensionsWith(otherExtensions: List>) = - baseProjectSchema.extensions + - listOf( - ProjectSchemaEntry( - "org.gradle.api.Project", - "reporting", - "org.gradle.api.reporting.ReportingExtension"), - ProjectSchemaEntry( - "org.gradle.api.reporting.ReportingExtension", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension")) + - otherExtensions + - listOf( - ProjectSchemaEntry( - "org.gradle.api.tasks.SourceSet", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension")) - - -private -val javaProjectSchema: ProjectSchema = - ProjectSchema( - extensions = javaExtensionsWith(emptyList()), - conventions = baseProjectSchema.conventions + listOf( - ProjectSchemaEntry( - "org.gradle.api.Project", - "java", - "org.gradle.api.plugins.JavaPluginConvention")), - configurations = (baseProjectSchema.configurations + listOf( - "annotationProcessor", - "apiElements", - "compile", "compileClasspath", "compileOnly", - "implementation", - "runtime", "runtimeClasspath", "runtimeElements", "runtimeOnly", - "testAnnotationProcessor", - "testCompile", "testCompileClasspath", "testCompileOnly", - "testImplementation", - "testRuntime", "testRuntimeClasspath", "testRuntimeOnly")).sorted()) - - -private -val groovyProjectSchema: ProjectSchema = - ProjectSchema( - extensions = javaExtensionsWith(listOf( - ProjectSchemaEntry( - "org.gradle.api.Project", - "groovyRuntime", - "org.gradle.api.tasks.GroovyRuntime"), - ProjectSchemaEntry( - "org.gradle.api.tasks.GroovyRuntime", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension"))), - conventions = javaProjectSchema.conventions, - configurations = javaProjectSchema.configurations) - - -private -val kotlinDslProjectSchema: ProjectSchema = - ProjectSchema( - extensions = javaExtensionsWith(listOf( - ProjectSchemaEntry( - "org.gradle.api.Project", - "kotlin", - "org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension"), - ProjectSchemaEntry( - "org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension"), - ProjectSchemaEntry( - "org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension", - "experimental", - "org.jetbrains.kotlin.gradle.dsl.ExperimentalExtension"), - ProjectSchemaEntry( - "org.jetbrains.kotlin.gradle.dsl.ExperimentalExtension", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension"), - ProjectSchemaEntry( - "org.gradle.api.Project", - "kapt", - "org.jetbrains.kotlin.gradle.plugin.KaptExtension"), - ProjectSchemaEntry( - "org.jetbrains.kotlin.gradle.plugin.KaptExtension", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension"), - ProjectSchemaEntry( - "org.gradle.api.Project", - "samWithReceiver", - "org.jetbrains.kotlin.samWithReceiver.gradle.SamWithReceiverExtension"), - ProjectSchemaEntry( - "org.jetbrains.kotlin.samWithReceiver.gradle.SamWithReceiverExtension", - "ext", - "org.gradle.api.plugins.ExtraPropertiesExtension"))), - conventions = javaProjectSchema.conventions, - configurations = (javaProjectSchema.configurations + listOf("embeddedKotlin", "kapt", "kaptTest")).sorted()) Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/KotlinTypeStringTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/KotlinTypeStringTest.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/KotlinTypeStringTest.kt (revision 0) @@ -1,49 +0,0 @@ -package org.gradle.kotlin.dsl.accessors - -import org.gradle.api.reflect.TypeOf.typeOf - -import org.gradle.kotlin.dsl.typeOf - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Test - - -class KotlinTypeStringTest { - - @Test - fun `#kotlinTypeStringFor array type`() { - assertThat( - kotlinTypeStringFor(typeOf>()), - equalTo("Array")) - } - - @Test - fun `#kotlinTypeStringFor parameterized type`() { - assertThat( - kotlinTypeStringFor(typeOf>>()), - equalTo("java.util.List>")) - } - - @Test - fun `#kotlinTypeStringFor primitive type`() { - assertPrimitiveTypeName(java.lang.Boolean.TYPE) - assertPrimitiveTypeName(java.lang.Character.TYPE) - assertPrimitiveTypeName(java.lang.Byte.TYPE) - assertPrimitiveTypeName(java.lang.Short.TYPE) - assertPrimitiveTypeName(java.lang.Integer.TYPE) - assertPrimitiveTypeName(java.lang.Long.TYPE) - assertPrimitiveTypeName(java.lang.Float.TYPE) - assertPrimitiveTypeName(java.lang.Double.TYPE) - } - - private - inline fun assertPrimitiveTypeName(primitiveTypeClass: Class<*>) { - assertThat( - kotlinTypeStringFor(typeOf(primitiveTypeClass)), - equalTo(T::class.simpleName)) - assertThat( - kotlinTypeStringFor(typeOf()), - equalTo(T::class.simpleName)) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaAccessorsIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaAccessorsIntegrationTest.kt (revision 4972bc463f614c45f5622356aea48cabd40f28bf) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaAccessorsIntegrationTest.kt (revision 0) @@ -1,535 +0,0 @@ -package org.gradle.kotlin.dsl.accessors - -import org.gradle.kotlin.dsl.integration.kotlinBuildScriptModelFor - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.gradle.kotlin.dsl.fixtures.fileByName -import org.gradle.kotlin.dsl.fixtures.matching - -import org.hamcrest.CoreMatchers.* -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - -import java.io.File - - -class ProjectSchemaAccessorsIntegrationTest : AbstractIntegrationTest() { - - @Test - fun `can configure deferred configurable extension`() { - - withBuildScript(""" - - import org.gradle.api.publish.maven.MavenPublication - - plugins { - `java-library` - `maven-publish` - } - - dependencies { - api("com.google.guava:guava:21.0") - } - - publishing { - publications.create("mavenJavaLibrary") { - from(components["java"]) - } - } - - dependencies { - api("org.apache.commons:commons-lang3:3.5") - } - - """) - - build("generatePom") - - val pom = existing("build/publications/mavenJavaLibrary/pom-default.xml").readText() - assertThat(pom, containsString("com.google.guava")) - assertThat(pom, containsString("commons-lang3")) - } - - @Test - fun `can access NamedDomainObjectContainer extension via generated accessor`() { - - withKotlinBuildSrc() - - withFile("buildSrc/src/main/kotlin/my/DocumentationPlugin.kt", """ - package my - - import org.gradle.api.* - - class DocumentationPlugin : Plugin { - - override fun apply(project: Project) { - val books = project.container(Book::class.java, ::Book) - project.extensions.add("the books", books) - } - } - - data class Book(val name: String) - - """) - - val buildFile = withBuildScript(""" - - apply() - - """) - - - println( - build("kotlinDslAccessorsSnapshot").output) - - - buildFile.appendText(""" - - (`the books`) { - "quickStart" { - } - "userGuide" { - } - } - - tasks { - "books" { - doLast { println(`the books`.joinToString { it.name }) } - } - } - - """) - assertThat( - build("books").output, - containsString("quickStart, userGuide")) - } - - @Test - fun `can access extensions registered by declared plugins via jit accessor`() { - - withBuildScript(""" - plugins { application } - - application { mainClassName = "App" } - - task("mainClassName") { - doLast { println("*" + application.mainClassName + "*") } - } - """) - - assertThat( - build("mainClassName").output, - containsString("*App*")) - } - - @Test - fun `can access configurations registered by declared plugins via jit accessor`() { - - withSettings(""" - include("a", "b", "c") - """) - - withBuildScriptIn("a", """ - plugins { `java-library` } - """) - - withBuildScriptIn("b", """ - plugins { `java-library` } - - dependencies { - compile("org.apache.commons:commons-io:1.3.2") - } - - repositories { jcenter() } - """) - - withBuildScriptIn("c", """ - plugins { `java-library` } - - dependencies { - compileOnly(group = "org.slf4j", name = "slf4j-api", version = "1.7.25") - api("com.google.guava:guava:21.0") - implementation("ch.qos.logback:logback-classic:1.2.3") { - isTransitive = false - } - implementation(project(":a")) - implementation(project(":b")) { - exclude(group = "org.apache.commons") - } - } - - repositories { jcenter() } - - configurations.compileClasspath.files.forEach { - println(org.gradle.util.TextUtil.normaliseFileSeparators(it.path)) - } - """) - - val result = build("help", "-q") - - assertThat( - result.output, - allOf( - containsString("slf4j-api-1.7.25.jar"), - containsString("guava-21.0.jar"), - containsString("logback-classic-1.2.3.jar"), - containsString("a/build/classes/java/main"), - containsString("b/build/classes/java/main"), - not(containsString("logback-core")), - not(containsString("commons-io")))) - } - - @Test - fun `classpath model includes generated accessors`() { - - val buildFile = withBuildScript(""" - plugins { java } - """) - - println( - build("kotlinDslAccessorsSnapshot").output) - - assertAccessorsInClassPathOf(buildFile) - } - - @Test - fun `classpath model includes jit accessors by default`() { - - val buildFile = withBuildScript(""" - plugins { java } - """) - - assertAccessorsInClassPathOf(buildFile) - } - - @Test - fun `jit accessors can be turned off`() { - - val buildFile = withBuildScript(""" - plugins { java } - """) - - withFile("gradle.properties", "org.gradle.kotlin.dsl.accessors=off") - - assertThat( - classPathFor(buildFile), - not(hasAccessorsJar())) - } - - @Test - fun `the set of jit accessors is a function of the set of applied plugins`() { - - val s1 = setOfAutomaticAccessorsFor(setOf("application")) - val s2 = setOfAutomaticAccessorsFor(setOf("java")) - val s3 = setOfAutomaticAccessorsFor(setOf("application")) - val s4 = setOfAutomaticAccessorsFor(setOf("application", "java")) - val s5 = setOfAutomaticAccessorsFor(setOf("java")) - - assertThat(s1, not(equalTo(s2))) // application ≠ java - assertThat(s1, equalTo(s3)) // application = application - assertThat(s2, equalTo(s5)) // java = java - assertThat(s1, equalTo(s4)) // application ⊇ java - } - - @Test - fun `accessors tasks applied in a mixed Groovy-Kotlin multi-project build`() { - - withSettings("include(\"a\")") - withBuildScriptIn("a", "") - - val aTasks = build(":a:tasks").output - assertThat(aTasks, containsString("kotlinDslAccessorsReport")) - assertThat(aTasks, not(containsString("kotlinDslAccessorsSnapshot"))) - - val rootTasks = build(":tasks").output - assertThat(rootTasks, allOf(containsString("kotlinDslAccessorsReport"), containsString("kotlinDslAccessorsSnapshot"))) - } - - @Test - fun `given extension with inaccessible type, its accessor is typed Any`() { - - withFile("init.gradle", """ - initscript { - repositories { - gradlePluginPortal() - } - dependencies { - classpath "com.gradle:build-scan-plugin:1.8" - } - } - rootProject { - apply plugin: "base" - apply plugin: initscript.classLoader.loadClass("com.gradle.scan.plugin.BuildScanPlugin") - buildScan { - publishAlways() - } - } - """) - - withBuildScript(""" - - inline fun typeOf(t: T) = T::class.simpleName - - buildScan { - println("Type of `buildScan` receiver is " + typeOf(this@buildScan)) - } - """) - - val result = build("help", "-I", "init.gradle") - assertThat(result.output, containsString("Type of `buildScan` receiver is Any")) - } - - @Test - fun `given extension with erased generic type parameters, its accessor is typed Any`() { - - withFile("buildSrc/build.gradle.kts", """ - plugins { - `kotlin-dsl` - `java-gradle-plugin` - } - - gradlePlugin { - (plugins) { - "mine" { - id = "mine" - implementationClass = "foo.FooPlugin" - } - } - } - """) - - withFile("buildSrc/src/main/kotlin/foo/FooPlugin.kt", """ - package foo - - import org.gradle.api.* - - open class MyExtension - - open class FooPlugin : Plugin { - override fun apply(project: Project): Unit = project.run { - // Using add() without specifying the public type causes type erasure - extensions.add("mine", MyExtension()) - } - } - """) - - withBuildScript(""" - plugins { - id("mine") - } - - inline fun typeOf(t: T) = T::class.simpleName - - mine { - println("Type of `mine` receiver is " + typeOf(this@mine)) - } - """) - - val result = build("help") - assertThat(result.output, containsString("Type of `mine` receiver is Any")) - } - - @Test - fun `can access nested extensions and conventions registered by declared plugins via jit accessors`() { - withBuildScriptIn("buildSrc", """ - plugins { - `java-gradle-plugin` - `kotlin-dsl` - } - gradlePlugin { - (plugins) { - "my-plugin" { - id = "my-plugin" - implementationClass = "plugins.MyPlugin" - } - } - } - """) - - withFile("buildSrc/src/main/kotlin/plugins/MyPlugin.kt", """ - package plugins - - import org.gradle.api.* - import org.gradle.api.plugins.* - import org.gradle.api.internal.* - import org.gradle.api.internal.plugins.* - - open class MyPlugin : Plugin { - override fun apply(project: Project): Unit = project.run { - - val rootExtension = MyExtension("root") - val rootExtensionNestedExtension = MyExtension("nested-in-extension") - val rootExtensionNestedConvention = MyConvention("nested-in-extension") - - extensions.add("rootExtension", rootExtension) - - rootExtension.extensions.add("nestedExtension", rootExtensionNestedExtension) - rootExtensionNestedExtension.extensions.add("deepExtension", listOf("foo", "bar")) - - rootExtensionNestedConvention.extensions.add("deepExtension", mapOf("foo" to "bar")) - - val rootConvention = MyConvention("root") - val rootConventionNestedExtension = MyExtension("nested-in-convention") - val rootConventionNestedConvention = MyConvention("nested-in-convention") - - convention.plugins.put("rootConvention", rootConvention) - - rootConvention.extensions.add("nestedExtension", rootConventionNestedExtension) - rootConventionNestedExtension.extensions.add("deepExtension", listOf("bazar", "cathedral")) - - rootConventionNestedConvention.extensions.add("deepExtension", mapOf("bazar" to "cathedral")) - } - } - - class MyExtension(val value: String = "value") : ExtensionAware, HasConvention { - private val convention: DefaultConvention = DefaultConvention() - override fun getExtensions(): ExtensionContainer = convention - override fun getConvention(): Convention = convention - } - - class MyConvention(val value: String = "value") : ExtensionAware, HasConvention { - private val convention: DefaultConvention = DefaultConvention() - override fun getExtensions(): ExtensionContainer = convention - override fun getConvention(): Convention = convention - } - """) - - withBuildScript(""" - plugins { - id("my-plugin") - } - - rootExtension { - nestedExtension { - require(value == "nested-in-extension", { "rootExtension.nestedExtension" }) - require(deepExtension == listOf("foo", "bar"), { "rootExtension.nestedExtension.deepExtension" }) - } - } - - rootConvention { - nestedExtension { - require(value == "nested-in-convention", { "rootConvention.nestedExtension" }) - require(deepExtension == listOf("bazar", "cathedral"), { "rootConvention.nestedExtension.deepExtension" }) - } - } - """) - - build("help") - } - - @Test - fun `convention accessors honor HasPublicType`() { - withBuildScriptIn("buildSrc", """ - plugins { - `java-gradle-plugin` - `kotlin-dsl` - } - gradlePlugin { - (plugins) { - "my-plugin" { - id = "my-plugin" - implementationClass = "plugins.MyPlugin" - } - } - } - """) - - withFile("buildSrc/src/main/kotlin/plugins/MyPlugin.kt", """ - package plugins - - import org.gradle.api.* - import org.gradle.api.plugins.* - - open class MyPlugin : Plugin { - override fun apply(project: Project): Unit = project.run { - convention.plugins.put("myConvention", MyPrivateConventionImpl()) - } - } - """) - - withFile("buildSrc/src/main/kotlin/plugins/MyConvention.kt", """ - package plugins - - interface MyConvention - - internal - class MyPrivateConventionImpl : MyConvention - """) - - withBuildScript(""" - plugins { - id("my-plugin") - } - - inline fun typeOf(t: T) = T::class.simpleName - - myConvention { - println("Type of `myConvention` receiver is " + typeOf(this@myConvention)) - } - """) - - assertThat( - build("help").output, - containsString("Type of `myConvention` receiver is Any")) - - withFile("buildSrc/src/main/kotlin/plugins/MyConvention.kt", """ - package plugins - - import org.gradle.api.reflect.* - import org.gradle.kotlin.dsl.* - - interface MyConvention - - internal - class MyPrivateConventionImpl : MyConvention, HasPublicType { - override fun getPublicType() = typeOf() - } - """) - - assertThat( - build("help").output, - containsString("Type of `myConvention` receiver is MyConvention")) - } - - private - fun setOfAutomaticAccessorsFor(plugins: Set): File { - val script = "plugins {\n${plugins.joinToString(separator = "\n")}\n}" - val buildFile = withBuildScript(script, produceFile = ::newOrExisting) - return accessorsJarFor(buildFile)!!.relativeTo(buildFile.parentFile) - } - - private - fun assertAccessorsInClassPathOf(buildFile: File) { - val model = kotlinBuildScriptModelFor(buildFile) - assertThat(model.classPath, hasAccessorsJar()) - assertThat(model.sourcePath, hasAccessorsSource()) - } - - private - fun hasAccessorsSource() = - hasItem( - matching({ appendText("accessors source") }) { - File(this, "org/gradle/kotlin/dsl/accessors.kt").isFile - }) - - private - fun hasAccessorsJar() = - hasItem(fileByName(accessorsJarFileName)) - - private - fun accessorsJarFor(buildFile: File) = - classPathFor(buildFile) - .find { it.isFile && it.name == accessorsJarFileName } - - private - val accessorsJarFileName = "gradle-kotlin-dsl-accessors.jar" - - private - fun classPathFor(buildFile: File) = - kotlinBuildScriptModelFor(buildFile).classPath - - private - fun kotlinBuildScriptModelFor(buildFile: File) = - kotlinBuildScriptModelFor(projectRoot, buildFile) -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaTest.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/ProjectSchemaTest.kt (revision 0) @@ -1,179 +0,0 @@ -package org.gradle.kotlin.dsl.accessors - -import org.gradle.api.Project - -import org.gradle.internal.classpath.ClassPath - -import org.gradle.kotlin.dsl.typeOf - -import org.hamcrest.CoreMatchers.equalTo - -import org.junit.Assert.assertThat -import org.junit.Assert.assertFalse -import org.junit.Test - -import org.objectweb.asm.Opcodes.ACC_PUBLIC -import org.objectweb.asm.Opcodes.ACC_SYNTHETIC - - -@Suppress("unused") -class PublicGenericType - - -class PublicComponentType - - -private -class PrivateComponentType - - -class ProjectSchemaTest : TestWithClassPath() { - - @Test - fun `#isLegalAccessorName rejects illegal Kotlin extension names`() { - - assert(isLegalAccessorName("foo_bar")) - assert(isLegalAccessorName("foo-bar")) - assert(isLegalAccessorName("foo bar")) - assert(isLegalAccessorName("'foo'bar'")) - assert(isLegalAccessorName("foo${'$'}${'$'}bar")) - - assertFalse(isLegalAccessorName("foo`bar")) - assertFalse(isLegalAccessorName("foo.bar")) - assertFalse(isLegalAccessorName("foo/bar")) - assertFalse(isLegalAccessorName("foo\\bar")) - } - - @Test - fun `accessor name spec escapes string template dollar signs`() { - val original = "foo${'$'}${'$'}bar" - val spec = AccessorNameSpec(original) - - assertThat(spec.original, equalTo(original)) - assertThat(spec.kotlinIdentifier, equalTo(original)) - assertThat(spec.stringLiteral, equalTo("foo${'$'}{'${'$'}'}${'$'}{'${'$'}'}bar")) - } - - @Test - fun `non existing type is represented as Inaccessible because NonAvailable`() { - - val typeString = "non.existing.Type" - - val projectSchema = availableProjectSchemaFor( - schemaWithExtensions("buildScan" to typeString), - ClassPath.EMPTY) - - assertThat( - projectSchema.extension("buildScan").type, - equalTo(inaccessible(typeString, nonAvailable(typeString)))) - } - - @Test - fun `public type is represented as Accessible`() { - - val typeString = "existing.Type" - - val projectSchema = availableProjectSchemaFor( - schemaWithExtensions("buildScan" to typeString), - classPathWithPublicType(typeString)) - - assertThat( - projectSchema.extension("buildScan").type, - equalTo(accessible(typeString))) - } - - @Test - fun `private type is represented as Inaccessible because NonPublic`() { - - val typeString = "non.visible.Type" - - val projectSchema = availableProjectSchemaFor( - schemaWithExtensions("buildScan" to typeString), - classPathWithPrivateType(typeString)) - - assertThat( - projectSchema.extension("buildScan").type, - equalTo(inaccessible(typeString, nonPublic(typeString)))) - } - - @Test - fun `public synthetic type is represented as Inaccessible because Synthetic`() { - - val typeString = "synthetic.Type" - - val projectSchema = availableProjectSchemaFor( - schemaWithExtensions("buildScan" to typeString), - classPathWithType(typeString, ACC_PUBLIC, ACC_SYNTHETIC)) - - assertThat( - projectSchema.extension("buildScan").type, - equalTo(inaccessible(typeString, synthetic(typeString)))) - } - - @Test - fun `parameterized public type with public component type is represented as Accessible`() { - - val genericTypeString = kotlinTypeStringFor(typeOf>()) - - val projectSchema = availableProjectSchemaFor( - schemaWithExtensions("generic" to genericTypeString), - classPathWith(PublicGenericType::class, PublicComponentType::class)) - - assertThat( - projectSchema.extension("generic").type, - equalTo(accessible(genericTypeString))) - } - - @Test - fun `parameterized public type with non public component type is represented as Inaccessible because of NonPublic component type`() { - - val genericTypeString = kotlinTypeStringFor(typeOf>()) - - val projectSchema = availableProjectSchemaFor( - schemaWithExtensions("generic" to genericTypeString), - classPathWith(PublicGenericType::class, PrivateComponentType::class)) - - assertThat( - projectSchema.extension("generic").type, - equalTo(inaccessible(genericTypeString, nonPublic(PrivateComponentType::class.qualifiedName!!)))) - } - - @Test - fun `parameterized public type with non existing component type is represented as Inaccessible because of NonAvailable component type`() { - - val genericTypeString = kotlinTypeStringFor(typeOf>()) - - val projectSchema = availableProjectSchemaFor( - schemaWithExtensions("generic" to genericTypeString), - classPathWith(PublicGenericType::class)) - - assertThat( - projectSchema.extension("generic").type, - equalTo(inaccessible(genericTypeString, nonAvailable(PublicComponentType::class.qualifiedName!!)))) - } - - @Test - fun `public type from jar is represented as Accessible`() { - - val genericTypeString = kotlinTypeStringFor(typeOf>()) - - val projectSchema = availableProjectSchemaFor( - schemaWithExtensions("generic" to genericTypeString), - jarClassPathWith(PublicGenericType::class, PublicComponentType::class)) - - assertThat( - projectSchema.extension("generic").type, - equalTo(accessible(genericTypeString))) - } - - private - fun schemaWithExtensions(vararg pairs: Pair) = - ProjectSchema( - extensions = pairs.map { ProjectSchemaEntry(Project::class.java.name!!, it.first, it.second) }, - conventions = emptyList(), - configurations = emptyList()) - - private - fun ProjectSchema.extension(name: String) = - extensions.single { it.name == name } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/TestWithClassPath.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/TestWithClassPath.kt (revision 5d704f53ce8ac61d04df2e6e25f2ad9f76e0803a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/TestWithClassPath.kt (revision 0) @@ -1,82 +0,0 @@ -package org.gradle.kotlin.dsl.accessors - -import org.gradle.internal.classpath.ClassPath -import org.gradle.internal.classpath.DefaultClassPath - -import org.gradle.kotlin.dsl.fixtures.TestWithTempFiles -import org.gradle.kotlin.dsl.fixtures.classEntriesFor -import org.gradle.kotlin.dsl.support.zipTo - -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.Opcodes.ACC_PUBLIC -import org.objectweb.asm.Opcodes.ACC_PRIVATE -import org.objectweb.asm.Opcodes.ALOAD -import org.objectweb.asm.Opcodes.INVOKESPECIAL -import org.objectweb.asm.Opcodes.RETURN -import org.objectweb.asm.Opcodes.V1_7 - -import java.io.File - -import kotlin.reflect.KClass - - -open class TestWithClassPath : TestWithTempFiles() { - - protected - fun jarClassPathWith(vararg classes: KClass<*>): ClassPath = - classPathOf(file("cp.jar").also { jar -> - zipTo(jar, classEntriesFor(*classes.map { it.java }.toTypedArray())) - }) - - protected - fun classPathWith(vararg classes: KClass<*>): ClassPath = - classPathOf(file("cp").also { rootDir -> - for ((path, bytes) in classEntriesFor(*classes.map { it.java }.toTypedArray())) { - File(rootDir, path).apply { - parentFile.mkdirs() - writeBytes(bytes) - } - } - }) - - protected - fun classPathWithPublicType(name: String) = - classPathWithType(name, ACC_PUBLIC) - - protected - fun classPathWithPrivateType(name: String) = - classPathWithType(name, ACC_PRIVATE) - - protected - fun classPathWithType(name: String, vararg modifiers: Int): ClassPath = - classPathOf(file("cp").also { rootDir -> - classFileForType(name, rootDir, *modifiers) - }) - - private - fun classPathOf(vararg files: File) = - DefaultClassPath.of(files.asList()) - - private - fun classFileForType(name: String, rootDir: File, vararg modifiers: Int) { - File(rootDir, "${name.replace(".", "/")}.class").apply { - parentFile.mkdirs() - writeBytes(classBytesOf(name, *modifiers)) - } - } - - private - fun classBytesOf(name: String, vararg modifiers: Int): ByteArray = - ClassWriter(0).run { - visit(V1_7, modifiers.fold(0, Int::plus), name, null, "java/lang/Object", null) - visitMethod(ACC_PUBLIC, "", "()V", null, null).apply { - visitCode() - visitVarInsn(ALOAD, 0) - visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false) - visitInsn(RETURN) - visitMaxs(1, 1) - } - visitEnd() - toByteArray() - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/TypeAccessibilityProviderTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/TypeAccessibilityProviderTest.kt (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/accessors/TypeAccessibilityProviderTest.kt (revision 0) @@ -1,70 +0,0 @@ -package org.gradle.kotlin.dsl.accessors - -import org.gradle.internal.classpath.ClassPath - -import org.gradle.kotlin.dsl.typeOf - -import org.hamcrest.CoreMatchers.* - -import org.junit.Assert.* -import org.junit.Test - - -internal -interface InternalType - - -class TypeAccessibilityProviderTest : TestWithClassPath() { - - @Test - fun `public generic type with primitive component type is accessible`() { - - val genericTypeWithPrimitiveComponent = kotlinTypeStringFor(typeOf>()) - assertThat( - accessibilityFor( - genericTypeWithPrimitiveComponent, - classPath = jarClassPathWith(PublicGenericType::class)), - equalTo(accessible(genericTypeWithPrimitiveComponent))) - } - - @Test - fun `internal Kotlin type is inaccessible because NonPublic`() { - - val internalType = kotlinTypeStringFor(typeOf()) - assertThat( - accessibilityFor( - internalType, - classPath = jarClassPathWith(InternalType::class)), - equalTo(inaccessible(internalType, InaccessibilityReason.NonPublic(internalType)))) - } - - @Test - fun `class names from type strings`() { - - classNamesFromTypeString("String").apply { - assertTrue(all.isEmpty()) - assertTrue(leafs.isEmpty()) - } - - classNamesFromTypeString("java.util.List").apply { - assertThat(all, hasItems("java.util.List")) - assertTrue(leafs.isEmpty()) - } - - classNamesFromTypeString("java.lang.String").apply { - assertThat(all, hasItems("java.lang.String")) - assertThat(leafs, hasItems("java.lang.String")) - } - - classNamesFromTypeString("java.util.Map").apply { - assertThat(all, hasItems("java.util.Map", "java.util.List", "java.util.Set")) - assertThat(leafs, hasItems("java.util.List", "java.util.Set")) - } - } - - private - fun accessibilityFor(type: String, classPath: ClassPath) = - TypeAccessibilityProvider(classPath).use { - it.accessibilityForType(type) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/codegen/UserGuideLinkTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/codegen/UserGuideLinkTest.kt (revision c0fc3cdb2b6b652d46a684fff51d9bf2e90fdd71) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/codegen/UserGuideLinkTest.kt (revision 0) @@ -1,68 +0,0 @@ -package org.gradle.kotlin.dsl.codegen - -import org.hamcrest.CoreMatchers.notNullValue -import org.hamcrest.CoreMatchers.nullValue -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class UserGuideLinkTest { - - @Test - fun `linked plugins`() { - val linkedPlugins = - listOf( - "announce", "antlr", "application", "assembler", "assembler-lang", - "base", "binary-base", "build-announcements", "build-dashboard", "build-init", - "c", "c-lang", "checkstyle", "clang-compiler", "codenarc", - "cpp", "cpp-executable", "cpp-lang", "cpp-library", - "compare-gradle-builds", "component-base", "component-model-base", - "cunit", "cunit-test-suite", - "distribution", - "ear", "eclipse", "eclipse-wtp", - "findbugs", - "gcc-compiler", "google-test", "google-test-test-suite", - "groovy", "groovy-base", - "help-tasks", - "idea", "ivy-publish", - "jacoco", "java", "java-base", "java-gradle-plugin", "java-lang", - "java-library", "java-library-distribution", "jdepend", "junit-test-suite", - "jvm-component", "jvm-resources", - "maven", "maven-publish", - "microsoft-visual-cpp-compiler", - "native-component", "native-component-model", - "objective-c", "objective-c-lang", "objective-cpp", "objective-cpp-lang", "osgi", - "play", "play-application", "play-cofeescript", "play-ide", "play-javascript", "pmd", - "project-report", "project-reports", - "reporting-base", - "scala", "scala-base", "signing", "standard-tool-chains", - "visual-studio", - "war", - "windows-resource-script", "windows-resources") - linkedPlugins.forEach { - assertThat( - "$it is linked", - UserGuideLink.forPlugin(it), - notNullValue()) - } - } - - @Test - fun `unlinked plugins`() { - val unlinkedPlugins = - listOf( - "coffeescript-base", "envjs", "javascript-base", "jshint", - "language-base", "lifecycle-base", - "publishing", - "rhino", - "scala-lang", - "wrapper") - unlinkedPlugins.forEach { - assertThat( - "$it is not linked", - UserGuideLink.forPlugin(it), - nullValue()) - } - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/DelegatedExtraPropertiesIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/DelegatedExtraPropertiesIntegrationTest.kt (revision 260110cf48a8ab8165cef834a44655c26cce141c) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/DelegatedExtraPropertiesIntegrationTest.kt (revision 0) @@ -1,42 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest - -import org.hamcrest.CoreMatchers.containsString - -import org.junit.Assert.assertThat -import org.junit.Test - - -class DelegatedExtraPropertiesIntegrationTest : AbstractIntegrationTest() { - - @Test - fun `non-nullable delegated extra property access of non-existing extra property throws`() { - - withBuildScript(""" - val myTask = task("myTask") {} - val foo: Int by myTask.extra - foo.toString() - """) - - assertThat( - buildAndFail("myTask").output, - containsString("Cannot get non-null extra property 'foo' as it does not exist")) - } - - @Test - fun `non-nullable delegated extra property access of existing null extra property throws`() { - - withBuildScript(""" - val myTask = task("myTask") { - val foo: Int? by extra { null } - } - val foo: Int by myTask.extra - foo.toString() - """) - - assertThat( - buildAndFail("myTask").output, - containsString("Cannot get non-null extra property 'foo' as it is null")) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/DelegatedGradlePropertiesIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/DelegatedGradlePropertiesIntegrationTest.kt (revision bf4209d15cfff174dbda88ed632af01e809624d7) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/DelegatedGradlePropertiesIntegrationTest.kt (revision 0) @@ -1,208 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles - -import org.hamcrest.CoreMatchers.containsString - -import org.junit.Assert.assertThat -import org.junit.Test - - -/** - * See https://docs.gradle.org/current/userguide/build_environment.html - */ -class DelegatedGradlePropertiesIntegrationTest : AbstractIntegrationTest() { - - @Test - fun `non-nullable delegated property access of non-existing gradle property throws`() { - - withSettings(""" - val nonExisting: String by settings - println(nonExisting) - """) - - assertThat( - buildAndFail("help").output, - containsString("Cannot get non-null property 'nonExisting' on settings '${projectRoot.name}' as it does not exist")) - - withSettings("") - withBuildScript(""" - val nonExisting: String by project - println(nonExisting) - """) - - assertThat( - buildAndFail("help").output, - containsString("Cannot get non-null property 'nonExisting' on root project '${projectRoot.name}' as it does not exist")) - } - - @LeaksFileHandles - @Test - fun `delegated properties follow Gradle mechanics and allow to model optional properties via nullable kotlin types`() { - - // given: build root gradle.properties file - withFile("gradle.properties", """ - setBuildProperty=build value - emptyBuildProperty= - - userHomeOverriddenBuildProperty=build value - cliOverriddenBuildProperty=build value - - projectMutatedBuildProperty=build value - """.trimIndent()) - - // and: gradle user home gradle.properties file - withFile("gradle-user-home/gradle.properties", """ - setUserHomeProperty=user home value - emptyUserHomeProperty= - - userHomeOverriddenBuildProperty=user home value - cliOverriddenUserHomeProperty=user home value - - projectMutatedUserHomeProperty=user home value - """.trimIndent()) - - // and: gradle command line with properties - val buildArguments = arrayOf( - "-g", "gradle-user-home", - "-PsetCliProperty=cli value", - "-PemptyCliProperty=", - "-PcliOverriddenBuildProperty=cli value", - "-PcliOverriddenUserHomeProperty=cli value", - "-Dorg.gradle.project.setOrgGradleProjectSystemProperty=system property value", - "-Dorg.gradle.project.emptyOrgGradleProjectSystemProperty=", - "help") - - // when: both settings and project scripts asserting on delegated properties - withSettings(requirePropertiesFromSettings()) - withBuildScript(requirePropertiesFromProject()) - - // then: - build(*buildArguments) - - // when: project script buildscript block asserting on delegated properties - withSettings("") - withBuildScript(""" - buildscript { - ${requirePropertiesFromProject()} - } - """) - - // then: - build(*buildArguments) - } - - private - fun requirePropertiesFromSettings() = - """ - ${requireNotOverriddenPropertiesFrom("settings")} - ${requireOverriddenPropertiesFrom("settings")} - ${requireEnvironmentPropertiesFrom("settings")} - ${requireProjectMutatedPropertiesOriginalValuesFrom("settings")} - """.trimIndent() - - private - fun requirePropertiesFromProject() = - """ - ${requireNotOverriddenPropertiesFrom("project")} - ${requireOverriddenPropertiesFrom("project")} - ${requireEnvironmentPropertiesFrom("project")} - ${requireProjectExtraProperties()} - ${requireProjectMutatedPropertiesOriginalValuesFrom("project")} - ${requireProjectPropertiesMutation()} - """.trimIndent() - - private - fun requireNotOverriddenPropertiesFrom(source: String) = - """ - ${requireProperty(source, "setUserHomeProperty", """"user home value"""")} - ${requireProperty(source, "emptyUserHomeProperty", """""""")} - ${requireProperty(source, "setBuildProperty", """"build value"""")} - ${requireProperty(source, "emptyBuildProperty", """""""")} - ${requireProperty(source, "setCliProperty", """"cli value"""")} - ${requireProperty(source, "emptyCliProperty", """""""")} - ${requireNullableProperty(source, "unsetProperty", "null")} - """.trimIndent() - - private - fun requireOverriddenPropertiesFrom(source: String) = - """ - ${requireProperty(source, "userHomeOverriddenBuildProperty", """"user home value"""")} - ${requireProperty(source, "cliOverriddenBuildProperty", """"cli value"""")} - ${requireProperty(source, "cliOverriddenUserHomeProperty", """"cli value"""")} - """.trimIndent() - - private - fun requireEnvironmentPropertiesFrom(source: String) = - """ - ${requireProperty(source, "setOrgGradleProjectSystemProperty", """"system property value"""")} - ${requireProperty(source, "emptyOrgGradleProjectSystemProperty", """""""")} - """.trimIndent() - - private - fun requireProjectExtraProperties() = - """ - run { - extra["setExtraProperty"] = "extra value" - extra["emptyExtraProperty"] = "" - extra["unsetExtraProperty"] = null - - val setExtraProperty: String by project - require(setExtraProperty == "extra value") - - val emptyExtraProperty: String by project - require(emptyExtraProperty == "") - - val unsetExtraProperty: String? by project - require(unsetExtraProperty == null) - - setProperty("setExtraProperty", "mutated") - require(setExtraProperty == "mutated") - } - """.trimIndent() - - private - fun requireProjectMutatedPropertiesOriginalValuesFrom(source: String) = - """ - ${requireProperty(source, "projectMutatedBuildProperty", """"build value"""")} - ${requireProperty(source, "projectMutatedUserHomeProperty", """"user home value"""")} - """.trimIndent() - - private - fun requireProjectPropertiesMutation() = - """ - run { - val projectMutatedBuildProperty: String by project - require(projectMutatedBuildProperty == "build value") - - setProperty("projectMutatedBuildProperty", "mutated") - require(projectMutatedBuildProperty == "mutated") - - val projectMutatedUserHomeProperty: String by project - require(projectMutatedUserHomeProperty == "user home value") - - setProperty("projectMutatedUserHomeProperty", "mutated") - require(projectMutatedUserHomeProperty == "mutated") - } - """.trimIndent() - - private - inline fun requireProperty(source: String, name: String, valueRepresentation: String) = - requireProperty(source, name, T::class.qualifiedName!!, valueRepresentation) - - private - inline fun requireNullableProperty(source: String, name: String, valueRepresentation: String) = - requireProperty(source, name, "${T::class.qualifiedName!!}?", valueRepresentation) - - private - fun requireProperty(source: String, name: String, type: String, valueRepresentation: String) = - """ - run { - val $name: $type by $source - require($name == $valueRepresentation) { - ${"\"".repeat(3)}expected $name to be '$valueRepresentation' but was '${'$'}$name'${"\"".repeat(3)} - } - } - """.trimIndent() -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/GradleKotlinDslIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/GradleKotlinDslIntegrationTest.kt (revision 94b38849c38403a66714497600b37101f6217d1f) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/GradleKotlinDslIntegrationTest.kt (revision 0) @@ -1,870 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import okhttp3.mockwebserver.MockResponse -import okhttp3.mockwebserver.MockWebServer - -import org.gradle.kotlin.dsl.embeddedKotlinVersion -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.gradle.kotlin.dsl.fixtures.DeepThought -import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles -import org.gradle.kotlin.dsl.fixtures.LightThought -import org.gradle.kotlin.dsl.fixtures.ZeroThought -import org.gradle.kotlin.dsl.fixtures.canPublishBuildScan -import org.gradle.kotlin.dsl.fixtures.containsMultiLineString -import org.gradle.kotlin.dsl.fixtures.rootProjectDir - -import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.MatcherAssert.assertThat - -import org.jetbrains.kotlin.preprocessor.convertLineSeparators - -import org.junit.Assert.assertNotEquals -import org.junit.Test - -import java.io.File - - -class GradleKotlinDslIntegrationTest : AbstractIntegrationTest() { - - @Test - @LeaksFileHandles - fun `given a buildscript block, it will be used to compute the runtime classpath`() { - checkBuildscriptBlockIsUsedToComputeRuntimeClasspathAfter({ it }) - } - - @Test - fun `given a buildscript block separated by CRLF, it will be used to compute the runtime classpath`() { - checkBuildscriptBlockIsUsedToComputeRuntimeClasspathAfter({ it.replace("\r\n", "\n").replace("\n", "\r\n") }) - } - - private - fun checkBuildscriptBlockIsUsedToComputeRuntimeClasspathAfter(buildscriptTransformation: (String) -> String) { - - withClassJar("fixture.jar", DeepThought::class.java) - - withBuildScript(""" - buildscript { - dependencies { classpath(files("fixture.jar")) } - } - - task("compute") { - doLast { - val computer = ${DeepThought::class.qualifiedName}() - val answer = computer.compute() - println("*" + answer + "*") - } - } - """.let(buildscriptTransformation)) - - assert( - build("compute").output.contains("*42*")) - } - - @Test - @LeaksFileHandles - fun `given a script plugin with a buildscript block, it will be used to compute its classpath`() { - - withClassJar("fixture.jar", DeepThought::class.java) - - withFile("other.gradle.kts", """ - buildscript { - dependencies { classpath(files("fixture.jar")) } - } - - task("compute") { - doLast { - val computer = ${DeepThought::class.qualifiedName}() - val answer = computer.compute() - println("*" + answer + "*") - } - } - """) - - withBuildScript(""" - apply(from = "other.gradle.kts") - """) - - assert( - build("compute").output.contains("*42*")) - } - - @Test - fun `given a buildSrc dir, it will be added to the compilation classpath`() { - - withFile("buildSrc/src/main/groovy/build/DeepThought.groovy", """ - package build - class DeepThought { - def compute() { 42 } - } - """) - - withBuildScript(""" - task("compute") { - doLast { - val computer = build.DeepThought() - val answer = computer.compute() - println("*" + answer + "*") - } - } - """) - - assert( - build("compute").output.contains("*42*")) - } - - @Test - fun `given a Kotlin project in buildSrc, it will be added to the compilation classpath`() { - - withKotlinBuildSrc() - - withFile("buildSrc/src/main/kotlin/build/DeepThought.kt", """ - package build - - class DeepThought() { - fun compute(handler: (Int) -> Unit) { handler(42) } - } - """) - - withFile("buildSrc/src/main/kotlin/build/DeepThoughtPlugin.kt", """ - package build - - import org.gradle.api.* - import org.gradle.kotlin.dsl.* - - open class DeepThoughtPlugin : Plugin { - override fun apply(project: Project) { - project.run { - task("compute") { - doLast { - DeepThought().compute { answer -> - println("*" + answer + "*") - } - } - } - } - } - } - """) - - withBuildScript(""" - buildscript { - // buildSrc types are available within buildscript - // and must always be fully qualified - build.DeepThought().compute { answer -> - println("buildscript: " + answer) - } - } - apply() - """) - - val output = build("compute").output - assert(output.contains("buildscript: 42")) - assert(output.contains("*42*")) - } - - @Test - fun `given a plugin compiled against Kotlin one dot zero, it will run against the embedded Kotlin version`() { - - assumeJavaLessThan9() - - withBuildScript(""" - buildscript { - repositories { - ivy(url = "${fixturesRepository.toURI()}") - jcenter() - } - dependencies { - classpath("org.gradle.kotlin.dsl.fixtures:plugin-compiled-against-kotlin-1.0:1.0") - } - } - - apply() - - tasks.withType { - from = "new value" - doLast { - println(transform { "*[" + it + "]*" }) - } - } - """) - - assert( - build("the-plugin-task").output.contains("*[new value]*")) - } - - @Test - fun `can compile against a different (but compatible) version of the Kotlin compiler`() { - - val differentKotlinVersion = "1.0.7" - val expectedKotlinCompilerVersionString = "1.0.7-release-1" - - assertNotEquals(embeddedKotlinVersion, differentKotlinVersion) - - withBuildScript(""" - import org.jetbrains.kotlin.config.KotlinCompilerVersion - import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - - buildscript { - repositories { - jcenter() - } - dependencies { - classpath(kotlin("gradle-plugin", version = "$differentKotlinVersion")) - } - } - - apply(plugin = "kotlin") - - tasks.withType { - // can configure the Kotlin compiler - kotlinOptions.suppressWarnings = true - } - - task("print-kotlin-version") { - doLast { - val compileOptions = tasks.filterIsInstance().joinToString(prefix="[", postfix="]") { - it.name + "=" + it.kotlinOptions.suppressWarnings - } - println(KotlinCompilerVersion.VERSION + compileOptions) - } - } - """) - - assertThat( - build("print-kotlin-version").output, - containsString(expectedKotlinCompilerVersionString + "[compileKotlin=true, compileTestKotlin=true]")) - } - - @Test - fun `can apply base plugin via plugins block`() { - - withBuildScript(""" - plugins { - id("base") - } - - task("plugins") { - doLast { - println(plugins.map { "*" + it::class.simpleName + "*" }) - } - } - """) - - assertThat( - build("plugins").output, - containsString("*BasePlugin*")) - } - - @Test - fun `can apply plugin portal plugin via plugins block`() { - - withBuildScript(""" - plugins { - id("org.gradle.hello-world") version "0.2" - } - - task("plugins") { - doLast { - println(plugins.map { "*" + it.javaClass.simpleName + "*" }) - } - } - """) - - assertThat( - build("plugins").output, - containsString("*HelloWorldPlugin*")) - } - - @Test - fun `can use Closure only APIs`() { - - withBuildScript(""" - gradle.buildFinished(closureOf { - println("*" + action + "*") // <- BuildResult.getAction() - }) - """) - - assert( - build("build").output.contains("*Build*")) - } - - @Test - fun `given an exception thrown during buildscript block execution, its stack trace should contain correct file and line info`() { - - withBuildScript(""" // line 1 - // line 2 - // line 3 - buildscript { // line 4 - throw IllegalStateException() // line 5 - } - """) - - assertThat( - buildFailureOutput(), - containsString("build.gradle.kts:5")) - } - - @Test - fun `given a script with more than one buildscript block, it throws exception with offending block line number`() { - - withBuildScript(""" // line 1 - buildscript {} // line 2 - buildscript {} // line 3 - """) - - assertThat( - buildFailureOutput(), - containsString("build.gradle.kts:3:13: Unexpected `buildscript` block found. Only one `buildscript` block is allowed per script.")) - } - - @Test - fun `given a script with more than one plugins block, it throws exception with offending block line number`() { - - withBuildScript(""" // line 1 - plugins {} // line 2 - plugins {} // line 3 - """) - - assertThat( - buildFailureOutput(), - containsString("build.gradle.kts:3:13: Unexpected `plugins` block found. Only one `plugins` block is allowed per script.")) - } - - @Test - fun `given a buildscript block compilation error, it reports correct error location`() { - - assertCorrectLocationIsReportedForErrorIn("buildscript") - } - - @Test - fun `given a plugins block compilation error, it reports correct error location`() { - - assertCorrectLocationIsReportedForErrorIn("plugins") - } - - private - fun assertCorrectLocationIsReportedForErrorIn(block: String) { - val buildFile = - withBuildScript(""" - $block { - val module = "foo:bar:${'$'}fooBarVersion" - } - """) - - assertThat( - buildFailureOutput("tasks"), - containsString("e: $buildFile:3:44: Unresolved reference: fooBarVersion")) - } - - @Test - fun `sub-project build script inherits parent project compilation classpath`() { - - withClassJar("fixture.jar", DeepThought::class.java) - - withBuildScript(""" - buildscript { - dependencies { classpath(files("fixture.jar")) } - } - """) - - withSettings("include(\"sub-project\")") - - withBuildScriptIn("sub-project", """ - task("compute") { - doLast { - val computer = ${DeepThought::class.qualifiedName}() - val answer = computer.compute() - println("*" + answer + "*") - } - } - """) - - assert( - build(":sub-project:compute").output.contains("*42*")) - } - - @Test - fun `given non-existing build script file name set in settings do not fail`() { - - withSettings("rootProject.buildFileName = \"does-not-exist.gradle.kts\"") - - build("help") - } - - @Test - fun `build with groovy settings and kotlin-dsl build script succeeds`() { - - withFile("settings.gradle", """ - println 'Groovy DSL Settings' - """) - - withBuildScript(""" - println("Kotlin DSL Build Script") - """) - - assertThat( - build("help").output, - allOf( - containsString("Groovy DSL Settings"), - containsString("Kotlin DSL Build Script"))) - } - - @Test - fun `build script can use jdk8 extensions`() { - - assumeJavaLessThan9() - - withBuildScript(""" - - // without kotlin-stdlib-jdk8 we get: - // > Retrieving groups by name is not supported on this platform. - - val regex = Regex("(?.*)") - val groups = regex.matchEntire("abc")?.groups - println("*" + groups?.get("bla")?.value + "*") - - """) - - assertThat( - build("help").output, - containsString("*abc*")) - } - - @Test - fun `settings script can use buildscript dependencies`() { - - withSettings(""" - buildscript { - repositories { jcenter() } - dependencies { - classpath("org.apache.commons:commons-lang3:3.6") - } - } - - println(org.apache.commons.lang3.StringUtils.reverse("Gradle")) - """) - - assertThat( - build("help").output, - containsString("eldarG")) - } - - @Test - fun `script plugin can by applied to either Project or Settings`() { - - withFile("common.gradle.kts", """ - println("Target is Settings? ${"$"}{Settings::class.java.isAssignableFrom(this::class.java)}") - println("Target is Project? ${"$"}{Project::class.java.isAssignableFrom(this::class.java)}") - """) - - withSettings(""" - apply(from = "common.gradle.kts") - """) - - assertThat( - build("help").output, - allOf( - containsString("Target is Settings? true"), - containsString("Target is Project? false"))) - - withSettings("") - withBuildScript(""" - apply(from = "common.gradle.kts") - """) - - assertThat( - build("help").output, - allOf( - containsString("Target is Settings? false"), - containsString("Target is Project? true"))) - } - - @Test - fun `can apply buildSrc plugin to Settings`() { - - withBuildSrc() - - withFile("buildSrc/src/main/groovy/my/SettingsPlugin.groovy", """ - package my - - import org.gradle.api.* - import org.gradle.api.initialization.Settings - - class SettingsPlugin implements Plugin { - void apply(Settings settings) { - println("Settings plugin applied!") - } - } - """) - - withSettings(""" - apply() - """) - - assertThat( - build("help").output, - containsString("Settings plugin applied!")) - } - - @Test - fun `scripts can use the gradle script api`() { - - fun usageFor(target: String) = """ - - logger.error("Error logging from $target") - require(logging is LoggingManager, { "logging" }) - require(resources is ResourceHandler, { "resources" }) - - require(relativePath("src/../settings.gradle.kts") == "settings.gradle.kts", { "relativePath(path)" }) - require(uri("settings.gradle.kts").toString().endsWith("settings.gradle.kts"), { "uri(path)" }) - require(file("settings.gradle.kts").isFile, { "file(path)" }) - require(files("settings.gradle.kts").files.isNotEmpty(), { "files(paths)" }) - require(fileTree(".").contains(file("settings.gradle.kts")), { "fileTree(path)" }) - require(copySpec {} != null, { "copySpec {}" }) - require(mkdir("some").isDirectory, { "mkdir(path)" }) - require(delete("some"), { "delete(path)" }) - require(delete {} != null, { "delete {}" }) - - """ - - withSettings(usageFor("Settings")) - withBuildScript(usageFor("Project")) - - assertThat( - build("help").output, - allOf( - containsString("Error logging from Settings"), - containsString("Error logging from Project"))) - } - - @Test - fun `automatically applies build scan plugin when --scan is provided on command-line and a script is applied in the buildscript block`() { - - withBuildScript(""" - buildscript { - rootProject.apply(from = rootProject.file("gradle/dependencies.gradle.kts")) - } - buildScan { - setLicenseAgreementUrl("https://gradle.com/terms-of-service") - setLicenseAgree("yes") - } - """) - withFile("gradle/dependencies.gradle.kts") - canPublishBuildScan() - } - - @Test - fun `can use shorthand notation for bound callable references with inline functions in build scripts`() { - - withBuildScript(""" - fun foo(it: Any) = true - - // The inline modifier is important. This does not fail when this is no inline function. - inline fun bar(f: (Any) -> Boolean) = print("*" + f(Unit) + "*") - - bar(::foo) - """) - - assertThat( - build().output, - containsString("*true*")) - } - - @Test - fun `script compilation error message`() { - - val buildFile = - withBuildScript("foo") - - assertThat( - buildFailureOutput().convertLineSeparators(), - containsString(""" - FAILURE: Build failed with an exception. - - * Where: - Build file '${buildFile.canonicalPath}' line: 1 - - * What went wrong: - Script compilation error: - - Line 1: foo - ^ Unresolved reference: foo - - 1 error - """.replaceIndent()) - ) - } - - @Test - fun `multiline script compilation error message`() { - - withBuildScript("publishing { }") - - assertThat( - buildFailureOutput().convertLineSeparators(), - containsString(""" - * What went wrong: - Script compilation errors: - - Line 1: publishing { } - ^ Expression 'publishing' cannot be invoked as a function. The function 'invoke()' is not found - - Line 1: publishing { } - ^ Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:${' '} - public val PluginDependenciesSpec.publishing: PluginDependencySpec defined in org.gradle.kotlin.dsl - - 2 errors - """.replaceIndent())) - } - - @Test - fun `multiple script compilation errors message`() { - val buildFile = withBuildScript("println(foo)\n\n\n\n\nprintln(\"foo\").bar.bazar\n\n\n\nprintln(cathedral)") - - assertThat( - buildFailureOutput().convertLineSeparators(), - containsString(""" - FAILURE: Build failed with an exception. - - * Where: - Build file '${buildFile.canonicalPath}' line: 1 - - * What went wrong: - Script compilation errors: - - Line 01: println(foo) - ^ Unresolved reference: foo - - Line 06: println("foo").bar.bazar - ^ Unresolved reference: bar - - Line 10: println(cathedral) - ^ Unresolved reference: cathedral - - 3 errors - """.replaceIndent())) - } - - @Test - fun `given a remote buildscript, file paths are resolved relative to root project dir`() { - - val remoteScript = """ - - apply(from = "./gradle/answer.gradle.kts") - - """ - - withFile("gradle/answer.gradle.kts", """ - - val answer by extra { "42" } - - """) - - MockWebServer().use { server -> - - server.enqueue(MockResponse().setBody(remoteScript)) - server.start() - - val remoteScriptUrl = server.url("/remote.gradle.kts") - - withBuildScript(""" - apply(from = "$remoteScriptUrl") - val answer: String by extra - println("*" + answer + "*") - """) - - assert(build().output.contains("*42*")) - } - } - - @Test - fun `given a script from a jar, file paths are resolved relative to root project dir`() { - - val scriptFromJar = """ - - apply(from = "./gradle/answer.gradle.kts") - - """ - - withZip( - "fixture.jar", - sequenceOf("common.gradle.kts" to scriptFromJar.toByteArray())) - - withFile("gradle/answer.gradle.kts", """ - - val answer by extra { "42" } - - """) - - withBuildScript(""" - buildscript { - dependencies { classpath(files("fixture.jar")) } - } - - apply(from = project.buildscript.classLoader.getResource("common.gradle.kts").toURI()) - - val answer: String by extra - println("*" + answer + "*") - """) - - assert(build().output.contains("*42*")) - } - - @Test - fun `script handler belongs to the current script`() { - - val init = withFile("some.init.gradle.kts", """ - println("init: ${'$'}{initscript.sourceFile}") - """) - - val settings = withSettings(""" - println("settings: ${'$'}{buildscript.sourceFile}") - """) - - val other = withFile("other.gradle.kts", """ - println("other: ${'$'}{buildscript.sourceFile}") - """) - - val main = withBuildScript(""" - apply(from = "other.gradle.kts") - println("main: ${'$'}{buildscript.sourceFile}") - """) - - assertThat( - build("-I", init.absolutePath, "help", "-q").output, - containsMultiLineString(""" - init: ${init.absolutePath} - settings: ${settings.absolutePath} - other: ${other.absolutePath} - main: ${main.absolutePath} - """)) - } - - @Test - @LeaksFileHandles - fun `can cross configure buildscript`() { - - withClassJar("zero.jar", ZeroThought::class.java) - withClassJar("light.jar", LightThought::class.java) - withClassJar("deep.jar", DeepThought::class.java) - - val init = withFile("some.init.gradle.kts", """ - projectsLoaded { - rootProject.buildscript { - dependencies { - classpath(files("zero.jar")) - } - } - } - """) - - withSettings(""" - include("sub") - gradle.projectsLoaded { - rootProject.buildscript { - dependencies { - classpath(files("light.jar")) - } - } - } - """) - - withBuildScript(""" - project(":sub") { - buildscript { - dependencies { - classpath(files("../deep.jar")) - } - } - } - """) - - withFile("sub/build.gradle.kts", """ - task("think") { - doLast { - val zero = ${ZeroThought::class.qualifiedName}() - val light = ${LightThought::class.qualifiedName}() - val deep = ${DeepThought::class.qualifiedName}() - println("*" + zero.compute() + "*") - println("*" + light.compute() + "*") - println("*" + deep.compute() + "*") - } - } - """) - - assertThat( - build("-I", init.absolutePath, ":sub:think").output, - containsMultiLineString(""" - *0* - *23* - *42* - """)) - } - - @Test - fun `given generic extension types they can be accessed and configured`() { - - withFile("buildSrc/build.gradle.kts", """ - plugins { - `kotlin-dsl` - `java-gradle-plugin` - } - - gradlePlugin { - (plugins) { - "my" { - id = "my" - implementationClass = "my.MyPlugin" - } - } - } - """) - - withFile("buildSrc/src/main/kotlin/my/MyPlugin.kt", """ - package my - - import org.gradle.api.* - import org.gradle.kotlin.dsl.* - - class Book(val name: String) - - open class MyPlugin : Plugin { - override fun apply(project: Project): Unit = project.run { - extensions.add(typeOf>(), "mapOfString", mutableMapOf("foo" to "bar")) - extensions.add(typeOf>(), "mapOfInt", mutableMapOf("deep" to 42)) - extensions.add(typeOf>(), "books", container(Book::class.java)) - } - } - """) - - withBuildScript(""" - plugins { - id("my") - } - - configure> { - put("bazar", "cathedral") - } - require(the>() == mapOf("foo" to "bar", "bazar" to "cathedral")) - - configure> { - put("zero", 0) - } - require(the>() == mapOf("deep" to 42, "zero" to 0)) - - require(the>() == mapOf("foo" to "bar", "bazar" to "cathedral")) - - configure> { - create("The Dosadi experiment") - } - require(the>().size == 1) - """) - - build("help") - } - - private - val fixturesRepository: File - get() = File(rootProjectDir, "fixtures/repository").absoluteFile -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinBuildScriptModelIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinBuildScriptModelIntegrationTest.kt (revision 7119b76408e0dc8545d7ee25c03359ba2fa607af) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinBuildScriptModelIntegrationTest.kt (revision 0) @@ -1,271 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.embeddedKotlinVersion -import org.gradle.kotlin.dsl.fixtures.DeepThought - -import org.gradle.util.TextUtil.normaliseFileSeparators - -import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.hasItem -import org.hamcrest.CoreMatchers.hasItems -import org.hamcrest.CoreMatchers.not - -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - -import java.io.File - - -class KotlinBuildScriptModelIntegrationTest : ScriptModelIntegrationTest() { - - @Test - fun `can fetch buildSrc classpath in face of compilation errors`() { - - withBuildSrc() - - withBuildScript(""" - val p = - """) - - assertContainsBuildSrc(canonicalClassPath()) - } - - @Test - fun `can fetch buildscript classpath in face of compilation errors`() { - - withFile("classes.jar") - - withBuildScript(""" - buildscript { - dependencies { - classpath(files("classes.jar")) - } - } - - val p = - """) - - assertClassPathContains( - existing("classes.jar")) - } - - @Test - fun `can fetch buildscript classpath of top level Groovy script`() { - - withBuildSrc() - - withFile("classes.jar", "") - - withFile("build.gradle", """ - buildscript { - dependencies { - classpath(files("classes.jar")) - } - } - """) - - val classPath = canonicalClassPath() - assertThat( - classPath.map { it.name }, - hasItem("classes.jar")) - - assertContainsBuildSrc(classPath) - - assertContainsGradleKotlinDslJars(classPath) - } - - @Test - fun `can fetch buildscript classpath for sub-project script`() { - - withSettings("include(\"foo\", \"bar\")") - - fun withFixture(fixture: String) = - withClassJar("libs/$fixture.jar", DeepThought::class.java) - - val parentJar = withFixture("parent") - val fooJar = withFixture("foo") - val barJar = withFixture("bar") - - fun String.withBuildscriptDependencyOn(fixture: File) = - withFile(this, """ - buildscript { - dependencies { classpath(files("${normaliseFileSeparators(fixture.path)}")) } - } - """) - - val parentBuildScript = "build.gradle".withBuildscriptDependencyOn(parentJar) - val fooBuildScript = "foo/build.gradle.kts".withBuildscriptDependencyOn(fooJar) - val barBuildScript = "bar/build.gradle.kts".withBuildscriptDependencyOn(barJar) - - assertClassPathFor( - parentBuildScript, - includes = setOf(parentJar), - excludes = setOf(fooJar, barJar)) - - assertClassPathFor( - fooBuildScript, - includes = setOf(parentJar, fooJar), - excludes = setOf(barJar)) - - assertClassPathFor( - barBuildScript, - includes = setOf(parentJar, barJar), - excludes = setOf(fooJar)) - } - - @Test - fun `can fetch classpath of script plugin`() { - - withBuildSrc() - - val buildSrcDependency = - withFile("buildSrc-dependency.jar") - - withFile("buildSrc/build.gradle", """ - dependencies { compile(files("../${buildSrcDependency.name}")) } - """) - - val rootProjectDependency = withFile("rootProject-dependency.jar") - - withFile("build.gradle", """ - buildscript { - dependencies { classpath(files("${rootProjectDependency.name}")) } - } - """) - - val scriptPlugin = withFile("plugin.gradle.kts") - - val scriptPluginClassPath = canonicalClassPathFor(projectRoot, scriptPlugin) - assertThat( - scriptPluginClassPath.map { it.name }, - allOf( - not(hasItem(rootProjectDependency.name)), - hasItem(buildSrcDependency.name))) - assertContainsBuildSrc(scriptPluginClassPath) - assertContainsGradleKotlinDslJars(scriptPluginClassPath) - } - - @Test - fun `can fetch classpath of script plugin with buildscript block`() { - - val scriptPluginDependency = - withFile("script-plugin-dependency.jar") - - val scriptPlugin = withFile("plugin.gradle.kts", """ - buildscript { - dependencies { classpath(files("${scriptPluginDependency.name}")) } - } - - // Shouldn't be evaluated - throw IllegalStateException() - """) - - val model = kotlinBuildScriptModelFor(projectRoot, scriptPlugin) - assertThat( - "Script body shouldn't be evaluated", - model.exceptions, - equalTo(emptyList())) - - val scriptPluginClassPath = model.canonicalClassPath - assertThat( - scriptPluginClassPath.map { it.name }, - hasItem(scriptPluginDependency.name)) - - assertContainsGradleKotlinDslJars(scriptPluginClassPath) - } - - @Test - fun `can fetch classpath of plugin portal plugin in plugins block`() { - withBuildScript(""" - plugins { - id("org.gradle.hello-world") version "0.2" - } - """) - - assertThat( - canonicalClassPath().map { it.name }, - hasItems("gradle-hello-world-plugin-0.2.jar")) - } - - @Test - fun `sourcePath includes Gradle sources`() { - - assertSourcePathIncludesGradleSourcesGiven( - rootProjectScript = "", - subProjectScript = "") - } - - @Test - fun `sourcePath includes kotlin-stdlib sources resolved against project`() { - - assertSourcePathIncludesKotlinStdlibSourcesGiven( - rootProjectScript = "", - subProjectScript = "buildscript { repositories { jcenter() } }") - } - - @Test - fun `sourcePath includes kotlin-stdlib sources resolved against project hierarchy`() { - - assertSourcePathIncludesKotlinStdlibSourcesGiven( - rootProjectScript = "buildscript { repositories { jcenter() } }", - subProjectScript = "") - } - - @Test - fun `sourcePath includes buildscript classpath sources resolved against project`() { - - assertSourcePathIncludesKotlinPluginSourcesGiven( - rootProjectScript = "", - subProjectScript = """ - buildscript { - dependencies { classpath(embeddedKotlin("gradle-plugin")) } - repositories { jcenter() } - } - """) - } - - @Test - fun `sourcePath includes buildscript classpath sources resolved against project hierarchy`() { - - assertSourcePathIncludesKotlinPluginSourcesGiven( - rootProjectScript = """ - buildscript { - dependencies { classpath(embeddedKotlin("gradle-plugin")) } - repositories { jcenter() } - } - """, - subProjectScript = "") - } - - @Test - fun `sourcePath includes plugins classpath sources resolved against project`() { - - assertSourcePathIncludesKotlinPluginSourcesGiven( - rootProjectScript = "", - subProjectScript = """ plugins { kotlin("jvm") version "$embeddedKotlinVersion" } """) - } - - @Test - fun `sourcePath includes buildSrc source roots`() { - - withKotlinBuildSrc() - withSettings("""include(":sub")""") - - assertThat( - sourcePathFor(withFile("sub/build.gradle.kts")), - matchesProjectsSourceRoots(withMainSourceSetJavaKotlinIn("buildSrc"))) - } - - @Test - fun `sourcePath includes buildSrc project dependencies source roots`() { - - val sourceRoots = withMultiProjectKotlinBuildSrc() - withSettings("""include(":sub")""") - - assertThat( - sourcePathFor(withFile("sub/build.gradle.kts")), - matchesProjectsSourceRoots(*sourceRoots)) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinInitScriptIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinInitScriptIntegrationTest.kt (revision f8dcfc9672dca18becab52e606c5ffeb6886b98b) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinInitScriptIntegrationTest.kt (revision 0) @@ -1,100 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.gradle.kotlin.dsl.fixtures.DeepThought -import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles -import org.gradle.kotlin.dsl.fixtures.withFolders -import org.gradle.kotlin.dsl.fixtures.withIsolatedTestKitDir - -import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class KotlinInitScriptIntegrationTest : AbstractIntegrationTest() { - - @Test - @LeaksFileHandles - fun `initscript classpath`() { - - withClassJar("fixture.jar", DeepThought::class.java) - - val initScript = - withFile("init.gradle.kts", """ - - initscript { - dependencies { classpath(files("fixture.jar")) } - } - - val computer = ${DeepThought::class.qualifiedName}() - val answer = computer.compute() - println("*" + answer + "*") - """) - - assert( - build("-I", initScript.canonicalPath) - .output.contains("*42*")) - } - - @Test - fun `initscript file path is resolved relative to parent script dir`() { - - val initScript = - withFile("gradle/init.gradle.kts", """ - apply(from = "./answer.gradle.kts") - """) - - withFile("gradle/answer.gradle.kts", """ - rootProject { - val answer by extra { "42" } - } - """) - - withBuildScript(""" - val answer: String by extra - println("*" + answer + "*") - """) - - assert( - build("-I", initScript.canonicalPath) - .output.contains("*42*")) - } - - @Test - @LeaksFileHandles - fun `Kotlin init scripts from init dir can add buildscript repositories to projects`() { - - val testRepositoryDir = temporaryFolder.newFolder("test-repository") - - val isolatedTestKitDir = temporaryFolder.newFolder("test-kit") - isolatedTestKitDir.withFolders { - "init.d" { - withFile("init.gradle.kts", """ - allprojects { - buildscript.repositories { - maven { - name = "test-repository" - url = uri("${testRepositoryDir.toURI()}") - } - } - } - """) - } - } - - withBuildScript(""" - buildscript { - repositories.forEach { - println("*" + it.name + "*") - } - } - """) - - withIsolatedTestKitDir(isolatedTestKitDir) { - assertThat( - build().output, - containsString("*test-repository*")) - } - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinInitScriptModelIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinInitScriptModelIntegrationTest.kt (revision d9be5d1d592f7d2d22d333f33f0427d7c3e5bcd4) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinInitScriptModelIntegrationTest.kt (revision 0) @@ -1,54 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.hamcrest.CoreMatchers.hasItem -import org.hamcrest.CoreMatchers.not -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - -import java.io.File - - -class KotlinInitScriptModelIntegrationTest : ScriptModelIntegrationTest() { - - @Test - fun `initscript classpath does not include buildSrc`() { - - withBuildSrc() - - val initScript = withFile("my.init.gradle.kts") - val classPath = canonicalClassPathFor(initScript) - - assertContainsGradleKotlinDslJars(classPath) - assertThat( - classPath.map { it.name }, - not(hasItem("buildSrc.jar"))) - } - - @Test - fun `can fetch initscript classpath in face of compilation errors`() { - - withFile("classes.jar") - - val initScript = - withFile("my.init.gradle.kts", """ - initscript { - dependencies { - classpath(files("classes.jar")) - } - } - - val p = - """) - - val classPath = canonicalClassPathFor(initScript) - - assertContainsGradleKotlinDslJars(classPath) - assertClassPathContains( - classPath, - existing("classes.jar")) - } - - private - fun canonicalClassPathFor(initScript: File) = canonicalClassPathFor(projectRoot, initScript) -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinSettingsScriptIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinSettingsScriptIntegrationTest.kt (revision e8616ae97e38fa4a2b2559e328c515af282e533f) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinSettingsScriptIntegrationTest.kt (revision 0) @@ -1,84 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.gradle.kotlin.dsl.fixtures.DeepThought -import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles - -import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class KotlinSettingsScriptIntegrationTest : AbstractIntegrationTest() { - - @Test - fun `Settings script path is resolved relative to parent script dir`() { - - withFile("gradle/my.settings.gradle.kts", """ - apply(from = "./answer.settings.gradle.kts") - """) - - withFile("gradle/answer.settings.gradle.kts", """ - gradle.rootProject { - val answer by extra { "42" } - } - """) - - withSettings(""" - apply(from = "gradle/my.settings.gradle.kts") - """) - - withBuildScript(""" - val answer: String by extra - println("*" + answer + "*") - """) - - assertThat( - build().output, - containsString("*42*")) - } - - @Test - fun `pluginManagement block cannot appear twice in settings scripts`() { - - withSettings(""" - pluginManagement {} - pluginManagement {} - """) - - assertThat( - buildAndFail("help").output, - containsString("settings.gradle.kts:3:13: Unexpected `pluginManagement` block found. Only one `pluginManagement` block is allowed per script.")) - } - - @Test - @LeaksFileHandles - fun `given a script plugin with a buildscript block, it will be used to compute its classpath`() { - - withClassJar("fixture.jar", DeepThought::class.java) - - withFile("other.settings.gradle.kts", """ - buildscript { - dependencies { classpath(files("fixture.jar")) } - } - - gradle.rootProject { - task("compute") { - doLast { - val computer = ${DeepThought::class.qualifiedName}() - val answer = computer.compute() - println("*" + answer + "*") - } - } - } - """) - - withSettings(""" - apply(from = "other.settings.gradle.kts") - """) - - assert( - build("compute").output.contains("*42*")) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinSettingsScriptModelIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinSettingsScriptModelIntegrationTest.kt (revision 7a1b9c27df828508cbc12f52359c6a1e19416430) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlinSettingsScriptModelIntegrationTest.kt (revision 0) @@ -1,94 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.util.TextUtil -import org.junit.Assert.assertThat - -import org.junit.Test - - -class KotlinSettingsScriptModelIntegrationTest : ScriptModelIntegrationTest() { - - @Test - fun `can fetch classpath of settings script`() { - - withBuildSrc() - - val settingsDependency = withFile("settings-dependency.jar", "") - val settings = withSettings(""" - buildscript { - dependencies { - classpath(files("${TextUtil.normaliseFileSeparators(settingsDependency.path)}")) - } - } - """) - - val projectDependency = withFile("project-dependency.jar", "") - withFile("build.gradle", """ - buildscript { - dependencies { - classpath(files("${TextUtil.normaliseFileSeparators(projectDependency.path)}")) - } - } - """) - - val classPath = canonicalClassPathFor(projectRoot, settings) - - assertContainsBuildSrc(classPath) - assertContainsGradleKotlinDslJars(classPath) - assertIncludes(classPath, settingsDependency) - assertExcludes(classPath, projectDependency) - } - - @Test - fun `can fetch classpath of settings script plugin`() { - - withBuildSrc() - - val settingsDependency = withFile("settings-dependency.jar", "") - val settings = withFile("my.settings.gradle.kts", """ - buildscript { - dependencies { - classpath(files("${TextUtil.normaliseFileSeparators(settingsDependency.path)}")) - } - } - """) - - val projectDependency = withFile("project-dependency.jar", "") - withFile("build.gradle", """ - buildscript { - dependencies { - classpath(files("${TextUtil.normaliseFileSeparators(projectDependency.path)}")) - } - } - """) - - val classPath = canonicalClassPathFor(projectRoot, settings) - - assertContainsBuildSrc(classPath) - assertContainsGradleKotlinDslJars(classPath) - assertIncludes(classPath, settingsDependency) - assertExcludes(classPath, projectDependency) - } - - @Test - fun `sourcePath includes buildSrc source roots`() { - - withKotlinBuildSrc() - val settings = withSettings("""include(":sub")""") - - assertThat( - sourcePathFor(settings), - matchesProjectsSourceRoots(withMainSourceSetJavaKotlinIn("buildSrc"))) - } - - @Test - fun `sourcePath includes buildSrc project dependencies source roots`() { - - val sourceRoots = withMultiProjectKotlinBuildSrc() - val settings = withSettings("""include(":sub")""") - - assertThat( - sourcePathFor(settings), - matchesProjectsSourceRoots(*sourceRoots)) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlintBuildScriptIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlintBuildScriptIntegrationTest.kt (revision a851d4604b09c0370a477494ff9a1b10dfc189d3) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/KotlintBuildScriptIntegrationTest.kt (revision 0) @@ -1,52 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest - -import org.hamcrest.CoreMatchers.containsString - -import org.junit.Assert.assertThat -import org.junit.Test - - -class KotlintBuildScriptIntegrationTest : AbstractIntegrationTest() { - - @Test - fun `use of the plugins block on nested project block fails with reasonable error message`() { - - withBuildScript(""" - plugins { - id("base") - } - - allprojects { - plugins { - id("java-base") - } - } - """) - - buildAndFail("help").apply { - assertThat(output, containsString("The plugins {} block must not be used here")) - } - } - - @Test - fun `non top-level use of the plugins block fails with reasonable error message`() { - - withBuildScript(""" - plugins { - id("java-base") - } - - dependencies { - plugins { - id("java") - } - } - """) - - buildAndFail("help").apply { - assertThat(output, containsString("The plugins {} block must not be used here")) - } - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/LocationAwareScriptEvaluationIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/LocationAwareScriptEvaluationIntegrationTest.kt (revision 82831c5115ac3f3fb1525b13fc2af7d5b608e888) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/LocationAwareScriptEvaluationIntegrationTest.kt (revision 0) @@ -1,172 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.gradle.kotlin.dsl.fixtures.containsMultiLineString - -import org.junit.Assert.assertThat -import org.junit.Test - - -class LocationAwareScriptEvaluationIntegrationTest : AbstractIntegrationTest() { - - private - val boom = """throw InternalError("BOOM!")""" - - @Test - fun `location of exception thrown from build script is reported`() { - - withSettings("""include("a")""") - val script = withBuildScriptIn("a", boom) - - assertFailingBuildOutputOf("help") { - """ - * Where: - Build file '${script.canonicalPath}' line: 1 - """ - } - } - - @Test - fun `location of exception thrown from applied script is reported`() { - - withBuildScript("""apply(from = "other.gradle.kts")""") - val script = withFile("other.gradle.kts", boom) - - assertFailingBuildOutputOf("help") { - """ - * Where: - Script '${script.canonicalPath}' line: 1 - """ - } - } - - @Test - fun `location of exception thrown from applied script with same filename is reported`() { - - withBuildScript("""apply(from = "other/build.gradle.kts")""") - val script = withFile("other/build.gradle.kts", boom) - - assertFailingBuildOutputOf("help") { - """ - * Where: - Script '${script.canonicalPath}' line: 1 - """ - } - } - - @Test - fun `location of exception thrown from buildscript block is reported`() { - - val script = withBuildScript("buildscript { $boom }") - - assertFailingBuildOutputOf("help") { - """ - * Where: - Build file '${script.canonicalPath}' line: 1 - """ - } - } - - @Test - fun `location of exception thrown from plugins block is reported`() { - - val script = withBuildScript("plugins { $boom }") - - assertFailingBuildOutputOf("help") { - """ - * Where: - Build file '${script.canonicalPath}' line: 1 - """ - } - } - - @Test - fun `location of exception thrown from settings script is reported`() { - - val script = withSettings(boom) - - assertFailingBuildOutputOf("help") { - """ - * Where: - Settings file '${script.canonicalPath}' line: 1 - """ - } - } - - @Test - fun `location of exception thrown from initialization script is reported`() { - - val script = withFile("my.init.gradle.kts", boom) - - assertFailingBuildOutputOf("help", "-I", script.absolutePath) { - """ - * Where: - Initialization script '${script.canonicalPath}' line: 1 - """ - } - } - - @Test - fun `location of missing script application is reported`() { - - withBuildScript("""apply(from = "present.gradle.kts")""") - val present = withFile("present.gradle.kts", """apply(from = "absent.gradle.kts")""") - - assertFailingBuildOutputOf("help") { - """ - * Where: - Script '${present.canonicalPath}' line: 1 - - * What went wrong: - Could not read script '${existing("absent.gradle.kts").canonicalPath}' as it does not exist. - """ - } - } - - @Test - fun `location of exception thrown by kotlin script applied from groovy script is reported`() { - - withFile("build.gradle", "apply from: 'other.gradle.kts'") - val script = withFile("other.gradle.kts", """ - println("In Kotlin Script") - $boom - """) - - assertFailingBuildOutputOf("help") { - """ - * Where: - Script '${script.canonicalPath}' line: 3 - """ - } - } - - /** - * This is a caveat. - * The Groovy DSL provider relies on exceptions being analyzed up the stack. - * See [org.gradle.initialization.DefaultExceptionAnalyser.transform], note the comments. - * The Kotlin DSL provider handles this in isolation, - * thus hiding the location of exceptions thrown by groovy scripts applied from kotlin scripts. - * - * This test exercises the current behavior. - */ - @Test - fun `location of exception thrown by groovy script applied from kotlin script shadowed by the kotlin location`() { - - val kotlinScript = withBuildScript("""apply(from = "other.gradle")""") - withFile("other.gradle", """ - println("In Groovy Script") - throw new InternalError("BOOM!") - """) - - assertFailingBuildOutputOf("help") { - """ - * Where: - Build file '${kotlinScript.canonicalPath}' line: 1 - """ - } - } - - private - fun assertFailingBuildOutputOf(vararg arguments: String, string: () -> String) = - assertThat(buildAndFail(*arguments).output, containsMultiLineString(string())) -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginModelIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginModelIntegrationTest.kt (revision e7197a9fd15a6f58e34c52acb247042cff4051a5) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginModelIntegrationTest.kt (revision 0) @@ -1,101 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.FoldersDsl -import org.gradle.kotlin.dsl.fixtures.withFolders - -import org.junit.Test - -import java.io.File - - -class PrecompiledScriptPluginModelIntegrationTest : ScriptModelIntegrationTest() { - - @Test - fun `given a single project build, the classpath of a precompiled script plugin is the compile classpath of its enclosing source-set`() { - - val implementationDependency = - withFile("implementation.jar") - - val classpathDependency = - withFile("classpath.jar") - - withBuildScript(""" - plugins { - `kotlin-dsl` - } - - buildscript { - dependencies { - classpath(files("${classpathDependency.name}")) - } - } - - dependencies { - implementation(files("${implementationDependency.name}")) - } - """) - - val precompiledScriptPlugin = - withFile("src/main/kotlin/my-plugin.gradle.kts") - - assertClassPathFor( - precompiledScriptPlugin, - includes = setOf(implementationDependency), - excludes = setOf(classpathDependency)) - } - - @Test - fun `given a multi-project build, the classpath of a precompiled script plugin is the compile classpath of its enclosing source-set`() { - - val dependencyA = - withFile("a.jar") - - val dependencyB = - withFile("b.jar") - - projectRoot.withFolders { - - withFile("settings.gradle.kts", """ - include("project-a") - include("project-b") - """) - - "project-a" { - "src/main/kotlin" { - withFile("my-plugin-a.gradle.kts") - } - withImplementationDependencyOn(dependencyA) - } - - "project-b" { - "src/main/kotlin" { - withFile("my-plugin-b.gradle.kts") - } - withImplementationDependencyOn(dependencyB) - } - } - - assertClassPathFor( - existing("project-a/src/main/kotlin/my-plugin-a.gradle.kts"), - includes = setOf(dependencyA), - excludes = setOf(dependencyB)) - - assertClassPathFor( - existing("project-b/src/main/kotlin/my-plugin-b.gradle.kts"), - includes = setOf(dependencyB), - excludes = setOf(dependencyA)) - } - - private - fun FoldersDsl.withImplementationDependencyOn(file: File) { - withFile("build.gradle.kts", """ - plugins { - `kotlin-dsl` - } - - dependencies { - implementation(files("${file.name}")) - } - """) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/ScriptCachingIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/ScriptCachingIntegrationTest.kt (revision 92916e9a3858ff2e1d4d624fe08b944445677603) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/ScriptCachingIntegrationTest.kt (revision 0) @@ -1,430 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.KotlinBuildScript -import org.gradle.kotlin.dsl.KotlinInitScript -import org.gradle.kotlin.dsl.KotlinSettingsScript - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.gradle.kotlin.dsl.fixtures.DeepThought -import org.gradle.kotlin.dsl.fixtures.IsolatedTestKitDir -import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles - -import org.gradle.kotlin.dsl.support.KotlinBuildscriptBlock -import org.gradle.kotlin.dsl.support.KotlinInitscriptBlock -import org.gradle.kotlin.dsl.support.KotlinPluginsBlock -import org.gradle.kotlin.dsl.support.KotlinSettingsBuildscriptBlock - -import org.gradle.testkit.runner.BuildResult - -import org.junit.ClassRule -import org.junit.Test - -import java.io.File - -import kotlin.reflect.KClass - - -@LeaksFileHandles(""" - Daemons hold their daemon log file open after the build has finished, debug logging exacerbates this. - This should be revisited once TestKit provides a mechanism to control daemon termination. -""") -class ScriptCachingIntegrationTest : AbstractIntegrationTest() { - - companion object { - - @Suppress("unused") - @get:ClassRule - @JvmStatic - val isolatedTestKitDir = IsolatedTestKitDir() - } - - @Test - fun `same script, target type & classpath`() { - - // given: multi-project build with same build files - val sameContent = """println("Same script content on ${'$'}this")""" - withMultiProjectBuild(left = sameContent, right = sameContent).apply { - - // when: first use - buildForCacheInspection("help").apply { - - // then: single compilation and classloading - compilationCache { - misses(settingsFile, rootBuildFile, leftBuildFile) - hits(rightBuildFile) - } - classLoadingCache { - misses(settingsFile, rootBuildFile, leftBuildFile) - hits(rightBuildFile) - } - } - - // when: second use - buildForCacheInspection("help").apply { - - // then: no compilation nor class loading - compilationCache { - hits(leftBuildFile, rootBuildFile, rightBuildFile) - } - classLoadingCache { - hits(leftBuildFile, rootBuildFile, rightBuildFile) - } - } - - // when: other daemon - buildWithAnotherDaemon("help").apply { - - // then: single class loading only - compilationCache { - hits(leftBuildFile, rootBuildFile, rightBuildFile) - } - classLoadingCache { - misses(rootBuildFile, leftBuildFile) - hits(rightBuildFile) - } - } - } - } - - @Test - fun `same script different target type`() { - - // given: same init, settings & build files all applying same script - val same = withFile("same.gradle.kts", """println("Same script on ${'$'}this")""") - val sameApply = """apply(from = "same.gradle.kts")""" - val initScriptFile = withFile("same.init.gradle.kts", sameApply) - - val initializationFile = cachedInitializationFile(initScriptFile) - val settingsFile = cachedSettingsFile(withSettings(sameApply)) - val buildFile = cachedBuildFile(withBuildScript(sameApply)) - val sameOnGradle = cachedGradleScript(same) - val sameOnSettings = cachedSettingsScript(same) - val sameOnProject = cachedProjectScript(same) - - // when: first use - buildForCacheInspection("help", "-I", initScriptFile.absolutePath).apply { - - // then: compilation and classloading - compilationCache { - misses(initializationFile, settingsFile, buildFile) - misses(sameOnGradle, sameOnSettings, sameOnProject) - } - classLoadingCache { - misses(initializationFile, settingsFile, buildFile) - misses(sameOnGradle, sameOnSettings, sameOnProject) - } - } - - // when: second use - buildForCacheInspection("help", "-I", initScriptFile.absolutePath).apply { - - // then: no compilation nor class loading - compilationCache { - hits(initializationFile, settingsFile, buildFile) - hits(sameOnGradle, sameOnSettings, sameOnProject) - } - classLoadingCache { - hits(initializationFile, settingsFile, buildFile) - hits(sameOnGradle, sameOnSettings, sameOnProject) - } - } - - // when: other daemon - buildWithAnotherDaemon("help", "-I", initScriptFile.absolutePath).apply { - - // then: class loading only - compilationCache { - hits(initializationFile, settingsFile, buildFile) - hits(sameOnGradle, sameOnSettings, sameOnProject) - } - classLoadingCache { - misses(initializationFile, settingsFile, buildFile) - misses(sameOnGradle, sameOnSettings, sameOnProject) - } - } - } - - @Test - fun `same script & target type different classpath`() { - - // given: different classpath - withClassJar("left/fixture.jar") - withClassJar("right/fixture.jar", DeepThought::class.java) - - // and: same script & target type - val sameContent = """ - buildscript { - dependencies { classpath(files("fixture.jar")) } - } - println("Same content, different classpath on ${'$'}this") - """ - withMultiProjectBuild(left = sameContent, right = sameContent).apply { - - // when: first use - buildForCacheInspection("help").apply { - - // then: compilation and classloading - compilationCache { - misses(leftBuildFile) - hits(rightBuildFile.buildscript!!) // same buildscript block, target type and classpath - misses(rightBuildFile.body) // different classpath - } - classLoadingCache { - misses(leftBuildFile) - hits(rightBuildFile.buildscript!!) - misses(rightBuildFile.body) - } - } - - // when: second use - buildForCacheInspection("help").apply { - - // then: no compilation nor class loading - compilationCache { - hits(leftBuildFile, rightBuildFile) - } - classLoadingCache { - hits(leftBuildFile, rightBuildFile) - } - } - - // when: other daemon - buildWithAnotherDaemon("help").apply { - - // then: class loading only - compilationCache { - hits(leftBuildFile, rightBuildFile) - } - classLoadingCache { - misses(leftBuildFile) - hits(rightBuildFile.buildscript!!) - misses(rightBuildFile.body) - } - } - } - } - - @Test - fun `in-memory script class loading cache releases memory of unused entries`() { - - // given: buildSrc memory hog - val myTask = withFile("buildSrc/src/main/groovy/MyTask.groovy", """ - import org.gradle.api.* - import org.gradle.api.tasks.* - - class MyTask extends DefaultTask { - static final byte[] MEMORY_HOG = new byte[64 * 1024 * 1024] - @TaskAction void runAction0() {} - } - """) - val buildFile = cachedBuildFile(withBuildScript("""task("myTask")""")) - - // expect: - for (run in 1..4) { - myTask.writeText(myTask.readText().replace("runAction${run - 1}", "runAction$run")) - buildWithDaemonHeapSize(256, "MyTask").apply { - compilationCache { misses(buildFile) } - classLoadingCache { misses(buildFile) } - } - } - } - - private - fun buildForCacheInspection(vararg arguments: String): BuildResult = - gradleRunnerForCacheInspection(*arguments) - .build() - - private - fun buildWithAnotherDaemon(vararg arguments: String): BuildResult = - buildWithDaemonHeapSize(160, *arguments) - - private - fun buildWithDaemonHeapSize(heapMb: Int, vararg arguments: String): BuildResult = - withGradleJvmArguments("-Xms${heapMb}m", "-Xmx${heapMb}m", "-Dfile.encoding=UTF-8").run { - gradleRunnerForCacheInspection(*arguments).build() - } - - private - fun gradleRunnerForCacheInspection(vararg arguments: String) = - gradleRunnerForArguments(*arrayOf("-d") + arguments) - - private - fun withMultiProjectBuild(settings: String = "", root: String = "", left: String = "", right: String = "") = - MultiProjectCachedScripts( - cachedSettingsFile( - withSettings(""" - rootProject.name = "${projectRoot.name}" // distinguish settings files - $settings - include("right", "left") - """)), - cachedBuildFile( - withBuildScript(root), - root.contains("buildscript {"), - root.contains("plugins {")), - cachedBuildFile( - withBuildScriptIn("left", left), - left.contains("buildscript {"), - left.contains("plugins {")), - cachedBuildFile( - withBuildScriptIn("right", right), - right.contains("buildscript {"), - right.contains("plugins {"))) -} - - -private -data class MultiProjectCachedScripts( - val settingsFile: CachedScript.WholeFile, - val rootBuildFile: CachedScript.WholeFile, - val leftBuildFile: CachedScript.WholeFile, - val rightBuildFile: CachedScript.WholeFile -) - - -private -sealed class CachedScript { - - class WholeFile( - val buildscript: CompilationStage? = null, - val plugins: CompilationStage? = null, - val body: CompilationStage - ) : CachedScript() { - - val stages = listOfNotNull(buildscript, plugins, body) - } - - class CompilationStage( - sourceDescription: String, - file: File, - templateClass: KClass<*>, - val enabled: Boolean = true - ) : CachedScript() { - - val source = "$sourceDescription '$file'" - val template = templateClass.simpleName!! - } -} - - -private -object Descriptions { - val initializationScript = "initialization script" - val settingsFile = "settings file" - val buildFile = "build file" - val script = "script" - val initscriptBlock = "initscript block" - val buildscriptBlock = "buildscript block" - val pluginsBlock = "plugins block" -} - - -private -fun cachedInitializationFile(file: File, initscript: Boolean = false) = - CachedScript.WholeFile( - buildscript = CachedScript.CompilationStage(Descriptions.initscriptBlock, file, KotlinInitscriptBlock::class, initscript), - body = CachedScript.CompilationStage(Descriptions.initializationScript, file, KotlinInitScript::class)) - - -private -fun cachedGradleScript(file: File) = - CachedScript.WholeFile( - buildscript = CachedScript.CompilationStage(Descriptions.initscriptBlock, file, KotlinInitscriptBlock::class, false), - body = CachedScript.CompilationStage(Descriptions.script, file, KotlinInitScript::class)) - - -private -fun cachedSettingsFile(file: File, buildscript: Boolean = false) = - CachedScript.WholeFile( - buildscript = CachedScript.CompilationStage(Descriptions.buildscriptBlock, file, KotlinSettingsBuildscriptBlock::class, buildscript), - body = CachedScript.CompilationStage(Descriptions.settingsFile, file, KotlinSettingsScript::class)) - - -private -fun cachedSettingsScript(file: File) = - CachedScript.WholeFile( - buildscript = CachedScript.CompilationStage(Descriptions.buildscriptBlock, file, KotlinSettingsBuildscriptBlock::class, false), - body = CachedScript.CompilationStage(Descriptions.script, file, KotlinSettingsScript::class)) - - -private -fun cachedBuildFile(file: File, buildscript: Boolean = false, plugins: Boolean = false) = - CachedScript.WholeFile( - buildscript = CachedScript.CompilationStage(Descriptions.buildscriptBlock, file, KotlinBuildscriptBlock::class, buildscript), - plugins = CachedScript.CompilationStage(Descriptions.pluginsBlock, file, KotlinPluginsBlock::class, plugins), - body = CachedScript.CompilationStage(Descriptions.buildFile, file, KotlinBuildScript::class)) - - -private -fun cachedProjectScript(file: File) = - CachedScript.WholeFile( - buildscript = CachedScript.CompilationStage(Descriptions.buildscriptBlock, file, KotlinBuildscriptBlock::class, false), - plugins = CachedScript.CompilationStage(Descriptions.pluginsBlock, file, KotlinPluginsBlock::class, false), - body = CachedScript.CompilationStage(Descriptions.script, file, KotlinBuildScript::class)) - - -private -fun BuildResult.compilationCache(action: CompilationCache.() -> Unit) = - action(CompilationCache(this)) - - -private -class CompilationCache(val result: BuildResult) { - - fun misses(vararg cachedScripts: CachedScript) = - cachedScripts.forEach { assertCompilations(it, 1) } - - fun hits(vararg cachedScripts: CachedScript) = - cachedScripts.forEach { assertCompilations(it, 0) } - - fun assertCompilations(cachedScript: CachedScript, count: Int) = - when (cachedScript) { - is CachedScript.WholeFile -> cachedScript.stages.forEach { assertCompilations(it, count) } - is CachedScript.CompilationStage -> assertCompilations(cachedScript, count) - } - - fun assertCompilations(stage: CachedScript.CompilationStage, count: Int) = - result.assertOccurrenceCountOf("compiling", stage, count) -} - - -private -fun BuildResult.classLoadingCache(action: ClassLoadingCache.() -> Unit) = - action(ClassLoadingCache(this)) - - -private -class ClassLoadingCache(val result: BuildResult) { - - fun misses(vararg cachedScripts: CachedScript) = - cachedScripts.forEach { assertClassLoads(it, 1) } - - fun hits(vararg cachedScripts: CachedScript) = - cachedScripts.forEach { assertClassLoads(it, 0) } - - fun assertClassLoads(cachedScript: CachedScript, count: Int) = - when (cachedScript) { - is CachedScript.WholeFile -> cachedScript.stages.forEach { assertClassLoads(it, count) } - is CachedScript.CompilationStage -> assertClassLoads(cachedScript, count) - } - - fun assertClassLoads(stage: CachedScript.CompilationStage, count: Int) = - result.assertOccurrenceCountOf("loading", stage, count) -} - - -private -fun BuildResult.assertOccurrenceCountOf(actionDisplayName: String, stage: CachedScript.CompilationStage, count: Int) { - val expectedCount = if (stage.enabled) count else 0 - val logStatement = "${actionDisplayName.capitalize()} ${stage.template} from ${stage.source}" - val observedCount = output.occurrenceCountOf(logStatement) - require(observedCount == expectedCount) { - "Expected $actionDisplayName $expectedCount ${stage.template} from ${stage.source}, but got $observedCount\n" + - " Looking for statement: $logStatement\n" + - " Build output was:\n" + output.prependIndent(" ") - } -} - - -private -fun String.occurrenceCountOf(string: String) = - split(string).size - 1 Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/ScriptModelIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/ScriptModelIntegrationTest.kt (revision 7119b76408e0dc8545d7ee25c03359ba2fa607af) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/ScriptModelIntegrationTest.kt (revision 0) @@ -1,241 +0,0 @@ -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.concurrent.future -import org.gradle.kotlin.dsl.embeddedKotlinVersion - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.gradle.kotlin.dsl.fixtures.customInstallation -import org.gradle.kotlin.dsl.fixtures.matching -import org.gradle.kotlin.dsl.fixtures.withTestDaemon - -import org.gradle.kotlin.dsl.resolver.GradleInstallation -import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptModelRequest -import org.gradle.kotlin.dsl.resolver.fetchKotlinBuildScriptModelFor -import org.gradle.kotlin.dsl.tooling.models.KotlinBuildScriptModel - -import org.hamcrest.CoreMatchers.* -import org.hamcrest.Matcher -import org.hamcrest.MatcherAssert.assertThat - -import java.io.File - - -/** - * Base class for [KotlinBuildScriptModel] integration tests. - */ -abstract class ScriptModelIntegrationTest : AbstractIntegrationTest() { - - protected - fun assertSourcePathIncludesGradleSourcesGiven(rootProjectScript: String, subProjectScript: String) { - - assertSourcePathGiven( - rootProjectScript, - subProjectScript, - hasItems("core-api")) - } - - protected - fun assertSourcePathIncludesKotlinStdlibSourcesGiven(rootProjectScript: String, subProjectScript: String) { - - assertSourcePathGiven( - rootProjectScript, - subProjectScript, - hasItems("kotlin-stdlib-jdk8-$embeddedKotlinVersion-sources.jar")) - } - - protected - fun assertSourcePathIncludesKotlinPluginSourcesGiven(rootProjectScript: String, subProjectScript: String) { - - assertSourcePathGiven( - rootProjectScript, - subProjectScript, - hasItems( - equalTo("kotlin-gradle-plugin-$embeddedKotlinVersion-sources.jar"), - matching("annotations-[0-9.]+-sources\\.jar"))) - } - - private - fun assertSourcePathGiven( - rootProjectScript: String, - subProjectScript: String, - matches: Matcher> - ) { - - val subProjectName = "sub" - withSettings("include(\"$subProjectName\")") - - withBuildScript(rootProjectScript) - val subProjectScriptFile = withBuildScriptIn(subProjectName, subProjectScript) - - assertThat(sourcePathFor(subProjectScriptFile).map { it.name }, matches) - } - - protected - fun sourcePathFor(scriptFile: File) = - kotlinBuildScriptModelFor(projectRoot, scriptFile).sourcePath - - protected - class ProjectSourceRoots(val projectDir: File, val sourceSets: List, val languages: List) - - protected - fun withMainSourceSetJavaIn(projectDir: String) = - ProjectSourceRoots(existing(projectDir), listOf("main"), listOf("java")) - - protected - fun withMainSourceSetJavaKotlinIn(projectDir: String) = - ProjectSourceRoots(existing(projectDir), listOf("main"), listOf("java", "kotlin")) - - protected - fun matchesProjectsSourceRoots(vararg projectSourceRoots: ProjectSourceRoots): Matcher> { - - fun hasLanguageDir(base: File, set: String, lang: String): Matcher> = - hasItem(base.resolve("src/$set/$lang")) - - return allOf( - *projectSourceRoots - .filter { it.languages.isNotEmpty() } - .flatMap { sourceRoots -> - val languageDirs = - sourceRoots.sourceSets.flatMap { sourceSet -> - listOf("java", "kotlin").map { language -> - val hasLanguageDir = hasLanguageDir(sourceRoots.projectDir, sourceSet, language) - if (language in sourceRoots.languages) hasLanguageDir - else not(hasLanguageDir) - } - } - - val resourceDirs = - sourceRoots.sourceSets.map { sourceSet -> - hasLanguageDir(sourceRoots.projectDir, sourceSet, "resources") - } - - languageDirs + resourceDirs - }.toTypedArray()) - } - - protected - fun withMultiProjectKotlinBuildSrc(): Array { - withFile("buildSrc/settings.gradle.kts", """include(":a", ":b", ":c")""") - withFile("buildSrc/build.gradle.kts", """ - plugins { - java - `kotlin-dsl` apply false - } - - val kotlinDslProjects = listOf(project.project(":a"), project.project(":b")) - - kotlinDslProjects.forEach { - it.apply(plugin = "org.gradle.kotlin.kotlin-dsl") - } - - dependencies { - kotlinDslProjects.forEach { - "runtime"(project(it.path)) - } - } - """) - withFile("buildSrc/b/build.gradle.kts", """dependencies { implementation(project(":c")) }""") - withFile("buildSrc/c/build.gradle.kts", "plugins { java }") - - return arrayOf( - withMainSourceSetJavaIn("buildSrc"), - withMainSourceSetJavaKotlinIn("buildSrc/a"), - withMainSourceSetJavaKotlinIn("buildSrc/b"), - withMainSourceSetJavaIn("buildSrc/c")) - } - - protected - fun assertContainsGradleKotlinDslJars(classPath: List) { - val version = "[0-9.]+(-.+?)?" - assertThat( - classPath.map { it.name }, - hasItems( - matching("gradle-kotlin-dsl-$version\\.jar"), - matching("gradle-api-$version\\.jar"), - matching("gradle-kotlin-dsl-extensions-$version\\.jar"))) - } - - protected - fun assertClassPathFor(buildScript: File, includes: Set, excludes: Set) = - assertThat( - classPathFor(projectRoot, buildScript).map { it.name }, - allOf( - hasItems(*includes.map { it.name }.toTypedArray()), - not(hasItems(*excludes.map { it.name }.toTypedArray())))) - - protected - fun assertClassPathContains(vararg files: File) = - assertClassPathContains(canonicalClassPath(), *files) - - protected - fun assertClassPathContains(classPath: List, vararg files: File) = - assertThat( - classPath.map { it.name }, - hasItems(*fileNameSetOf(*files))) - - protected - fun assertContainsBuildSrc(classPath: List) = - assertThat( - classPath.map { it.name }, - hasItem("buildSrc.jar")) - - protected - fun assertIncludes(classPath: List, vararg files: File) = - assertThat( - classPath.map { it.name }, - hasItems(*fileNameSetOf(*files))) - - protected - fun assertExcludes(classPath: List, vararg files: File) = - assertThat( - classPath.map { it.name }, - not(hasItems(*fileNameSetOf(*files)))) - - private - fun fileNameSetOf(vararg files: File) = - files.map { it.name }.toSet().toTypedArray().also { - assert(it.size == files.size) - } - - protected - fun canonicalClassPath() = - canonicalClassPathFor(projectRoot) -} - - -internal -fun canonicalClassPathFor(projectDir: File, scriptFile: File? = null) = - kotlinBuildScriptModelFor(projectDir, scriptFile).canonicalClassPath - - -private -fun classPathFor(projectDir: File, scriptFile: File?) = - kotlinBuildScriptModelFor(projectDir, scriptFile).classPath - - -internal -val KotlinBuildScriptModel.canonicalClassPath - get() = classPath.map(File::getCanonicalFile) - - -internal -fun kotlinBuildScriptModelFor(projectDir: File, scriptFile: File? = null): KotlinBuildScriptModel = - withTestDaemon { - future { - fetchKotlinBuildScriptModelFor( - KotlinBuildScriptModelRequest( - projectDir = projectDir, - scriptFile = scriptFile, - gradleInstallation = customGradleInstallation(), - jvmOptions = listOf("-Xms128m", "-Xmx256m"))) { - - setStandardOutput(System.out) - setStandardError(System.err) - } - }.get() - } - - -internal -fun customGradleInstallation() = - GradleInstallation.Local(customInstallation()) Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/TestKitIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/TestKitIntegrationTest.kt (revision 2590a9fe43369ee0d7f3b68861bb979426ad13d3) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/integration/TestKitIntegrationTest.kt (revision 0) @@ -1,123 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.integration - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest - -import org.junit.Test - - -class TestKitIntegrationTest : AbstractIntegrationTest() { - - @Test - fun `withPluginClasspath works`() { - - withBuildScript(""" - - plugins { - `java-gradle-plugin` - `kotlin-dsl` - } - - gradlePlugin { - (plugins) { - "test" { - id = "test" - implementationClass = "plugin.TestPlugin" - } - } - } - - dependencies { - testImplementation("junit:junit:4.12") - } - - repositories { - jcenter() - } - """) - - withFile("src/main/kotlin/plugin/TestPlugin.kt", """ - - package plugin - - import org.gradle.api.* - - class TestPlugin : Plugin { - override fun apply(project: Project) { - project.extensions.create("test", TestExtension::class.java) - } - } - - open class TestExtension { - fun ack() = println("Ack!") - } - """) - - withFile("src/test/kotlin/plugin/TestPluginTest.kt", """ - - package plugin - - import org.gradle.testkit.runner.* - import org.hamcrest.CoreMatchers.* - import org.junit.* - import org.junit.Assert.assertThat - import org.junit.rules.TemporaryFolder - - class TestPluginTest { - - @Test - fun `test extension can be configured`() { - - withBuildscript(""${'"'} - plugins { - id("test") - } - - test { - ack() - } - ""${'"'}) - - assertThat( - build().output, - containsString("Ack!")) - } - - private - fun build(vararg arguments: String): BuildResult = - GradleRunner - .create() - .withProjectDir(temporaryFolder.root) - .withPluginClasspath() - .withArguments(*arguments) - .build() - - private - fun withBuildscript(script: String) = - temporaryFolder.newFile("build.gradle.kts").apply { - writeText(script) - } - - @Rule @JvmField val temporaryFolder = TemporaryFolder() - } - """) - - println( - build("test").output) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/BuildscriptBlockExtractionTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/BuildscriptBlockExtractionTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/BuildscriptBlockExtractionTest.kt (revision 0) @@ -1,108 +0,0 @@ -package org.gradle.kotlin.dsl.provider - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Assert.assertNull -import org.junit.Assert.fail -import org.junit.Test - - -class BuildscriptBlockExtractionTest { - - @Test - fun `given top-level buildscript it returns exact range`() { - val script = """ - val foo = 42 - buildscript { - val bar = 51 - repositories {} - // also part of the content }} - }dependencies {}""".replaceIndent() - - val range = extractBuildscriptBlockFrom(script)!! - assertThat( - script.substring(range), - equalTo(""" - buildscript { - val bar = 51 - repositories {} - // also part of the content }} - }""".replaceIndent())) - } - - @Test - fun `given non top-level buildscript it returns null`() { - // as we can't currently know if it's a legit call to another similarly named - // function in a different context - assertNoBuildscript("foo { buildscript {} }") - } - - @Test - fun `given top-level buildscript with typo it returns null`() { - assertNoBuildscript("buildscripto {}") - } - - @Test - fun `given top-level buildscript reference it returns null`() { - assertNoBuildscript(""" - val a = buildscript - a.dependencies {}""") - } - - @Test - fun `given top-level buildscript reference followed by top-level buildscript it returns correct range`() { - assertThat( - extractBuildscriptBlockFrom("val a = buildscript\nbuildscript {}"), - equalTo(20..33)) - } - - @Test - fun `given no buildscript it returns null`() { - assertNoBuildscript("dependencies {}") - } - - @Test - fun `given an empty script it returns null`() { - assertNoBuildscript("") - } - - @Test - fun `given line commented buildscript it returns null`() { - assertNoBuildscript("// no buildscript {} here") - } - - @Test - fun `given block commented buildscript it returns null`() { - assertNoBuildscript("/* /* no */ buildscript {} here either */") - } - - @Test - fun `given more than one top level buildscript block it throws IllegalStateException`() { - try { - extractBuildscriptBlockFrom("buildscript {} buildscript {}") - fail("Expecting ${UnexpectedBlock::class.simpleName}!") - } catch (unexpectedBlock: UnexpectedBlock) { - assertThat(unexpectedBlock.identifier, equalTo("buildscript")) - assertThat(unexpectedBlock.location, equalTo(15..28)) - assertThat(unexpectedBlock.message, equalTo("Unexpected block found.")) - } - } - - @Test - fun `given script containing CR characters it throws IllegalArgumentException`() { - try { - extractBuildscriptBlockFrom("buildscript {\r\n}\n\n") - fail("Expecting IllegalArgumentException!") - } catch (exception: IllegalArgumentException) { - assertThat( - exception.message, - equalTo("CR characters are not supported by the Kotlin lexer. Convert the line separators before attempting this operation.")) - } - } - - private - fun assertNoBuildscript(script: String) { - assertNull(extractBuildscriptBlockFrom(script)) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ChildFirstClassLoader.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ChildFirstClassLoader.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ChildFirstClassLoader.kt (revision 0) @@ -1,40 +0,0 @@ -/* - * Copyright 2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.provider - -import org.gradle.internal.classloader.VisitableURLClassLoader -import org.gradle.internal.classpath.ClassPath - - -/** - * A [VisitableURLClassLoader] that tries to load classes locally before delegating to its parent. - */ -class ChildFirstClassLoader(parent: ClassLoader, classPath: ClassPath) : VisitableURLClassLoader(parent, classPath) { - - override fun loadClass(name: String, resolve: Boolean): Class<*> = - findLoadedClass(name) - ?: tryToLoadLocally(name) - ?: super.loadClass(name, resolve) - - private - fun tryToLoadLocally(name: String): Class<*>? = - try { - findClass(name) - } catch (e: ClassNotFoundException) { - null - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ClassLoaderHierarchyTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ClassLoaderHierarchyTest.kt (revision e1a19b2b552fd1dc08d0455b7def529e5ee670fc) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ClassLoaderHierarchyTest.kt (revision 0) @@ -1,84 +0,0 @@ -package org.gradle.kotlin.dsl.provider - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock - -import org.gradle.api.internal.initialization.AbstractClassLoaderScope - -import org.gradle.internal.classpath.ClassPath -import org.gradle.internal.classpath.DefaultClassPath - -import org.gradle.kotlin.dsl.fixtures.DeepThought -import org.gradle.kotlin.dsl.fixtures.TestWithTempFiles -import org.gradle.kotlin.dsl.fixtures.classEntriesFor - -import org.gradle.kotlin.dsl.support.zipTo - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.CoreMatchers.hasItem -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - -import java.lang.ClassLoader.getSystemClassLoader - - -class ClassLoaderHierarchyTest : TestWithTempFiles() { - - @Test - fun `can dump complete ClassLoader hierarchy to json`() { - - ChildFirstClassLoader(getSystemClassLoader(), classPathWith(DeepThought::class.java)).use { loader -> - - val `class` = loader.loadClass(DeepThought::class.qualifiedName) - - val targetScope = mock { - on { localClassLoader } doReturn loader - on { exportClassLoader } doReturn loader.parent - on { parent }.then { it.mock } - on { path }.then { "the path" } - } - - val json = classLoaderHierarchyJsonFor(`class`, targetScope) - - val mapper = jacksonObjectMapper() - val hierarchy = mapper.readValue(json) - - assertThat(hierarchy.classLoaders.size, equalTo(3)) - assertThat(hierarchy.scopes.size, equalTo(1)) - assertThat(hierarchy.classLoaders[0].parents, hasItem(hierarchy.classLoaders[1].id)) - assertThat(hierarchy.scopes[0].label, equalTo("the path")) - assertThat(hierarchy.scopes[0].localClassLoader, equalTo(hierarchy.classLoaders[0].id)) - assertThat(hierarchy.scopes[0].exportClassLoader, equalTo(hierarchy.classLoaders[1].id)) - } - } - - private - fun classPathWith(`class`: Class<*>): ClassPath { - val jar = file("fixture.jar") - zipTo(jar, classEntriesFor(`class`)) - return DefaultClassPath.of(listOf(jar)) - } - - data class ClassLoaderHierarchy( - val classLoaders: List, - val scopes: List - ) - - data class ClassLoaderNode( - val id: String, - val label: String, - val parents: Set, - val classPath: List - ) - - data class ScopeNode( - val label: String, - val localClassLoader: String, - val exportClassLoader: String, - val isLocked: Boolean - ) -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassPathProviderTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassPathProviderTest.kt (revision 0a6ca13901930bc3aef7551f43a7104a4f1bfc90) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/KotlinScriptClassPathProviderTest.kt (revision 0) @@ -1,53 +0,0 @@ -package org.gradle.kotlin.dsl.provider - -import org.gradle.kotlin.dsl.support.ProgressMonitor - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.times -import com.nhaarman.mockito_kotlin.verify - -import org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory.ClassPathNotation.GRADLE_API -import org.gradle.internal.classpath.ClassPath - -import org.gradle.kotlin.dsl.fixtures.TestWithTempFiles - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class KotlinScriptClassPathProviderTest : TestWithTempFiles() { - - @Test - fun `should report progress based on the number of entries in gradle-api jar`() { - - val gradleApiJar = file("gradle-api-3.1.jar") - - val generatedKotlinExtensions = file("kotlin-dsl-extensions.jar") - - val kotlinExtensionsMonitor = mock(name = "kotlinExtensionsMonitor") - val progressMonitorProvider = mock { - on { progressMonitorFor(generatedKotlinExtensions, 1) } doReturn kotlinExtensionsMonitor - } - - val subject = KotlinScriptClassPathProvider( - classPathRegistry = mock { on { getClassPath(GRADLE_API.name) } doReturn ClassPath.EMPTY }, - gradleApiJarsProvider = { listOf(gradleApiJar) }, - jarCache = { id, generator -> file("$id.jar").apply(generator) }, - progressMonitorProvider = progressMonitorProvider) - - assertThat( - subject.gradleKotlinDsl.asFiles.toList(), - equalTo(listOf(gradleApiJar, generatedKotlinExtensions))) - - verifyProgressMonitor(kotlinExtensionsMonitor) - } - - private - fun verifyProgressMonitor(monitor: ProgressMonitor) { - verify(monitor, times(1)).onProgress() - verify(monitor, times(1)).close() - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/LineAndColumnFromRangeTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/LineAndColumnFromRangeTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/LineAndColumnFromRangeTest.kt (revision 0) @@ -1,36 +0,0 @@ -package org.gradle.kotlin.dsl.provider - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Test - -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - - -@RunWith(Parameterized::class) -class LineAndColumnFromRangeTest(val given: LineAndColumnFromRangeTest.Given) { - - data class Given(val range: IntRange, val expected: Pair) - - companion object { - - const val text = "line 1\nline 2\nline 3" - - @Parameterized.Parameters(name = "{0}") - @JvmStatic fun testCases(): Iterable = - listOf( - LineAndColumnFromRangeTest.Given(0..0, 1 to 1), - LineAndColumnFromRangeTest.Given(1..1, 1 to 2), - LineAndColumnFromRangeTest.Given(7..7, 2 to 1), - LineAndColumnFromRangeTest.Given(8..8, 2 to 2), - LineAndColumnFromRangeTest.Given(19..19, 3 to 6)) - } - - @Test - fun test() { - assertThat( - LineAndColumnFromRangeTest.Companion.text.lineAndColumnFromRange(given.range), - equalTo(given.expected)) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/LinePreservingSubstringTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/LinePreservingSubstringTest.kt (revision 629a0f4379c64be6db6cfa831af823996698a12b) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/LinePreservingSubstringTest.kt (revision 0) @@ -1,82 +0,0 @@ -package org.gradle.kotlin.dsl.provider - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class LinePreservingSubstringTest { - - @Test - fun `given a range starting after the first line, it should return a substring prefixed by blank lines`() { - val original = """ - // line 1 - // line 2 - buildscript { - // line 4 - } - """.replaceIndent() - val begin = original.indexOf("buildscript") - val end = original.indexOf("}") - assertThat( - original.linePreservingSubstring(begin..end), - equalTo(""" - - - buildscript { - // line 4 - }""".replaceIndent()) - ) - } - - @Test - fun `given a range starting on the first line, it should return it undecorated`() { - val original = """ - buildscript { - // line 2 - } - """.replaceIndent() - val begin = original.indexOf("buildscript") - val end = original.indexOf("}") - assertThat( - original.linePreservingSubstring(begin..end), - equalTo(""" - buildscript { - // line 2 - }""".replaceIndent()) - ) - } - - @Test - fun `given ranges linePreservingBlankRange should blank lines`() { - val original = """ - |// line 1 - |// line 2 - |buildscript { - | // line 4 - |} - |// line 6 - |plugins { - | // line 8 - |} - |// line 10 - """.trimMargin() - val buildscriptRange = original.indexOf("buildscript")..original.indexOf("}") - val pluginsRange = original.indexOf("plugins")..original.lastIndexOf("}") - assertThat( - original.linePreservingBlankRanges(listOf(buildscriptRange, pluginsRange)), - equalTo(""" - |// line 1 - |// line 2 - | - | - | - |// line 6 - | - | - | - |// line 10 - """.trimMargin())) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/PluginRequestsHandlerTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/PluginRequestsHandlerTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/PluginRequestsHandlerTest.kt (revision 0) @@ -1,45 +0,0 @@ -package org.gradle.kotlin.dsl.provider - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock -import com.nhaarman.mockito_kotlin.verify - -import org.gradle.api.internal.initialization.ClassLoaderScope -import org.gradle.api.internal.initialization.ScriptHandlerInternal -import org.gradle.api.internal.plugins.PluginManagerInternal -import org.gradle.api.internal.project.ProjectInternal - -import org.gradle.plugin.management.internal.PluginRequests -import org.gradle.plugin.management.internal.autoapply.AutoAppliedPluginHandler -import org.gradle.plugin.use.internal.PluginRequestApplicator - -import org.junit.Test - - -class PluginRequestsHandlerTest { - - @Test - fun `applies plugins after merging auto-applied plugin requests`() { - - // given: - val pluginManager = mock() - val target = mock { - on { this.pluginManager } doReturn pluginManager - } - val initialRequests = mock(name = "initialRequests") - val mergedRequests = mock(name = "mergedRequests") - val autoAppliedPluginHandler = mock { - on { mergeWithAutoAppliedPlugins(initialRequests, target) } doReturn mergedRequests - } - val pluginRequestApplicator = mock() - val scriptHandler = mock() - val targetScope = mock() - - // when: - val subject = PluginRequestsHandler(pluginRequestApplicator, autoAppliedPluginHandler) - subject.handle(initialRequests, scriptHandler, target, targetScope) - - // then: - verify(pluginRequestApplicator).applyPlugins(mergedRequests, scriptHandler, pluginManager, targetScope) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ScriptApiTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ScriptApiTest.kt (revision 5d704f53ce8ac61d04df2e6e25f2ad9f76e0803a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/provider/ScriptApiTest.kt (revision 0) @@ -1,207 +0,0 @@ -package org.gradle.kotlin.dsl.provider - -import org.gradle.kotlin.dsl.KotlinBuildScript -import org.gradle.kotlin.dsl.KotlinInitScript -import org.gradle.kotlin.dsl.KotlinSettingsScript - -import org.gradle.api.Action -import org.gradle.api.initialization.Settings - -import org.gradle.kotlin.dsl.precompile.PrecompiledInitScript -import org.gradle.kotlin.dsl.precompile.PrecompiledProjectScript -import org.gradle.kotlin.dsl.precompile.PrecompiledSettingsScript - -import kotlin.reflect.KCallable -import kotlin.reflect.KClass -import kotlin.reflect.KFunction -import kotlin.reflect.KMutableProperty -import kotlin.reflect.KParameter -import kotlin.reflect.KProperty -import kotlin.reflect.KType -import kotlin.reflect.KTypeProjection -import kotlin.reflect.KVariance -import kotlin.reflect.KVisibility -import kotlin.reflect.full.createType -import kotlin.reflect.full.declaredMembers -import kotlin.reflect.full.valueParameters -import kotlin.reflect.full.withNullability -import kotlin.reflect.jvm.javaGetter -import kotlin.reflect.jvm.jvmErasure - -import org.hamcrest.CoreMatchers.equalTo - -import org.junit.Assert.assertThat -import org.junit.Test - - -class ScriptApiTest { - - @Test - fun `build script template implements script api`() = - assertScriptApiOf() - - @Test - fun `settings script template implements script api`() = - assertScriptApiOf() - - @Test - fun `settings script template implements Settings#enableFeaturePreview`() = - assert(KotlinSettingsScript::class.implements(Settings::enableFeaturePreview)) - - @Test - fun `init script template implements script api`() = - assertScriptApiOf() - - @Test - fun `precompiled project script template implements script api`() = - assertScriptApiOf() - - @Test - fun `precompiled settings script template implements script api`() = - assertScriptApiOf() - - @Test - fun `precompiled init script template implements script api`() = - assertScriptApiOf() -} - - -private -inline fun assertScriptApiOf() = - assertApiOf(ScriptApi::class) - - -private -inline fun assertApiOf(expectedApi: KClass<*>) = - assertThat( - expectedApi.apiMembers.missingMembersFrom(T::class), - equalTo(emptyList())) - - -private -typealias ScriptApiMembers = Collection> - - -private -val KClass<*>.apiMembers: ScriptApiMembers - get() = declaredMembers - - -private -fun ScriptApiMembers.missingMembersFrom(scriptTemplate: KClass<*>): List> = - scriptTemplate.publicMembers.let { scriptTemplateMembers -> - filterNot(scriptTemplateMembers::containsMemberCompatibleWith) - } - - -private -fun KClass<*>.implements(api: KCallable<*>) = - publicMembers.containsMemberCompatibleWith(api) - - -private -val KClass<*>.publicMembers - get() = members.filter { it.visibility == KVisibility.PUBLIC } - - -private -fun List>.containsMemberCompatibleWith(api: KCallable<*>) = - find { it.isCompatibleWith(api) } != null - - -private -fun KCallable<*>.isCompatibleWith(api: KCallable<*>) = - when (this) { - is KFunction -> isCompatibleWith(api) - is KProperty -> isCompatibleWith(api) - else -> false - } - - -private -fun KProperty<*>.isCompatibleWith(api: KCallable<*>) = - this::class == api::class - && name == api.name - && returnType == api.returnType - - -private -fun KFunction<*>.isCompatibleWith(api: KCallable<*>) = - when { - api is KProperty && api !is KMutableProperty && isCompatibleWithGetterOf(api) -> true - api is KFunction && isCompatibleWith(api) -> true - else -> false - } - - -private -fun KFunction<*>.isCompatibleWithGetterOf(api: KProperty<*>) = - name == api.javaGetter?.name - && returnType == api.getter.returnType - && valueParameters.isEmpty() && api.getter.valueParameters.isEmpty() - - -private -fun KFunction<*>.isCompatibleWith(api: KFunction<*>) = - name == api.name - && returnType == api.returnType - && valueParameters.isCompatibleWith(api.valueParameters) - - -private -fun List.isCompatibleWith(api: List) = - when { - size != api.size -> false - isEmpty() -> true - else -> (0..(size - 1)).all { idx -> this[idx].isCompatibleWith(api[idx]) } - } - - -private -fun KParameter.isCompatibleWith(api: KParameter) = - when { - isVarargCompatibleWith(api) -> true - isGradleActionCompatibleWith(api) -> true - type.isParameterTypeCompatibleWith(api.type) -> true - else -> false - } - - -private -fun KParameter.isGradleActionCompatibleWith(api: KParameter) = - type.jvmErasure == Action::class - && api.isSamWithReceiverReturningUnit() - && type.arguments[0].type!!.isTypeArgumentCompatibleWith(api.type.arguments[0].type!!) - - -private -fun KParameter.isSamWithReceiverReturningUnit() = - type.jvmErasure == Function1::class - && type.arguments[1] == KTypeProjection(KVariance.INVARIANT, Unit::class.createType()) - - -private -fun KParameter.isVarargCompatibleWith(api: KParameter) = - isVararg && api.isVararg && type.isParameterTypeCompatibleWith(api.type) - - -private -fun KType.isParameterTypeCompatibleWith(apiParameterType: KType) = - when { - this == apiParameterType -> true - classifier != apiParameterType.classifier -> false - hasCompatibleTypeArguments(apiParameterType) -> true - else -> false - } - - -private -fun KType.hasCompatibleTypeArguments(api: KType) = - arguments.size == api.arguments.size && (0..(arguments.size - 1)).all { idx -> - arguments[idx].type!!.isTypeArgumentCompatibleWith(api.arguments[idx].type!!) - } - - -private -fun KType.isTypeArgumentCompatibleWith(api: KType) = - withNullability(false) == api Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/CompactTreeTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/CompactTreeTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/CompactTreeTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl.resolver - -import org.hamcrest.CoreMatchers.equalTo -import org.junit.Assert.assertThat -import org.junit.Test - - -class CompactTreeTest { - - @Test - fun `it will compact common prefixes`() { - assertThat( - compactStringFor(listOf("/a/b/c", "/a/b/d", "/a/e/c"), separator = '/'), - equalTo("/a/{b/{c, d}, e/c}")) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/ProjectRootOfTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/ProjectRootOfTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/ProjectRootOfTest.kt (revision 0) @@ -1,122 +0,0 @@ -package org.gradle.kotlin.dsl.resolver - -import org.gradle.kotlin.dsl.fixtures.FolderBasedTest - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - - -@RunWith(Parameterized::class) -class ProjectRootOfTest(private val settingsFileName: String) : FolderBasedTest() { - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun testCases() = - listOf(arrayOf("settings.gradle"), arrayOf("settings.gradle.kts")) - } - - @Test - fun `given a script file under a nested project it should return the nested project root`() { - - withFolders { - "root" { - "nested-project-root" { - // a nested project is detected by the presence of a settings file - withFile(settingsFileName) - "sub-project" { - withFile("build.gradle.kts") - } - } - } - } - - assertThat( - projectRootOf( - scriptFile = file("root/nested-project-root/sub-project/build.gradle.kts"), - importedProjectRoot = folder("root")), - equalTo(folder("root/nested-project-root"))) - } - - @Test - fun `given a script file under a separate project it should return the separate project root`() { - - withFolders { - "root" { - } - "separate-project-root" { - withFile("build.gradle.kts") - } - } - - assertThat( - projectRootOf( - scriptFile = file("separate-project-root/build.gradle.kts"), - importedProjectRoot = folder("root")), - equalTo(folder("separate-project-root"))) - } - - @Test - fun `given a script file under a separate nested project it should return the separate nested project root`() { - - withFolders { - "root" { - } - "separate" { - "nested-project-root" { - // a nested project is detected by the presence of a settings file - withFile(settingsFileName) - "sub-project" { - withFile("build.gradle.kts") - } - } - } - } - - assertThat( - projectRootOf( - scriptFile = file("separate/nested-project-root/sub-project/build.gradle.kts"), - importedProjectRoot = folder("root")), - equalTo(folder("separate/nested-project-root"))) - } - - @Test - fun `given a script file under the imported project it should return the imported project root`() { - - withFolders { - "root" { - "sub-project" { - withFile("build.gradle.kts") - } - } - } - - assertThat( - projectRootOf( - scriptFile = file("root/sub-project/build.gradle.kts"), - importedProjectRoot = folder("root")), - equalTo(folder("root"))) - } - - @Test - fun `given a script file in buildSrc it should return the buildSrc project root`() { - - withFolders { - "root" { - "buildSrc" { - withFile("build.gradle.kts") - } - } - } - - assertThat( - projectRootOf( - scriptFile = file("root/buildSrc/build.gradle.kts"), - importedProjectRoot = folder("root")), - equalTo(folder("root/buildSrc"))) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/ResolverCoordinatorTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/ResolverCoordinatorTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/ResolverCoordinatorTest.kt (revision 0) @@ -1,84 +0,0 @@ -package org.gradle.kotlin.dsl.resolver - -import org.gradle.kotlin.dsl.fixtures.assertInstanceOf - - -class ResolverCoordinatorTest { - - @org.junit.Test - fun `given an environment with a 'getScriptSectionTokens' entry, when no buildscript change, it will not try to retrieve the model`() { - - val environment = - environmentWithGetScriptSectionTokensReturning( - "buildscript" to sequenceOf(""), - "plugins" to sequenceOf("")) - - val action1 = resolverActionFor(environment, null) - org.gradle.kotlin.dsl.fixtures.withInstanceOf(action1) { - val action2 = resolverActionFor(environment, scriptDependencies()) - assertInstanceOf(action2) - } - } - - @org.junit.Test - fun `given an environment with a 'getScriptSectionTokens' entry, when buildscript changes, it will try to retrieve the model again`() { - - val env1 = environmentWithGetScriptSectionTokensReturning("buildscript" to sequenceOf("foo")) - val env2 = environmentWithGetScriptSectionTokensReturning("buildscript" to sequenceOf("bar")) - - val action1 = resolverActionFor(env1, null) - org.gradle.kotlin.dsl.fixtures.withInstanceOf(action1) { - val action2 = resolverActionFor(env2, scriptDependencies()) - assertInstanceOf(action2) - } - } - - @org.junit.Test - fun `given an environment with a 'getScriptSectionTokens' entry, when plugins block changes, it will try to retrieve the model again`() { - - val env1 = environmentWithGetScriptSectionTokensReturning("plugins" to sequenceOf("foo")) - val env2 = environmentWithGetScriptSectionTokensReturning("plugins" to sequenceOf("bar")) - - val action1 = resolverActionFor(env1, null) - org.gradle.kotlin.dsl.fixtures.withInstanceOf(action1) { - val action2 = resolverActionFor(env2, scriptDependencies()) - assertInstanceOf(action2) - } - } - - @org.junit.Test - fun `given an environment lacking a 'getScriptSectionTokens' entry, it will always try to retrieve the model`() { - - val environment = emptyMap() - val action1 = resolverActionFor(environment, null) - org.gradle.kotlin.dsl.fixtures.withInstanceOf(action1) { - val action2 = resolverActionFor(environment, scriptDependencies()) - assertInstanceOf(action2) - } - } - - private - fun resolverActionFor(environment: Map, previousDependencies: kotlin.script.dependencies.KotlinScriptExternalDependencies?) = - ResolverCoordinator.selectNextActionFor(EmptyScriptContents, environment, - previousDependencies) - - private - fun ResolverAction.RequestNew.scriptDependencies() = - KotlinBuildScriptDependencies(emptyList(), emptyList(), emptyList(), buildscriptBlockHash) - - private - fun environmentWithGetScriptSectionTokensReturning(vararg sections: Pair>) = - environmentWithGetScriptSectionTokens { _, section -> sections.find { it.first == section }?.second ?: emptySequence() } - - private - fun environmentWithGetScriptSectionTokens(function: (CharSequence, String) -> Sequence) = - mapOf("getScriptSectionTokens" to function) -} - - -private -object EmptyScriptContents : kotlin.script.dependencies.ScriptContents { - override val file: java.io.File? = null - override val text: CharSequence? = "" - override val annotations: Iterable = emptyList() -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/SourceDistributionResolverIntegrationTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/SourceDistributionResolverIntegrationTest.kt (revision fe0cf76281c115184368795ed8398ee777372f5e) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/SourceDistributionResolverIntegrationTest.kt (revision 0) @@ -1,92 +0,0 @@ -package org.gradle.kotlin.dsl.resolver - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest - -import org.gradle.util.TextUtil.normaliseFileSeparators - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class SourceDistributionResolverIntegrationTest : AbstractIntegrationTest() { - - @Test - fun `can download source distribution`() { - - withBuildScript(""" - - val resolver = ${SourceDistributionResolver::class.qualifiedName}(project) - for (sourceDir in resolver.sourceDirs()) { - val path = sourceDir.toPath() - val relativePath = path.parent.parent.parent.parent.relativize(path) - println("*" + relativePath) - } - - """) - - assertThat( - build().output.linesPrefixedBy("*").map(::normaliseFileSeparators).toSet(), - equalTo(expectedSourceDirs)) - } - - private - fun String.linesPrefixedBy(prefix: String) = - lineSequence().filter { it.startsWith(prefix) }.map { it.removePrefix(prefix) } - - private - val expectedSourceDirs = setOf( - "announce/src/main/java", "announce/src/main/resources", - "antlr/src/main/java", "antlr/src/main/resources", - "base-services/src/main/java", "base-services-groovy/src/main/java", - "build-cache/src/main/java", "build-cache-http/src/main/java", - "build-cache-http/src/main/resources", "build-comparison/src/main/groovy", - "build-comparison/src/main/java", "build-comparison/src/main/resources", - "build-init/src/main/groovy", "build-init/src/main/java", - "build-init/src/main/resources", "build-option/src/main/java", - "cli/src/main/java", "code-quality/src/main/groovy", "code-quality/src/main/resources", - "composite-builds/src/main/java", "composite-builds/src/main/resources", - "core/src/main/java", "core/src/main/resources", "core-api/src/main/java", - "dependency-management/src/main/java", "dependency-management/src/main/resources", - "diagnostics/src/main/java", "diagnostics/src/main/resources", - "ear/src/main/java", "ear/src/main/resources", - "ide/src/main/java", "ide/src/main/resources", - "ide-native/src/main/groovy", "ide-native/src/main/java", "ide-native/src/main/resources", - "ide-play/src/main/java", "ide-play/src/main/resources", "installation-beacon/src/main/java", - "internal-android-performance-testing/src/main/java", - "internal-integ-testing/src/main/groovy", "internal-integ-testing/src/main/resources", - "internal-performance-testing/src/main/groovy", "internal-performance-testing/src/main/resources", - "internal-testing/src/main/groovy", "ivy/src/main/java", "ivy/src/main/resources", - "jacoco/src/main/java", "jacoco/src/main/resources", - "javascript/src/main/java", "javascript/src/main/resources", - "jvm-services/src/main/java", "language-groovy/src/main/java", - "language-java/src/main/java", "language-java/src/main/resources", - "language-jvm/src/main/java", "language-jvm/src/main/resources", - "language-native/src/main/java", "language-native/src/main/resources", - "language-scala/src/main/java", "language-scala/src/main/resources", - "launcher/src/main/java", "launcher/src/main/resources", - "logging/src/main/java", "maven/src/main/java", "maven/src/main/resources", - "messaging/src/main/java", "model-core/src/main/java", "model-groovy/src/main/java", - "native/src/main/java", "osgi/src/main/java", "osgi/src/main/resources", - "persistent-cache/src/main/java", "platform-base/src/main/java", "platform-base/src/main/resources", - "platform-jvm/src/main/java", "platform-jvm/src/main/resources", - "platform-native/src/main/java", "platform-native/src/main/resources", - "platform-play/src/main/java", "platform-play/src/main/resources", - "plugin-development/src/main/java", "plugin-development/src/main/resources", - "plugin-use/src/main/java", "plugin-use/src/main/resources", - "plugins/src/main/java", "plugins/src/main/resources", - "process-services/src/main/java", "publish/src/main/java", - "publish/src/main/resources", "reporting/src/main/java", "reporting/src/main/resources", - "resources/src/main/java", "resources-gcs/src/main/java", - "resources-gcs/src/main/resources", "resources-http/src/main/java", "resources-http/src/main/resources", - "resources-s3/src/main/java", "resources-s3/src/main/resources", - "resources-sftp/src/main/java", "resources-sftp/src/main/resources", - "scala/src/main/java", "scala/src/main/resources", "signing/src/main/java", "signing/src/main/resources", - "test-kit/src/main/java", "testing-base/src/main/java", "testing-base/src/main/resources", - "testing-junit-platform/src/main/java", "testing-jvm/src/main/java", "testing-jvm/src/main/resources", - "testing-native/src/main/java", "testing-native/src/main/resources", - "tooling-api/src/main/java", "tooling-api-builders/src/main/java", "tooling-api-builders/src/main/resources", - "version-control/src/main/java", "version-control/src/main/resources", - "workers/src/main/java", "workers/src/main/resources", "wrapper/src/main/java") -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/SourcePathProviderTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/SourcePathProviderTest.kt (revision ce77a5dea4dbfd063055ed94b9b2becbb9d50593) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/resolver/SourcePathProviderTest.kt (revision 0) @@ -1,86 +0,0 @@ -package org.gradle.kotlin.dsl.resolver - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.mock - -import org.gradle.internal.classpath.ClassPath - -import org.gradle.kotlin.dsl.fixtures.FolderBasedTest -import org.gradle.kotlin.dsl.resolver.SourcePathProvider.sourcePathFor - -import org.hamcrest.CoreMatchers.hasItems -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class SourcePathProviderTest : FolderBasedTest() { - - /** - * This unit test can't rely on `BuildSrcSourceRootsConfigurationAction` - * it is testing the fallback behavior of [SourcePathProvider] - */ - @Test - fun `given buildSrc folder, it will fallback to approximate buildSrc source roots`() { - withFolders { - "project" { - "buildSrc/src/main" { - +"foo" - +"bar" - } - } - "gradle" { - "src" { - +"gradle-foo" - +"gradle-bar" - } - } - } - - assertThat( - sourcePathFor( - classPath = ClassPath.EMPTY, - projectDir = folder("project"), - gradleHomeDir = folder("gradle"), - sourceDistributionResolver = mock()).asFiles, - hasItems( - folder("project/buildSrc/src/main/foo"), - folder("project/buildSrc/src/main/bar"), - folder("gradle/src/gradle-foo"), - folder("gradle/src/gradle-bar"))) - } - - @Test - fun `when src dir is missing from Gradle distribution, it will try to download it`() { - withFolders { - "project" { - "buildSrc/src/main" { - +"foo" - +"bar" - } - } - "gradle" { - } - "sourceDistribution" { - "src-foo" {} - "src-bar" {} - } - } - - val resolver = mock { - on { sourceDirs() } doReturn subDirsOf(folder("sourceDistribution")) - } - - assertThat( - sourcePathFor( - classPath = ClassPath.EMPTY, - projectDir = folder("project"), - gradleHomeDir = folder("gradle"), - sourceDistributionResolver = resolver).asFiles, - hasItems( - folder("project/buildSrc/src/main/foo"), - folder("project/buildSrc/src/main/bar"), - folder("sourceDistribution/src-foo"), - folder("sourceDistribution/src-bar"))) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/support/EmbeddedKotlinProviderTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/support/EmbeddedKotlinProviderTest.kt (revision 1fb2945612ffced6a5d61f33ba03df9078ae9b5d) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/support/EmbeddedKotlinProviderTest.kt (revision 0) @@ -1,74 +0,0 @@ -package org.gradle.kotlin.dsl.support - -import org.gradle.kotlin.dsl.embeddedKotlinVersion -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class EmbeddedKotlinProviderTest : AbstractIntegrationTest() { - - @Test - fun `no extra dependencies are added to the buildscript classpath`() { - - val result = build("buildEnvironment") - - assertThat(result.output, containsString("No dependencies")) - } - - @Test - fun `buildscript dependencies to embedded kotlin are resolved without an extra repository`() { - - withBuildScript(""" - buildscript { - dependencies { - classpath("org.jetbrains.kotlin:kotlin-stdlib:$embeddedKotlinVersion") - classpath("org.jetbrains.kotlin:kotlin-reflect:$embeddedKotlinVersion") - classpath("org.jetbrains.kotlin:kotlin-compiler-embeddable:$embeddedKotlinVersion") - classpath("org.jetbrains.kotlin:kotlin-script-runtime:$embeddedKotlinVersion") - classpath("org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin:$embeddedKotlinVersion") - } - } - """) - - val result = build("buildEnvironment") - - listOf("stdlib", "reflect", "compiler-embeddable", "script-runtime", "sam-with-receiver-compiler-plugin").forEach { module -> - assertThat(result.output, containsString("org.jetbrains.kotlin:kotlin-$module:$embeddedKotlinVersion")) - } - } - - @Test - fun `stdlib and reflect are pinned to the embedded kotlin version`() { - withBuildScript(""" - buildscript { - dependencies { - classpath("org.jetbrains.kotlin:kotlin-stdlib:1.0") - classpath("org.jetbrains.kotlin:kotlin-reflect:1.0") - } - } - """) - - val result = build("buildEnvironment") - - listOf("stdlib", "reflect").forEach { module -> - assertThat(result.output, containsString("org.jetbrains.kotlin:kotlin-$module:1.0 -> $embeddedKotlinVersion")) - } - } - - @Test - fun `compiler-embeddable is not pinned`() { - withBuildScript(""" - buildscript { - dependencies { - classpath("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0") - } - } - """) - - val result = buildAndFail("buildEnvironment") - - assertThat(result.output, containsString("Could not find org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0")) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/support/ImplicitImportsTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/support/ImplicitImportsTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/support/ImplicitImportsTest.kt (revision 0) @@ -1,27 +0,0 @@ -package org.gradle.kotlin.dsl.support - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class ImplicitImportsTest : AbstractIntegrationTest() { - - @Test - fun `implicit imports are fully qualified to allow use of the preferred type amongst those with same simple name in different Gradle API packages`() { - - // given: - withBuildScript(""" - - println("*" + Jar::class.qualifiedName + "*") - - """) - - // when: - val result = build("help") - - // then: - assertThat(result.output, containsString("*org.gradle.api.tasks.bundling.Jar*")) - } -} Index: provider/src/test/kotlin/org/gradle/kotlin/dsl/support/KotlinCompilerTest.kt =================================================================== diff -u -N --- provider/src/test/kotlin/org/gradle/kotlin/dsl/support/KotlinCompilerTest.kt (revision 9dc6b89c12529624c89adca8ffe6d0cc523fca1c) +++ provider/src/test/kotlin/org/gradle/kotlin/dsl/support/KotlinCompilerTest.kt (revision 0) @@ -1,44 +0,0 @@ -package org.gradle.kotlin.dsl.support - -import org.gradle.kotlin.dsl.fixtures.TestWithTempFiles -import org.gradle.kotlin.dsl.fixtures.classLoaderFor - -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class KotlinCompilerTest : TestWithTempFiles() { - - @Test - fun `can compile Kotlin source file into jar`() { - - val sourceFile = - newFile("DeepThought.kt", """ - package hhgttg - - class DeepThought { - fun compute(): Int = 42 - } - """) - - val outputJar = newFile("output.jar") - compileToJar(outputJar, listOf(sourceFile), loggerFor()) - - val answer = - classLoaderFor(outputJar).use { it - .loadClass("hhgttg.DeepThought") - .newInstance() - .run { - this::class.java.getMethod("compute").invoke(this) - } - } - - assertThat( - answer, - equalTo(42)) - - assert(outputJar.delete()) - } -} Index: samples-tests/.gitignore =================================================================== diff -u -N --- samples-tests/.gitignore (revision 997c55d5726cd74d720f0142a6b79fe0b5b27c8e) +++ samples-tests/.gitignore (revision 0) @@ -1 +0,0 @@ -/build Index: samples-tests/build.gradle.kts =================================================================== diff -u -N --- samples-tests/build.gradle.kts (revision 8ef5967764c32fd388a836cdb7e44da6f17260fe) +++ samples-tests/build.gradle.kts (revision 0) @@ -1,20 +0,0 @@ -import build.* - -plugins { - id("kotlin-library") -} - -dependencies { - compile(project(":test-fixtures")) - compile("org.xmlunit:xmlunit-matchers:2.5.1") -} - -val customInstallation by rootProject.tasks -tasks { - "test" { - dependsOn(customInstallation) - inputs.dir("../samples") - } -} - -withParallelTests() Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/AbstractSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/AbstractSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/AbstractSampleTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest -import org.junit.Before - -import java.io.File - - -abstract class AbstractSampleTest(val sampleName: String) : AbstractIntegrationTest() { - - @Before - fun populateProjectRootWithSample() { - val sampleDir = File(samplesRootDir, sampleName) - copySampleProject(from = sampleDir, to = projectRoot) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/AntSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/AntSampleTest.kt (revision fc5cd9d444c8917b1e7e9bf828cdd406068c9259) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/AntSampleTest.kt (revision 0) @@ -1,35 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.junit.Test -import java.io.File - - -class AntSampleTest : AbstractSampleTest("ant") { - - @Test - fun `hello ant task`() { - - // when: - val result = build("hello") - - // then: - result.output.contains("Hello from Ant!") - } - - @Test - fun `zip ant task`() { - - // when: - build("zip") - - // then: - File(projectRoot, "build/archive.zip").isFile - } - - @Test - fun `custom pmd ant task`() { - - // expect: - build("pmd") - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildCacheSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildCacheSampleTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildCacheSampleTest.kt (revision 0) @@ -1,20 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.testkit.runner.TaskOutcome -import org.hamcrest.CoreMatchers.equalTo -import org.junit.Assert.assertThat -import org.junit.Test - - -class BuildCacheSampleTest : AbstractSampleTest("build-cache") { - - @Test - fun `compileJava tasks gets cached`() { - - build("build") - - assertThat( - build("clean", "build").outcomeOf(":compileJava"), - equalTo(TaskOutcome.FROM_CACHE)) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildScanSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildScanSampleTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildScanSampleTest.kt (revision 0) @@ -1,13 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.canPublishBuildScan -import org.junit.Test - - -class BuildScanSampleTest : AbstractSampleTest("build-scan") { - - @Test - fun `publishes build scan`() { - canPublishBuildScan() - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildSrcPluginSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildSrcPluginSampleTest.kt (revision 52b6bab6963251c4d2ae0950d271ce417814e998) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/BuildSrcPluginSampleTest.kt (revision 0) @@ -1,33 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.MatcherAssert.assertThat - -import org.junit.Test - - -class BuildSrcPluginSampleTest : AbstractSampleTest("buildSrc-plugin") { - - @Test - fun `buildSrc-plugin`() { - assertThat( - build("greet").output, - containsString("I'm buildSrc-plugin.")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CodeQualitySampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CodeQualitySampleTest.kt (revision d2a3674af1801e88c7c0b42c1516f924d9845277) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CodeQualitySampleTest.kt (revision 0) @@ -1,33 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.testkit.runner.TaskOutcome - -import org.hamcrest.CoreMatchers.equalTo -import org.junit.Assert.assertThat - -import org.junit.Test - - -class CodeQualitySampleTest : AbstractSampleTest("code-quality") { - - @Test - fun `code quality plugins are properly configured`() { - - val result = build("build") - - val successfulTasks = listOf( - ":checkstyleMain", - ":checkstyleTest", - ":findbugsMain", - ":findbugsTest", - ":pmdMain", - ":pmdTest", - ":jdependMain", - ":jdependTest", - ":jacocoTestCoverageVerification") - - successfulTasks.forEach { taskName -> - assertThat(result.outcomeOf(taskName), equalTo(TaskOutcome.SUCCESS)) - } - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CompositeBuildsSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CompositeBuildsSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CompositeBuildsSampleTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class CompositeBuildsSampleTest : AbstractSampleTest("composite-builds") { - - @Test - fun `run cli`() { - assertThat( - build(":run").output, - containsString("The answer to the ultimate question of Life, the Universe and Everything is 42.")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CopySampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CopySampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/CopySampleTest.kt (revision 0) @@ -1,24 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Test - - -class CopySampleTest : AbstractSampleTest("copy") { - - @Test - fun `initConfig task copy spec satisfied`() { - // when: - build("initConfig") - - // then: - val root = projectRoot.toPath().resolve("build").resolve("target").resolve("config") - listOf("copy.data", "copy.xml").map { root.resolve(it).toFile() }.forEach { - assertTrue("File copied $it", it.exists()) - } - listOf("copy.bak", "copy.txt").map { root.resolve(it).toFile() }.forEach { - assertFalse("File not copied $it", it.exists()) - } - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/DomainObjectsSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/DomainObjectsSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/DomainObjectsSampleTest.kt (revision 0) @@ -1,23 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.containsMultiLineString - -import org.junit.Assert.assertThat -import org.junit.Test - -import java.io.File - - -class DomainObjectsSampleTest : AbstractSampleTest("domain-objects") { - - @Test - fun `books task list all books and their path`() { - assertThat( - build("books").output, - containsMultiLineString(""" - developerGuide -> src${File.separator}docs${File.separator}developerGuide - quickStart -> src${File.separator}docs${File.separator}quick-start - userGuide -> src${File.separator}docs${File.separator}userGuide - """)) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ExtraPropertiesSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ExtraPropertiesSampleTest.kt (revision f99bbfc61266c34c13408ece12d96c4b9f6de99d) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ExtraPropertiesSampleTest.kt (revision 0) @@ -1,21 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class ExtraPropertiesSampleTest : AbstractSampleTest("extra-properties") { - - @Test - fun `extra properties`() { - assertThat( - build("myTask").output, - allOf( - containsString("myTask.foo = 42"), - containsString("Extra foo property value: 42"), - containsString("myTask.bar = null"), - containsString("Optional extra bar property value: null"))) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/GradlePluginSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/GradlePluginSampleTest.kt (revision 9bc33d586b98b75996ccdb23550c3b38bd60dac6) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/GradlePluginSampleTest.kt (revision 0) @@ -1,21 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles - -import org.junit.Test -import org.junit.Assert.assertTrue - -import java.io.File - - -class GradlePluginSampleTest : AbstractSampleTest("gradle-plugin") { - - @Test - @LeaksFileHandles - fun `can use the plugin`() { - - build("consumer") - - assertTrue(File(projectRoot, "consumer/build/copy/build.gradle.kts").isFile) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/GroovyInteropSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/GroovyInteropSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/GroovyInteropSampleTest.kt (revision 0) @@ -1,23 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class GroovyInteropSampleTest : AbstractSampleTest("groovy-interop") { - - @Test - fun `stringSum`() { - assertThat( - build("stringSum").output, - containsString("GroovyKotlin")) - } - - @Test - fun `intSum`() { - assertThat( - build("intSum").output, - containsString("44")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloCoroutinesSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloCoroutinesSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloCoroutinesSampleTest.kt (revision 0) @@ -1,23 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.containsMultiLineString - -import org.junit.Assert.assertThat -import org.junit.Test - - -class HelloCoroutinesSampleTest : AbstractSampleTest("hello-coroutines") { - - @Test - fun `fibonacci`() { - assertThat( - build("run").output, - containsMultiLineString(""" - 1 - 1 - 2 - 3 - 5 - """)) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloKaptSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloKaptSampleTest.kt (revision 42e1bf0fd0692165393da29f7ea4b47716dd3d6f) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloKaptSampleTest.kt (revision 0) @@ -1,47 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.toPlatformLineSeparators -import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class HelloKaptSampleTest : AbstractSampleTest("hello-kapt") { - - @Test - fun `hello kapt`() { - val output = build("run").output - - assertThat( - output, - containsString(""" - Hello Writer{name=Douglas, age=41, books=[THGttG, DGHDA]} - The answer is 42 - """.trimIndent().toPlatformLineSeparators()) - ) - } - - @Test - fun `hello kapt tests`() { - build("test") - } - - @Test - fun `kapt javac options and kapt arguments`() { - existing("build.gradle.kts") - .appendText(""" - logger.info("JavacOptions: " + kapt.getJavacOptions().toString()) - """) - - val output = build("run", "--info").output - - assertThat( - output, - allOf( - containsString("The following options were not recognized by any processor: '[SomeKaptArgument"), - containsString("JavacOptions: {SomeJavacOption=OptionValue}") - ) - ) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloKotlinSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloKotlinSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloKotlinSampleTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class HelloKotlinSampleTest : AbstractSampleTest("hello-kotlin") { - - @Test - fun `hello kotlin world`() { - assertThat( - build("run").output, - containsString("Hello, world!")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloWorldSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloWorldSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/HelloWorldSampleTest.kt (revision 0) @@ -1,12 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.junit.Test - - -class HelloWorldSampleTest : AbstractSampleTest("hello-world") { - - @Test - fun `hello world`() { - build("test") - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/JavaScriptSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/JavaScriptSampleTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/JavaScriptSampleTest.kt (revision 0) @@ -1,51 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.junit.Test -import java.io.File -import java.io.FileReader -import javax.script.ScriptEngineManager -import java.io.StringWriter -import org.junit.Assert.assertThat -import org.hamcrest.CoreMatchers.equalTo -import java.io.Writer -import javax.script.ScriptEngine - - -class JavaScriptSampleTest : AbstractSampleTest("hello-js") { - - @Test - fun `hello world`() { - - build("assemble") - - val javaScriptOutput = StringWriter() - val engine = javaScriptEngine(javaScriptOutput) - - // Load Kotlin JS stdlib - engine.eval(existing("build/web/kotlin.js")) - - // Run build output - engine.eval(existing("build/web/output.js")) - - assertThat( - javaScriptOutput.toString().trim(), - equalTo("Hello, world!")) - } - - - private - fun javaScriptEngine(outputWriter: Writer) = - ScriptEngineManager().getEngineByName("nashorn").apply { - - // Redirect output from `print` to this writer - context.writer = outputWriter - - // Wire `console.log` to `print` - eval("var console = {}; console.log = print;") - } - - - private - fun ScriptEngine.eval(file: File) = - eval(FileReader(file)) -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MavenPluginSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MavenPluginSampleTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MavenPluginSampleTest.kt (revision 0) @@ -1,56 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.junit.Test -import org.junit.Assert.assertThat - -import org.xmlunit.matchers.CompareMatcher.isIdenticalTo -import java.io.File - - -class MavenPluginSampleTest : AbstractSampleTest("maven-plugin") { - - @Test - fun `uploadArchives publishes custom pom`() { - build("uploadArchives", "-Dmaven.repo.local=$tempMavenLocalDir") - assertPom(""" - - - 4.0.0 - - org.gradle - kotlin-dsl - 1.0 - - org.gradle.kotlin-dsl - $projectName - 1.0 - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - """) - } - - private - fun assertPom(expectedPom: String) = - assertThat(pomFile(), isIdenticalTo(expectedPom.trim()).ignoreWhitespace()) - - private - fun pomFile(): File = - existing("build/m2/releases/org/gradle/kotlin-dsl/$projectName/1.0/$projectName-1.0.pom") - - private - val projectName by lazy { - projectRoot.name - } - - private - val tempMavenLocalDir by lazy { - existing("build/m2/local") - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MavenPublishSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MavenPublishSampleTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MavenPublishSampleTest.kt (revision 0) @@ -1,45 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.junit.Assert.assertTrue -import org.junit.Test -import java.io.File -import java.util.jar.JarFile - - -class MavenPublishSampleTest : AbstractSampleTest("maven-publish") { - - @Test - fun `publish`() { - - // given: - val projectName = "maven-publish" - val projectVersion = "1.0.0" - val mavenPath = "org/gradle/sample/$projectName/$projectVersion" - - // when: - build("publish") - - // then: repository exists - val repoDir = existing("build/repo") - - // and: repository contains main JAR - val mainJar = File(repoDir, "$mavenPath/$projectName-$projectVersion.jar") - assertTrue("jar file $mainJar exists", mainJar.exists()) - - // and: main JAR contains .class entries - JarFile(mainJar).use { - val numClassEntries = it.stream().filter { it.name.endsWith(".class") }.count() - assertTrue(numClassEntries > 0) - } - - // and: repository contains sources JAR - val sourcesJar = File(repoDir, "$mavenPath/$projectName-$projectVersion-sources.jar") - assertTrue("source file $sourcesJar exists", sourcesJar.exists()) - - // and: sources JAR contains .java and .kt files - JarFile(sourcesJar).use { - assertTrue(it.stream().anyMatch { it.name.endsWith(".java") }) - assertTrue(it.stream().anyMatch { it.name.endsWith(".kt") }) - } - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ModelRulesSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ModelRulesSampleTest.kt (revision 318e736812bdea6d6cdfd642e81d0f397db131a2) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ModelRulesSampleTest.kt (revision 0) @@ -1,17 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.junit.Test - - -class ModelRulesSampleTest : AbstractSampleTest("model-rules") { - - @Test - fun `hello task`() { - - // when: - val result = build("hello") - - // then: - result.output.contains("Hello John Smith!") - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ModularitySampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ModularitySampleTest.kt (revision a03e5df79946c7171f9c286e15b4502a1a239fd8) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ModularitySampleTest.kt (revision 0) @@ -1,19 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class ModularitySampleTest : AbstractSampleTest("modularity") { - - @Test - fun `modularity`() { - assertThat( - build("foo", "bar", "lorem").output, - allOf( - containsString("Foo!"), - containsString("Bar!"))) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectConfigInjectionSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectConfigInjectionSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectConfigInjectionSampleTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class MultiKotlinProjectConfigInjectionSampleTest : AbstractSampleTest("multi-kotlin-project-config-injection") { - - @Test - fun `can run CLI application`() { - assertThat( - build(":cli:run").output, - containsString("The answer to the ultimate question of Life, the Universe and Everything is 42.")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectSampleTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class MultiKotlinProjectSampleTest : AbstractSampleTest("multi-kotlin-project") { - - @Test - fun `can run CLI application`() { - assertThat( - build(":cli:run").output, - containsString("The answer to the ultimate question of Life, the Universe and Everything is 42.")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectWithBuildSrcSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectWithBuildSrcSampleTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiKotlinProjectWithBuildSrcSampleTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class MultiKotlinProjectWithBuildSrcSampleTest : AbstractSampleTest("multi-kotlin-project-with-buildSrc") { - - @Test - fun `can run CLI application`() { - assertThat( - build(":cli:run").output, - containsString("The answer to the ultimate question of Life, the Universe and Everything is 42.")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiProjectWithBuildSrcSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiProjectWithBuildSrcSampleTest.kt (revision 71471b06755164d46cd8fe2482b7868124d58f5f) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/MultiProjectWithBuildSrcSampleTest.kt (revision 0) @@ -1,30 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.containsMultiLineString - -import org.junit.Assert.assertThat -import org.junit.Test - - -class MultiProjectWithBuildSrcSampleTest : AbstractSampleTest("multi-project-with-buildSrc") { - - @Test - fun `multi-project-with-buildSrc`() { - assertThat( - build("hello").output, - containsMultiLineString(""" - > Task :hello - I'm ${testName.methodName} - - > Task :bluewhale:hello - I'm bluewhale - - I depend on water - - I'm the largest animal that has ever lived on this planet. - - > Task :krill:hello - I'm krill - - I depend on water - - The weight of my species in summer is twice as heavy as all human beings. - """)) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/PrecompiledScriptPluginSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/PrecompiledScriptPluginSampleTest.kt (revision f1f3215177be6b21c17b2a98535ef8ee4450ae87) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/PrecompiledScriptPluginSampleTest.kt (revision 0) @@ -1,19 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles -import org.junit.Assert -import org.junit.Test -import java.io.File - - -class PrecompiledScriptPluginSampleTest : AbstractSampleTest("precompiled-script-plugin") { - - @Test - @LeaksFileHandles - fun `can use the plugin`() { - - build("consumer") - - Assert.assertTrue(File(projectRoot, "consumer/build/copy/build.gradle.kts").isFile) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ProjectPropertiesSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ProjectPropertiesSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ProjectPropertiesSampleTest.kt (revision 0) @@ -1,16 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class ProjectPropertiesSampleTest : AbstractSampleTest("project-properties") { - - @Test - fun `project properties`() { - assertThat( - build("-Plabel=answer to the ultimate question about life, the universe and everything", "compute").output, - containsString("The answer to the ultimate question about life, the universe and everything is 42.")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ProviderPropertiesSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ProviderPropertiesSampleTest.kt (revision cb44112374e36b41732ab390531b8bc29e8de327) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/ProviderPropertiesSampleTest.kt (revision 0) @@ -1,25 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString - -import org.junit.Assert.assertThat -import org.junit.Test -import java.io.File - - -class ProviderPropertiesSampleTest : AbstractSampleTest("provider-properties") { - - @Test - fun `hello task logs and write message to files`() { - // when: - val output = build("hello", "-i").output - - // then: - val message = "Hi from Gradle" - val files = listOf("a.txt", "b.txt").map { File(File(projectRoot, "build"), it).canonicalFile } - assertThat(output, containsString("Writing message '$message' to files $files")) - files.forEach { - assertThat(it.readText(), containsString(message)) - } - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/SamplesSmokeTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/SamplesSmokeTest.kt (revision 6a5d7590867130aa1212ed173d354038d1c62c59) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/SamplesSmokeTest.kt (revision 0) @@ -1,88 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.embeddedKotlinVersion -import org.gradle.kotlin.dsl.fixtures.AbstractIntegrationTest - -import org.hamcrest.CoreMatchers.containsString - -import org.junit.Assert.assertThat -import org.junit.Assume.assumeTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized - -import java.io.File - - -@RunWith(Parameterized::class) -class SamplesSmokeTest( - private val sampleName: String, - private val sampleDir: File -) : AbstractIntegrationTest() { - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun testCases(): Iterable> = - samplesRootDir.listFiles().filter { it.isDirectory }.map { arrayOf(it.name, it) } - } - - @Before - fun populateProjectRootWithSample() { - ignoreAndroidSampleUnlessAndroidHomeIsSet() - copySampleProject(from = sampleDir, to = projectRoot) - } - - @Test - fun `tasks task succeeds on `() { - build("tasks") - } - - @Test - fun `uses the right Kotlin Gradle Plugin version on `() { - - val projectPaths = listOf(":") + listSubProjectPaths().map { "$it:" } - val projectBuilds = projectPaths.map { buildSpec("${it}buildEnvironment") } - val buildsToCheck = - if (File(sampleDir, "buildSrc").isDirectory) { - projectBuilds + listOf(buildSpec("-p", "buildSrc", "buildEnvironment")) - } else { - projectBuilds - } - - val foundKotlinGradlePlugin = buildsToCheck.map(::assertKotlinGradlePluginVersion) - - // Mark that test as ignored if not using the kotlin-gradle-plugin - assumeTrue(foundKotlinGradlePlugin.any { it }) - } - - private - fun ignoreAndroidSampleUnlessAndroidHomeIsSet() { - if (sampleName.contains("android")) { - assumeTrue(System.getenv().containsKey("ANDROID_HOME")) - } - } - - private - fun buildSpec(vararg arguments: String) = arguments - - private - fun assertKotlinGradlePluginVersion(buildSpec: Array): Boolean = - build("-q", *buildSpec).run { - if (output.contains(":kotlin-gradle-plugin:")) { - assertThat(output, containsString(":kotlin-gradle-plugin:$embeddedKotlinVersion")) - true - } else { - false - } - } - - private - val extractSubProjectPaths = Regex("""Project '(:.*)'""") - - private - fun listSubProjectPaths() = - build("projects", "-q").output.lines() - .mapNotNull { extractSubProjectPaths.find(it)?.run { groupValues[1] } } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/SourceControlSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/SourceControlSampleTest.kt (revision 5c8d616a8132ca4fa330ecab3b47bafc0919021a) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/SourceControlSampleTest.kt (revision 0) @@ -1,22 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.hamcrest.CoreMatchers.containsString -import org.junit.Assert.assertThat -import org.junit.Test - - -class SourceControlSampleTest : AbstractSampleTest("source-control") { - - @Test - fun `source dependencies mapping`() { - - val externalDir = existing("external") - val sampleDir = existing("sample") - - build(externalDir, "generateGitRepo") - - assertThat( - build(sampleDir, "run").output, - containsString("The answer to the ultimate question of Life, the Universe and Everything is 42.")) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/TaskDependenciesSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/TaskDependenciesSampleTest.kt (revision 71471b06755164d46cd8fe2482b7868124d58f5f) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/TaskDependenciesSampleTest.kt (revision 0) @@ -1,40 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.containsMultiLineString - -import org.junit.Assert.assertThat -import org.junit.Test - - -class TaskDependenciesSampleTest : AbstractSampleTest("task-dependencies") { - - @Test - fun `default task`() { - assertThat( - build().output, - containsMultiLineString(""" - > Task :hello - Hello! - - > Task :goodbye - Goodbye! - - > Task :chat - """)) - } - - @Test - fun `mixItUp`() { - assertThat( - build("mixItUp").output, - containsMultiLineString(""" - > Task :hello - Hello! - - > Task :goodbye - Goodbye! - - > Task :mixItUp - """)) - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/TestKitSampleTest.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/TestKitSampleTest.kt (revision ffcbd26f25b949e19f525714cd06fa43ce0b93d9) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/TestKitSampleTest.kt (revision 0) @@ -1,28 +0,0 @@ -/* - * Copyright 2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.gradle.kotlin.dsl.samples - -import org.junit.Test - - -class TestKitSampleTest : AbstractSampleTest("testkit") { - - @Test - fun test() { - build("test") - } -} Index: samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/samples.kt =================================================================== diff -u -N --- samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/samples.kt (revision 5bcf6467a6ee9bac6c733b49353cfed0f1503776) +++ samples-tests/src/test/kotlin/org/gradle/kotlin/dsl/samples/samples.kt (revision 0) @@ -1,36 +0,0 @@ -package org.gradle.kotlin.dsl.samples - -import org.gradle.kotlin.dsl.fixtures.loadPropertiesFrom -import org.gradle.kotlin.dsl.fixtures.mergePropertiesInto -import org.gradle.kotlin.dsl.fixtures.rootProjectDir - -import java.io.File - - -internal -val samplesRootDir = File(rootProjectDir, "samples") - - -internal -fun copySampleProject(from: File, to: File) { - withMergedGradleProperties(to.resolve("gradle.properties")) { - from.copyRecursively(to) - listOf(".gradle", "build").map { File(to, it) }.filter { it.exists() }.forEach { - it.deleteRecursively() - } - } -} - - -private -fun withMergedGradleProperties(gradlePropertiesFile: File, action: () -> Unit) { - loadThenDeletePropertiesFrom(gradlePropertiesFile).let { baseProperties -> - action() - mergePropertiesInto(gradlePropertiesFile, baseProperties.map { it.toPair() }) - } -} - - -private -fun loadThenDeletePropertiesFrom(file: File) = - loadPropertiesFrom(file).also { file.delete() } Index: settings.gradle.kts =================================================================== diff -u -N -r04bad4e33e8419c6bdc6090d207bb8edfc6197e4 -r071d76cf5c78736f00c22fd6240ed425df3acf51 --- settings.gradle.kts (.../settings.gradle.kts) (revision 04bad4e33e8419c6bdc6090d207bb8edfc6197e4) +++ settings.gradle.kts (.../settings.gradle.kts) (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -12,3 +12,12 @@ "test-fixtures", "samples-tests", "integ-tests") + +for (project in rootProject.children) { + project.apply { + projectDir = file("subprojects/$name") + buildFileName = "build.gradle.kts" + assert(projectDir.isDirectory) + assert(buildFile.isFile) + } +} Index: subprojects/integ-tests/.gitignore =================================================================== diff -u -N --- subprojects/integ-tests/.gitignore (revision 0) +++ subprojects/integ-tests/.gitignore (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,2 @@ +/build +/out Index: subprojects/integ-tests/build.gradle.kts =================================================================== diff -u -N --- subprojects/integ-tests/build.gradle.kts (revision 0) +++ subprojects/integ-tests/build.gradle.kts (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,60 @@ +import build.* +import plugins.* + +plugins { + id("kotlin-library") +} + +dependencies { + compile(project(":test-fixtures")) +} + +val pluginBundles = listOf( + ":plugins", + ":plugins-experiments") + +pluginBundles.forEach { + evaluationDependsOn(it) +} + +val futurePluginVersionsTasks = + pluginBundles.map { + project(it).tasks["writeFuturePluginVersions"] as WriteProperties + } + +val customInstallation by rootProject.tasks + +tasks { + + "test" { + dependsOn(customInstallation) + pluginBundles.forEach { + dependsOn(":$it:publishPluginsToTestRepository") + } + } + + + val processTestResources by getting(ProcessResources::class) + + val writeFuturePluginVersions by creating { + + group = "build" + description = "Merges all future plugin bundle versions so they can all be tested at once" + + dependsOn(futurePluginVersionsTasks) + inputs.files(futurePluginVersionsTasks.map { it.outputFile }) + outputs.file(processTestResources.futurePluginVersionsFile) + + doLast { + outputs.files.singleFile.bufferedWriter().use { writer -> + inputs.files.forEach { input -> + writer.appendln(input.readText()) + } + } + } + } + + processTestResources.dependsOn(writeFuturePluginVersions) +} + +withParallelTests() Index: subprojects/integ-tests/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginIntegrationTest.kt =================================================================== diff -u -N --- subprojects/integ-tests/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginIntegrationTest.kt (revision 0) +++ subprojects/integ-tests/src/test/kotlin/org/gradle/kotlin/dsl/integration/PrecompiledScriptPluginIntegrationTest.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,38 @@ +package org.gradle.kotlin.dsl.integration + +import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest + +import org.junit.Test + + +class PrecompiledScriptPluginIntegrationTest : AbstractPluginTest() { + + @Test + fun `generated code follows kotlin-dsl coding conventions`() { + + withBuildScript(""" + plugins { + `kotlin-dsl` + `java-gradle-plugin` + id("org.gradle.kotlin.ktlint-convention") + } + + apply() + + repositories { jcenter() } + """) + + withFile("src/main/kotlin/plugin-without-package.gradle.kts") + withFile("src/main/kotlin/plugins/plugin-with-package.gradle.kts", """ + package plugins + """) + + build("generateScriptPluginAdapters") + build("ktlintC") + } + + override val testRepositoryPaths: List + get() = normalisedPathsOf( + "../plugins/build/repository", + "../plugins-experiments/build/repository") +} Index: subprojects/plugins-experiments/.gitignore =================================================================== diff -u -N --- subprojects/plugins-experiments/.gitignore (revision 0) +++ subprojects/plugins-experiments/.gitignore (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,2 @@ +/build +/out Index: subprojects/plugins-experiments/build.gradle.kts =================================================================== diff -u -N --- subprojects/plugins-experiments/build.gradle.kts (revision 0) +++ subprojects/plugins-experiments/build.gradle.kts (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,88 @@ +import build.futureKotlin +import plugins.bundledGradlePlugin +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.gradle.internal.hash.Hashing + +plugins { + id("kotlin-dsl-plugin-bundle") + id("com.github.johnrengelman.shadow") version "2.0.2" apply false +} + +base { + archivesBaseName = "gradle-kotlin-dsl-plugins-experiments" +} + +repositories { + gradlePluginPortal() +} + +dependencies { + compileOnly(gradleKotlinDsl()) + + implementation("gradle.plugin.org.jlleitschuh.gradle:ktlint-gradle:3.3.0") + implementation(futureKotlin("stdlib-jdk8")) + + testImplementation(project(":test-fixtures")) +} + + +// plugins ------------------------------------------------------------ + +bundledGradlePlugin( + name = "ktlintConvention", + shortDescription = "Gradle Kotlin DSL ktlint convention plugin (experimental)", + pluginId = "org.gradle.kotlin.ktlint-convention", + pluginClass = "org.gradle.kotlin.dsl.experiments.plugins.GradleKotlinDslKtlintConventionPlugin") + + +// default versions --------------------------------------------------- + +val ktlintVersion = "0.22.0" + +val basePackagePath = "org/gradle/kotlin/dsl/experiments/plugins" +val processResources: ProcessResources by tasks +val writeDefaultVersionsProperties by tasks.creating(WriteProperties::class) { + outputFile = processResources.destinationDir.resolve("$basePackagePath/default-versions.properties") + property("ktlint", ktlintVersion) +} +processResources.dependsOn(writeDefaultVersionsProperties) + + +// ktlint custom ruleset ---------------------------------------------- + +val ruleset by java.sourceSets.creating +val rulesetShaded by configurations.creating +val rulesetCompileOnly by configurations.getting { + extendsFrom(rulesetShaded) +} + +val generatedResourcesRulesetJarDir = file("$buildDir/generated-resources/ruleset/resources") +val rulesetJar by tasks.creating(ShadowJar::class) { + archiveName = "gradle-kotlin-dsl-ruleset.jar" + destinationDir = generatedResourcesRulesetJarDir.resolve(basePackagePath) + configurations = listOf(rulesetShaded) + from(ruleset.output) +} +val rulesetChecksum by tasks.creating { + dependsOn(rulesetJar) + val rulesetChecksumFile = generatedResourcesRulesetJarDir + .resolve(basePackagePath) + .resolve("gradle-kotlin-dsl-ruleset.md5") + inputs.file(rulesetJar.archivePath) + outputs.file(rulesetChecksumFile) + doLast { + rulesetChecksumFile.parentFile.mkdirs() + rulesetChecksumFile.writeText(Hashing.md5().hashBytes(rulesetJar.archivePath.readBytes()).toString()) + } +} +java.sourceSets["main"].output.dir( + mapOf("builtBy" to listOf(rulesetJar, rulesetChecksum)), + generatedResourcesRulesetJarDir) + +dependencies { + rulesetShaded("com.github.shyiko.ktlint:ktlint-ruleset-standard:$ktlintVersion") { + isTransitive = false + } + rulesetCompileOnly("com.github.shyiko.ktlint:ktlint-core:$ktlintVersion") + rulesetCompileOnly(futureKotlin("reflect")) +} Index: subprojects/plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPlugin.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPlugin.kt (revision 0) +++ subprojects/plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPlugin.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,137 @@ +package org.gradle.kotlin.dsl.experiments.plugins + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.execution.TaskExecutionListener +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.TaskState + +import org.gradle.cache.internal.GeneratedGradleJarCache +import org.gradle.internal.logging.ConsoleRenderer + +import org.jlleitschuh.gradle.ktlint.KtlintExtension +import org.jlleitschuh.gradle.ktlint.reporter.ReporterType + +import org.gradle.kotlin.dsl.* +import org.gradle.kotlin.dsl.support.serviceOf + + +private +val rulesetChecksum by lazy { + GradleKotlinDslKtlintConventionPlugin::class.java.getResource("gradle-kotlin-dsl-ruleset.md5").readText() +} + + +private +val rulesetJar by lazy { + GradleKotlinDslKtlintConventionPlugin::class.java.getResource("gradle-kotlin-dsl-ruleset.jar") +} + + +open class GradleKotlinDslKtlintConventionPlugin : Plugin { + + override fun apply(project: Project): Unit = project.run { + + plugins.apply("org.jlleitschuh.gradle.ktlint") + + configure { + version = DefaultVersions.ktlint + reporters = arrayOf(ReporterType.PLAIN) + } + + val ktlint by configurations.creating { + exclude(module = "ktlint-ruleset-standard") + } + + dependencies { + ktlint(files(gradleKotlinDslKtlintRulesetJar())) + ktlint(kotlin("reflect")) + } + + plugins.withId("kotlin") { + afterEvaluate { + fixKtlintTasks() + } + } + } + + + private + fun Project.gradleKotlinDslKtlintRulesetJar() = provider { + serviceOf().get("ktlint-convention-ruleset-$rulesetChecksum") { jar -> + jar.outputStream().use { it.write(rulesetJar.readBytes()) } + } + } + + + // Note that below are workarounds, not how things should be fixed upstream + // https://github.com/JLLeitschuh/ktlint-gradle/issues/67 + // https://github.com/JLLeitschuh/ktlint-gradle/issues/51 + private + fun Project.fixKtlintTasks() { + val reporters = the().reporters + val ktLintCheckTasks = collectKtLintCheckTasks() + fixKtlintCheckTaskCacheability(ktLintCheckTasks, reporters) + displayLinkToReportsOnFailure(ktLintCheckTasks, reporters) + } + + + private + fun Project.collectKtLintCheckTasks() = + the().sourceSets.mapNotNull { sourceSet -> + (tasks.findByName("ktlint${sourceSet.name.capitalize()}Check") as? JavaExec)?.let { task -> + Pair(sourceSet, task) + } + } + + + private + fun Project.fixKtlintCheckTaskCacheability( + tasksBySourceSets: List>, + reporters: Array + ) = + + tasksBySourceSets.forEach { (sourceSet, task) -> + + sourceSet.allSource.sourceDirectories.forEach { _ -> + reporters.forEach { + task.outputs.file("$buildDir/${it.reportPathFor(sourceSet)}") + } + task.outputs.cacheIf { true } + } + } + + + private + fun Project.displayLinkToReportsOnFailure( + tasksBySourceSets: List>, + reporters: Array + ) = + + gradle.taskGraph.addTaskExecutionListener(object : TaskExecutionListener { + + val consoleRenderer = ConsoleRenderer() + + override fun beforeExecute(aTask: Task) = Unit + + override fun afterExecute(aTask: Task, state: TaskState) { + if (state.failure != null) { + tasksBySourceSets.find { it.second == aTask }?.let { (sourceSet, _) -> + val message = "ktlint check failed\n\n" + reporters.map { + file("$buildDir/${it.reportPathFor(sourceSet)}") + }.joinToString(separator = "\n") { + consoleRenderer.asClickableFileUrl(it).prependIndent() + } + '\n' + logger.error(message) + } + } + } + }) + + private + fun ReporterType.reportPathFor(sourceSet: SourceSet) = + "reports/ktlint/ktlint-${sourceSet.name}.$fileExtension" +} Index: subprojects/plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/default-versions.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/default-versions.kt (revision 0) +++ subprojects/plugins-experiments/src/main/kotlin/org/gradle/kotlin/dsl/experiments/plugins/default-versions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,19 @@ +package org.gradle.kotlin.dsl.experiments.plugins + +import java.util.Properties + + +internal +object DefaultVersions { + + val ktlint: String by DEFAULT_VERSIONS +} + + +private +val DEFAULT_VERSIONS = + Properties().also { props -> + DefaultVersions::javaClass.get().getResourceAsStream("default-versions.properties")!!.use { input -> + props.load(input) + } + } Index: subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/BlankLinesRule.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/BlankLinesRule.kt (revision 0) +++ subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/BlankLinesRule.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,74 @@ +package org.gradle.kotlin.dsl.ktlint.ruleset + +import com.github.shyiko.ktlint.core.Rule + +import org.jetbrains.kotlin.com.intellij.lang.ASTNode +import org.jetbrains.kotlin.com.intellij.psi.PsiComment +import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement +import org.jetbrains.kotlin.com.intellij.psi.stubs.IStubElementType +import org.jetbrains.kotlin.com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.kdoc.psi.api.KDoc +import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes + +import kotlin.reflect.KClass + + +class BlankLinesRule : Rule("gradle-kotlin-dsl-blank-lines") { + + companion object { + + private + val ignoredTopLevelElementTypes = listOf>( + KtStubElementTypes.FILE_ANNOTATION_LIST, + KtStubElementTypes.IMPORT_LIST, + KtStubElementTypes.PACKAGE_DIRECTIVE) + + private + val ignoredTopLevelPsiTypes = listOf>( + PsiComment::class, + KDoc::class) + } + + private + var skippedFirstTopLevelWhiteSpace = false + + override fun visit( + node: ASTNode, + autoCorrect: Boolean, + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit + ) { + + if (node is PsiWhiteSpace) { + + val split = node.getText().split("\n") + + // Not more than 2 blank lines anywhere in the file + if (split.size > 4 || split.size == 3 && PsiTreeUtil.nextLeaf(node) == null /* eof */) { + emit(node.startOffset + split[0].length + split[1].length + 2, "Needless blank line(s)", true) + if (autoCorrect) { + (node as LeafPsiElement) + .rawReplaceWithText("${split.first()}\n${if (split.size > 3) "\n" else ""}${split.last()}") + } + } + + // Two blank lines before top level elements + if (node.treeParent.elementType == KtStubElementTypes.FILE) { + if (!skippedFirstTopLevelWhiteSpace) { + skippedFirstTopLevelWhiteSpace = true + return + } + } + + if (node.treeParent.elementType == KtStubElementTypes.FILE + && node.treeNext != null + && node.treeNext.elementType !in ignoredTopLevelElementTypes + && ignoredTopLevelPsiTypes.none { it.isInstance(node.treeNext) } + && PsiTreeUtil.nextLeaf(node) != null /* not oef */ + && split.size < 4) { + + emit(node.startOffset, "Top level elements must be separated by two blank lines", false) + } + } + } +} Index: subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomChainWrappingRule.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomChainWrappingRule.kt (revision 0) +++ subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomChainWrappingRule.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,54 @@ +package org.gradle.kotlin.dsl.ktlint.ruleset + +import com.github.shyiko.ktlint.core.Rule + +import org.jetbrains.kotlin.com.intellij.lang.ASTNode +import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement +import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl +import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.psiUtil.nextLeaf +import org.jetbrains.kotlin.psi.psiUtil.prevLeaf + + +// Same as upstream except it doesn't have checks for "same line tokens" +class CustomChainWrappingRule : Rule("gradle-kotlin-dsl-chain-wrapping") { + + private + val nextLineTokens = TokenSet.create(KtTokens.DOT, KtTokens.SAFE_ACCESS, KtTokens.ELVIS) + + private + val noSpaceAroundTokens = TokenSet.create(KtTokens.DOT, KtTokens.SAFE_ACCESS) + + override fun visit( + node: ASTNode, + autoCorrect: Boolean, + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit + ) { + /* + org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement (DOT) | "." + org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl (WHITE_SPACE) | "\n " + org.jetbrains.kotlin.psi.KtCallExpression (CALL_EXPRESSION) + */ + val elementType = node.elementType + if (nextLineTokens.contains(elementType)) { + val nextLeaf = node.psi.nextLeaf(true) + if (nextLeaf is PsiWhiteSpaceImpl && nextLeaf.textContains('\n')) { + emit(node.startOffset, "Line must not end with \"${node.text}\"", true) + if (autoCorrect) { + val prevLeaf = node.psi.prevLeaf(true) + if (prevLeaf is PsiWhiteSpaceImpl) { + prevLeaf.rawReplaceWithText(nextLeaf.text) + } else { + (node.psi as LeafPsiElement).rawInsertBeforeMe(PsiWhiteSpaceImpl(nextLeaf.text)) + } + if (noSpaceAroundTokens.contains(elementType)) { + nextLeaf.node.treeParent.removeChild(nextLeaf.node) + } else { + nextLeaf.rawReplaceWithText(" ") + } + } + } + } + } +} Index: subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomImportsRule.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomImportsRule.kt (revision 0) +++ subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/CustomImportsRule.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,37 @@ +package org.gradle.kotlin.dsl.ktlint.ruleset + +import com.github.shyiko.ktlint.core.Rule + +import org.jetbrains.kotlin.com.intellij.lang.ASTNode +import org.jetbrains.kotlin.psi.KtImportDirective +import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes + + +private +val allowedWildcardImports = listOf( + + "java.util.*", + "org.gradle.kotlin.dsl.*", + + "org.junit.Assert.*", + "org.hamcrest.CoreMatchers.*", + "com.nhaarman.mockito_kotlin.*" +) + + +class CustomImportsRule : Rule("gradle-kotlin-dsl-imports") { + + override fun visit( + node: ASTNode, + autoCorrect: Boolean, + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit + ) { + if (node.elementType == KtStubElementTypes.IMPORT_DIRECTIVE) { + val importDirective = node.psi as KtImportDirective + val path = importDirective.importPath?.pathStr + if (path != null && path.contains('*') && path !in allowedWildcardImports) { + emit(node.startOffset, "Wildcard import not allowed ($path)", false) + } + } + } +} Index: subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/GradleKotlinDslRuleSetProvider.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/GradleKotlinDslRuleSetProvider.kt (revision 0) +++ subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/GradleKotlinDslRuleSetProvider.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,82 @@ +package org.gradle.kotlin.dsl.ktlint.ruleset + +import com.github.shyiko.ktlint.core.RuleSet +import com.github.shyiko.ktlint.core.RuleSetProvider +import com.github.shyiko.ktlint.ruleset.standard.FinalNewlineRule +import com.github.shyiko.ktlint.ruleset.standard.IndentationRule +import com.github.shyiko.ktlint.ruleset.standard.MaxLineLengthRule +import com.github.shyiko.ktlint.ruleset.standard.ModifierOrderRule +import com.github.shyiko.ktlint.ruleset.standard.NoBlankLineBeforeRbraceRule +import com.github.shyiko.ktlint.ruleset.standard.NoEmptyClassBodyRule +import com.github.shyiko.ktlint.ruleset.standard.NoLineBreakAfterElseRule +import com.github.shyiko.ktlint.ruleset.standard.NoLineBreakBeforeAssignmentRule +import com.github.shyiko.ktlint.ruleset.standard.NoMultipleSpacesRule +import com.github.shyiko.ktlint.ruleset.standard.NoSemicolonsRule +import com.github.shyiko.ktlint.ruleset.standard.NoTrailingSpacesRule +import com.github.shyiko.ktlint.ruleset.standard.NoUnitReturnRule +import com.github.shyiko.ktlint.ruleset.standard.NoUnusedImportsRule +import com.github.shyiko.ktlint.ruleset.standard.ParameterListWrappingRule +import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundColonRule +import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundCommaRule +import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundCurlyRule +import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundKeywordRule +import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundOperatorsRule +import com.github.shyiko.ktlint.ruleset.standard.SpacingAroundRangeOperatorRule +import com.github.shyiko.ktlint.ruleset.standard.StringTemplateRule + + +/** + * Gradle Kotlin DSL ktlint RuleSetProvider. + * + * Reuse ktlint-standard-ruleset rules and add custom ones. + */ +class GradleKotlinDslRuleSetProvider : RuleSetProvider { + + override fun get(): RuleSet = + RuleSet( + "gradle-kotlin-dsl", + + // ktlint standard ruleset rules -------------------------- + // See https://github.com/shyiko/ktlint/blob/master/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/StandardRuleSetProvider.kt + + // kotlin-dsl: disabled in favor of CustomChainWrappingRule + // ChainWrappingRule(), + FinalNewlineRule(), + // disabled until it's clear how to reconcile difference in Intellij & Android Studio import layout + // ImportOrderingRule(), + IndentationRule(), + MaxLineLengthRule(), + ModifierOrderRule(), + NoBlankLineBeforeRbraceRule(), + // kotlin-dsl disabled in favor of BlankLinesRule + // NoConsecutiveBlankLinesRule(), + NoEmptyClassBodyRule(), + // disabled until it's clear what to do in case of `import _.it` + // NoItParamInMultilineLambdaRule(), + NoLineBreakAfterElseRule(), + NoLineBreakBeforeAssignmentRule(), + NoMultipleSpacesRule(), + NoSemicolonsRule(), + NoTrailingSpacesRule(), + NoUnitReturnRule(), + NoUnusedImportsRule(), + // kotlin-dsl: disabled in favor of CustomImportsRule + // NoWildcardImportsRule(), + ParameterListWrappingRule(), + SpacingAroundColonRule(), + SpacingAroundCommaRule(), + SpacingAroundCurlyRule(), + SpacingAroundKeywordRule(), + SpacingAroundOperatorsRule(), + SpacingAroundRangeOperatorRule(), + StringTemplateRule(), + + // gradle-kotlin-dsl rules -------------------------------- + + BlankLinesRule(), + CustomChainWrappingRule(), + CustomImportsRule(), + VisibilityModifiersOwnLineRule(), + PropertyAccessorOnNewLine() + ) +} Index: subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/PropertyAccessorOnNewLine.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/PropertyAccessorOnNewLine.kt (revision 0) +++ subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/PropertyAccessorOnNewLine.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,22 @@ +package org.gradle.kotlin.dsl.ktlint.ruleset + +import com.github.shyiko.ktlint.core.Rule +import org.jetbrains.kotlin.KtNodeTypes + +import org.jetbrains.kotlin.com.intellij.lang.ASTNode + + +class PropertyAccessorOnNewLine : Rule("property-get-new-line") { + + override fun visit( + node: ASTNode, + autoCorrect: Boolean, + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit + ) { + if (node.elementType == KtNodeTypes.PROPERTY_ACCESSOR) { + if (!node.treePrev.text.contains("\n")) { + emit(node.startOffset, "Property accessor must be on a new line", false) + } + } + } +} Index: subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/VisibilityModifiersOwnLineRule.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/VisibilityModifiersOwnLineRule.kt (revision 0) +++ subprojects/plugins-experiments/src/ruleset/kotlin/org/gradle/kotlin/dsl/ktlint/ruleset/VisibilityModifiersOwnLineRule.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,92 @@ +package org.gradle.kotlin.dsl.ktlint.ruleset + +import com.github.shyiko.ktlint.core.Rule + +import org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR +import org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER +import org.jetbrains.kotlin.com.intellij.lang.ASTNode +import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE +import org.jetbrains.kotlin.psi.KtDeclarationModifierList + + +class VisibilityModifiersOwnLineRule : Rule("visibility-modifiers-own-line") { + + private + val ownSingleLineModifierTokens = arrayOf( + KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD + ) + + private + val order = arrayOf( + KtTokens.PUBLIC_KEYWORD, + KtTokens.PROTECTED_KEYWORD, + KtTokens.PRIVATE_KEYWORD, + KtTokens.INTERNAL_KEYWORD, + KtTokens.EXPECT_KEYWORD, + KtTokens.ACTUAL_KEYWORD, + KtTokens.FINAL_KEYWORD, + KtTokens.OPEN_KEYWORD, + KtTokens.ABSTRACT_KEYWORD, + KtTokens.SEALED_KEYWORD, + KtTokens.CONST_KEYWORD, + KtTokens.EXTERNAL_KEYWORD, + KtTokens.OVERRIDE_KEYWORD, + KtTokens.LATEINIT_KEYWORD, + KtTokens.TAILREC_KEYWORD, + KtTokens.VARARG_KEYWORD, + KtTokens.SUSPEND_KEYWORD, + KtTokens.INNER_KEYWORD, + KtTokens.ENUM_KEYWORD, + KtTokens.ANNOTATION_KEYWORD, + KtTokens.COMPANION_KEYWORD, + KtTokens.INLINE_KEYWORD, + KtTokens.INFIX_KEYWORD, + KtTokens.OPERATOR_KEYWORD, + KtTokens.DATA_KEYWORD + // NOINLINE_KEYWORD, CROSSINLINE_KEYWORD, OUT_KEYWORD, IN_KEYWORD, REIFIED_KEYWORD + // HEADER_KEYWORD, IMPL_KEYWORD + ) + + private + val tokenSet = TokenSet.create(*order) + + private + val skippedParents = listOf(PRIMARY_CONSTRUCTOR, VALUE_PARAMETER) + + override fun visit( + node: ASTNode, + autoCorrect: Boolean, + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit + ) { + + if (node.psi is KtDeclarationModifierList && node.treeParent.elementType !in skippedParents) { + + val modifierArr = node.getChildren(tokenSet) + + val vizModifiers = modifierArr.filter { it.elementType in ownSingleLineModifierTokens } + + if (vizModifiers.isNotEmpty()) { + + val vizModifierExpectedText = vizModifiers.joinToString(separator = " ", postfix = "\n") { it.text } + + if (!node.textIncludingSurroundingWhitespace.contains(vizModifierExpectedText)) { + emit( + node.startOffset, + "Visibility modifiers must be on their own single line", + false + ) + } + } + } + } + + private + val ASTNode.textIncludingSurroundingWhitespace + get() = "${ + if (treePrev?.elementType == WHITE_SPACE) treePrev.text else "" + }$text${ + if (treeNext?.elementType == WHITE_SPACE) treeNext.text else "" + }" +} Index: subprojects/plugins-experiments/src/ruleset/resources/META-INF/services/com.github.shyiko.ktlint.core.RuleSetProvider =================================================================== diff -u -N --- subprojects/plugins-experiments/src/ruleset/resources/META-INF/services/com.github.shyiko.ktlint.core.RuleSetProvider (revision 0) +++ subprojects/plugins-experiments/src/ruleset/resources/META-INF/services/com.github.shyiko.ktlint.core.RuleSetProvider (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1 @@ +org.gradle.kotlin.dsl.ktlint.ruleset.GradleKotlinDslRuleSetProvider Index: subprojects/plugins-experiments/src/test/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPluginTest.kt =================================================================== diff -u -N --- subprojects/plugins-experiments/src/test/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPluginTest.kt (revision 0) +++ subprojects/plugins-experiments/src/test/kotlin/org/gradle/kotlin/dsl/experiments/plugins/GradleKotlinDslKtlintConventionPluginTest.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,265 @@ +package org.gradle.kotlin.dsl.experiments.plugins + +import org.gradle.kotlin.dsl.embeddedKotlinVersion +import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest + +import org.gradle.testkit.runner.TaskOutcome + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.CoreMatchers.containsString + +import org.junit.Assert.assertThat +import org.junit.Before +import org.junit.Test + + +class GradleKotlinDslKtlintConventionPluginTest : AbstractPluginTest() { + + @Before + fun setup() { + withBuildScript(""" + plugins { + kotlin("jvm") version "$embeddedKotlinVersion" + id("org.gradle.kotlin.ktlint-convention") + } + + repositories { + jcenter() + } + """) + } + + @Test + fun `ktlint dependencies include kotlin-reflect`() { + + assertThat( + build("dependencies", "--configuration", "ktlint").output, + containsString("org.jetbrains.kotlin:kotlin-reflect:$embeddedKotlinVersion")) + } + + @Test + fun `ktlint check tasks are cacheable`() { + + withFile("gradle.properties", "org.gradle.caching=true") + existing("settings.gradle.kts").run { + writeText(readText() + """ + buildCache { + local { isEnabled = false } + remote(DirectoryBuildCache::class.java) { + directory = file("local-build-cache") + isEnabled = true + isPush = true + } + } + """) + } + + withSource("""val foo = "bar"""") + + build("ktlintMainCheck").apply { + + assertThat(outcomeOf(":ktlintMainCheck"), equalTo(TaskOutcome.SUCCESS)) + } + + build("ktlintMainCheck").apply { + + assertThat(outcomeOf(":ktlintMainCheck"), equalTo(TaskOutcome.UP_TO_DATE)) + } + + build("clean") + + build("ktlintMainCheck").apply { + + assertThat(outcomeOf(":ktlintMainCheck"), equalTo(TaskOutcome.FROM_CACHE)) + } + } + + @Test + fun `visibility modifiers on their own single line`() { + + withSource(""" + + private val bar = false + + + class Bazar(private val name: String) { + + private lateinit + var description: String + + private inline + fun something() = Unit + } + """) + + buildAndFail("ktlintMainCheck") + + assertKtlintErrors(3) + assertKtLintError("Visibility modifiers must be on their own single line", 3, 13) + assertKtLintError("Visibility modifiers must be on their own single line", 8, 17) + assertKtLintError("Visibility modifiers must be on their own single line", 11, 17) + + withSource(""" + + private + val bar = false + + + class Bazar(private val name: String) { + + private + lateinit var description: String + + private + inline fun something() = Unit + } + """) + + build("ktlintMainCheck") + } + + @Test + fun `allowed wildcard imports`() { + + withSource(""" + + import java.util.* + import org.w3c.dom.* + + import org.gradle.kotlin.dsl.* + """) + + buildAndFail("ktlintMainCheck") + + assertKtlintErrors(1) + assertKtLintError("Wildcard import not allowed (org.w3c.dom.*)", 4, 13) + } + + @Test + fun `blank lines`() { + + withSource(""" + package some + + import org.gradle.kotlin.dsl.* + + val foo = "bar" + + interface Foo + + + + object Bar + + + data class Some(val name: String) + """) + + buildAndFail("ktlintMainCheck") + + assertKtlintErrors(3) + assertKtLintError("Top level elements must be separated by two blank lines", 4, 43) + assertKtLintError("Top level elements must be separated by two blank lines", 6, 28) + assertKtLintError("Needless blank line(s)", 10, 1) + + withSource(""" + /* + * Copyright 2016 the original author or authors. + */ + + // Random words + @file:JvmName("Something") + + /** + * Package kdoc. + */ + package some + + import org.gradle.kotlin.dsl.* + + + /* + * Some file documentation. + */ + + + val foo = "bar" + + + /** + * Interface kdoc. + */ + interface Foo + + + object Bar + + + data class Some(val name: String) + """) + + build("ktlintMainCheck") + } + + @Test + fun `new lines starting with ANDAND are allowed`() { + + withSource(""" + + val foo = "bar".isNotEmpty() + && "bazar".isNotEmpty() // either + """) + + build("ktlintMainCheck") + } + + @Test + fun `property accessors on new line`() { + + withSource(""" + + val foo get() = "bar" + + + val bar: String get() { return "bar" } + """) + + buildAndFail("ktlintMainCheck") + + assertKtlintErrors(2) + assertKtLintError("Property accessor must be on a new line", 3, 17) + assertKtLintError("Property accessor must be on a new line", 6, 25) + + withSource(""" + + val foo + get() = "bar" + + + val bar: String + get() { return "bar" } + """) + + build("ktlintMainCheck") + } + + private + fun withSource(text: String) = + withFile("src/main/kotlin/source.kt", text) + + private + val ktlintReportFile by lazy { existing("build/reports/ktlint/ktlint-main.txt") } + + private + fun assertKtlintErrors(count: Int) = + assertThat( + "ktlint error count", + ktlintReportFile.readLines().filter { it.contains("source.kt:") }.count(), + equalTo(count)) + + private + fun assertKtLintError(error: String, line: Int, column: Int) = + assertThat( + ktlintReportFile.readText(), + containsString("source.kt:$line:$column: $error")) +} Index: subprojects/plugins/.gitignore =================================================================== diff -u -N --- subprojects/plugins/.gitignore (revision 0) +++ subprojects/plugins/.gitignore (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,2 @@ +/build +/out Index: subprojects/plugins/build.gradle.kts =================================================================== diff -u -N --- subprojects/plugins/build.gradle.kts (revision 0) +++ subprojects/plugins/build.gradle.kts (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,35 @@ +import build.futureKotlin +import plugins.bundledGradlePlugin + +plugins { + id("kotlin-dsl-plugin-bundle") +} + +base { + archivesBaseName = "gradle-kotlin-dsl-plugins" +} + +dependencies { + compileOnly(project(":provider")) + + implementation(futureKotlin("stdlib-jdk8")) + implementation(futureKotlin("gradle-plugin")) + implementation(futureKotlin("sam-with-receiver")) + + testImplementation(project(":test-fixtures")) +} + + +// plugins ------------------------------------------------------------ + +bundledGradlePlugin( + name = "embeddedKotlin", + shortDescription = "Embedded Kotlin Gradle Plugin", + pluginId = "org.gradle.kotlin.embedded-kotlin", + pluginClass = "org.gradle.kotlin.dsl.plugins.embedded.EmbeddedKotlinPlugin") + +bundledGradlePlugin( + name = "kotlinDsl", + shortDescription = "Gradle Kotlin DSL Plugin", + pluginId = "org.gradle.kotlin.kotlin-dsl", + pluginClass = "org.gradle.kotlin.dsl.plugins.dsl.KotlinDslPlugin") Index: subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslCompilerPlugins.kt =================================================================== diff -u -N --- subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslCompilerPlugins.kt (revision 0) +++ subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslCompilerPlugins.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,40 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl.plugins.dsl + +import org.gradle.api.HasImplicitReceiver +import org.gradle.api.Plugin +import org.gradle.api.Project + +import org.jetbrains.kotlin.samWithReceiver.gradle.SamWithReceiverExtension +import org.jetbrains.kotlin.samWithReceiver.gradle.SamWithReceiverGradleSubplugin + + +/** + * Configures the Kotlin compiler to recognise Gradle functional interface + * annotated with [HasImplicitReceiver]. + */ +open class KotlinDslCompilerPlugins : Plugin { + + override fun apply(project: Project): Unit = project.run { + + plugins.apply(SamWithReceiverGradleSubplugin::class.java) + extensions.configure(SamWithReceiverExtension::class.java) { samWithReceiver -> + samWithReceiver.annotation(HasImplicitReceiver::class.qualifiedName!!) + } + } +} Index: subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPlugin.kt =================================================================== diff -u -N --- subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPlugin.kt (revision 0) +++ subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPlugin.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,61 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl.plugins.dsl + +import org.gradle.api.Plugin +import org.gradle.api.Project + +import org.gradle.kotlin.dsl.gradleKotlinDsl +import org.gradle.kotlin.dsl.plugins.embedded.EmbeddedKotlinPlugin + + +/** + * The `kotlin-dsl` plugin. + * + * - Applies the `embedded-kotlin` plugin + * - Adds the `gradleKotlinDsl()` dependency to the `compileOnly` and `testImplementation` configurations + * - Configures the Kotlin DSL compiler plugins + * + * @see org.gradle.kotlin.dsl.plugins.embedded.EmbeddedKotlinPlugin + */ +open class KotlinDslPlugin : Plugin { + + override fun apply(project: Project) { + project.run { + + applyEmbeddedKotlinPlugin() + applyKotlinDslCompilerPlugins() + addGradleKotlinDslDependencyTo("compileOnly", "testImplementation") + } + } + + private + fun Project.applyEmbeddedKotlinPlugin() { + plugins.apply(EmbeddedKotlinPlugin::class.java) + } + + private + fun Project.applyKotlinDslCompilerPlugins() { + plugins.apply(KotlinDslCompilerPlugins::class.java) + } + + private + fun Project.addGradleKotlinDslDependencyTo(vararg configurations: String) { + configurations.forEach { + dependencies.add(it, gradleKotlinDsl()) + } + } +} Index: subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPlugin.kt =================================================================== diff -u -N --- subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPlugin.kt (revision 0) +++ subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPlugin.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,62 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl.plugins.embedded + +import org.gradle.api.Plugin +import org.gradle.api.Project + +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper + +import org.gradle.kotlin.dsl.support.EmbeddedKotlinProvider + +import javax.inject.Inject + + +/** + * The `embedded-kotlin` plugin. + * + * Applies the `org.jetbrains.kotlin.jvm` plugin, + * adds compile only dependencies on `kotlin-stdlib` and `kotlin-reflect`, + * configures an embedded repository that contains all embedded Kotlin libraries, + * and pins them to the embedded Kotlin version. + */ +open class EmbeddedKotlinPlugin @Inject internal constructor( + private val embeddedKotlin: EmbeddedKotlinProvider +) : Plugin { + + override fun apply(project: Project) { + project.run { + + plugins.apply(KotlinPluginWrapper::class.java) + + embeddedKotlin.addRepositoryTo(repositories) + + val embeddedKotlinConfiguration = configurations.create("embeddedKotlin") + embeddedKotlin.addDependenciesTo( + dependencies, + embeddedKotlinConfiguration.name, + "stdlib-jdk8", "reflect") + + listOf("compileOnly", "testCompileOnly").forEach { + configurations.getByName(it).extendsFrom(embeddedKotlinConfiguration) + } + + configurations.all { + embeddedKotlin.pinDependenciesOn(it, "stdlib-jdk8", "reflect", "compiler-embeddable") + } + } + } +} Index: subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPlugins.kt =================================================================== diff -u -N --- subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPlugins.kt (revision 0) +++ subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPlugins.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,226 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl.plugins.precompiled + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.file.FileTree +import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.api.tasks.SourceSet + +import org.gradle.kotlin.dsl.* + +import org.gradle.kotlin.dsl.precompile.PrecompiledInitScript +import org.gradle.kotlin.dsl.precompile.PrecompiledProjectScript +import org.gradle.kotlin.dsl.precompile.PrecompiledScriptDependenciesResolver +import org.gradle.kotlin.dsl.precompile.PrecompiledSettingsScript + +import org.gradle.kotlin.dsl.support.ImplicitImports +import org.gradle.kotlin.dsl.support.serviceOf + +import org.gradle.plugin.devel.GradlePluginDevelopmentExtension +import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin + +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +import java.io.File + + +/* + * Exposes `*.gradle.kts` scripts from regular Kotlin source-sets as binary Gradle plugins. + */ +open class PrecompiledScriptPlugins : Plugin { + + override fun apply(project: Project): Unit = project.run { + + enableScriptCompilation() + + plugins.withType { + exposeScriptsAsGradlePlugins() + } + } +} + + +private +fun Project.enableScriptCompilation() { + + afterEvaluate { + + tasks { + + "compileKotlin"(KotlinCompile::class) { + kotlinOptions { + freeCompilerArgs += listOf( + "-script-templates", scriptTemplates, + // Propagate implicit imports and other settings + "-Xscript-resolver-environment=${resolverEnvironment()}" + ) + } + } + } + } +} + + +private +val scriptTemplates by lazy { + listOf( + // treat *.settings.gradle.kts files as Settings scripts + PrecompiledSettingsScript::class.qualifiedName!!, + // treat *.init.gradle.kts files as Gradle scripts + PrecompiledInitScript::class.qualifiedName!!, + // treat *.gradle.kts files as Project scripts + PrecompiledProjectScript::class.qualifiedName!! + ).joinToString(separator = ",") +} + + +private +fun Project.resolverEnvironment() = + (PrecompiledScriptDependenciesResolver.EnvironmentProperties.kotlinDslImplicitImports + + "=\"" + implicitImports().joinToString(separator = ":") + "\"") + + +private +fun Project.implicitImports(): List = + serviceOf().list + + +private +fun Project.exposeScriptsAsGradlePlugins() { + + val scriptSourceFiles = pluginSourceSet.allSource.matching { + it.include("**/*.gradle.kts") + } + + val scriptPlugins = + scriptSourceFiles.map(::ScriptPlugin) + + declareScriptPlugins(scriptPlugins) + + generatePluginAdaptersFor(scriptPlugins, scriptSourceFiles) +} + + +private +val Project.pluginSourceSet + get() = gradlePlugin.pluginSourceSet + + +private +val Project.gradlePlugin + get() = the() + + +private +fun Project.declareScriptPlugins(scriptPlugins: List) { + + configure { + for (scriptPlugin in scriptPlugins) { + plugins.create(scriptPlugin.id) { + it.id = scriptPlugin.id + it.implementationClass = scriptPlugin.implementationClass + } + } + } +} + + +private +fun Project.generatePluginAdaptersFor(scriptPlugins: List, scriptSourceFiles: FileTree) { + + tasks { + + val generatedSourcesDir = layout.buildDirectory.dir("generated-sources/kotlin-dsl-plugins/kotlin") + + sourceSets["main"].kotlin.srcDir(generatedSourcesDir) + + val generateScriptPluginAdapters by creating { + inputs.files(scriptSourceFiles) + outputs.dir(generatedSourcesDir) + doLast { + val outputDir = generatedSourcesDir.get().asFile + for (scriptPlugin in scriptPlugins) { + scriptPlugin.writeScriptPluginAdapterTo(outputDir) + } + } + } + + getByName("compileKotlin") { + it.dependsOn(generateScriptPluginAdapters) + } + } +} + + +internal +fun ScriptPlugin.writeScriptPluginAdapterTo(outputDir: File) { + + val (packageDir, packageDeclaration) = + packageName?.let { packageName -> + packageDir(outputDir, packageName) to "package $packageName" + } ?: outputDir to "" + + val outputFile = + packageDir.resolve("$simplePluginAdapterClassName.kt") + + outputFile.writeText(""" + + $packageDeclaration + + /** + * Precompiled [$scriptFileName][$compiledScriptTypeName] script plugin. + * + * @see $compiledScriptTypeName + */ + class $simplePluginAdapterClassName : org.gradle.api.Plugin<$targetType> { + override fun apply(target: $targetType) { + try { + Class + .forName("$compiledScriptTypeName") + .getDeclaredConstructor($targetType::class.java) + .newInstance(target) + } catch (e: java.lang.reflect.InvocationTargetException) { + throw e.targetException + } + } + } + + """.replaceIndent().trim() + "\n") +} + + +private +fun packageDir(outputDir: File, packageName: String) = + outputDir.mkdir(packageName.replace('.', '/')) + + +private +fun File.mkdir(relative: String) = + resolve(relative).apply { mkdirs() } + + +private +val Project.sourceSets + get() = project.the().sourceSets + + +private +val SourceSet.kotlin: SourceDirectorySet + get() = withConvention(KotlinSourceSet::class) { kotlin } Index: subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPlugin.kt =================================================================== diff -u -N --- subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPlugin.kt (revision 0) +++ subprojects/plugins/src/main/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPlugin.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,173 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl.plugins.precompiled + + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.initialization.Settings +import org.gradle.api.invocation.Gradle + +import org.gradle.kotlin.dsl.support.KotlinScriptType +import org.gradle.kotlin.dsl.support.KotlinScriptTypeMatch + +import org.gradle.util.TextUtil.normaliseLineSeparators + +import org.jetbrains.kotlin.lexer.KotlinLexer +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.NameUtils + +import java.io.File + + +internal +data class ScriptPlugin(private val scriptFile: File) { + + val scriptFileName = scriptFile.name + + /** + * Gradle plugin id inferred from the script file name and package declaration (if any). + */ + val id by lazy { + packagePrefixed(fileNameWithoutScriptExtension) + } + + /** + * Fully qualified name for the [Plugin] implementation class. + * + * The [Plugin] implementation class adapts the precompiled script class + * to the Gradle [Plugin] protocol and it is automatically generated by + * the `generateScriptPluginAdapters` task. + */ + val implementationClass by lazy { + packagePrefixed(simplePluginAdapterClassName) + } + + val simplePluginAdapterClassName by lazy { + fileNameWithoutScriptExtension + .kebabCaseToPascalCase() + .asJavaIdentifier() + "Plugin" + } + + private + val fileNameWithoutScriptExtension by lazy { + scriptFileName.removeSuffix(scriptExtension) + } + + val targetType by lazy { + when (scriptType) { + KotlinScriptType.PROJECT -> Project::class.qualifiedName + KotlinScriptType.SETTINGS -> Settings::class.qualifiedName + KotlinScriptType.INIT -> Gradle::class.qualifiedName + } + } + + private + val scriptType + get() = scriptTypeMatch.scriptType + + private + val scriptExtension + get() = scriptTypeMatch.match.value + + private + val scriptTypeMatch by lazy { + KotlinScriptTypeMatch.forName(scriptFileName)!! + } + + /** + * Fully qualified name + */ + val compiledScriptTypeName by lazy { + packagePrefixed(scriptClassNameForFile(scriptFile)) + } + + val packageName: String? by lazy { + packageNameOf(scriptFile) + } + + private + fun packagePrefixed(id: String) = + packageName?.let { "$it.$id" } ?: id +} + + +private +fun packageNameOf(file: File): String? = + packageNameOf(normaliseLineSeparators(file.readText())) + + +private +fun packageNameOf(code: String): String? = + KotlinLexer().run { + start(code) + skipWhiteSpaceAndComments() + when (tokenType) { + KtTokens.PACKAGE_KEYWORD -> { + advance() + skipWhiteSpaceAndComments() + parseQualifiedName() + } + else -> null + } + } + + +private +fun KotlinLexer.parseQualifiedName(): String = + StringBuilder().run { + while (tokenType == KtTokens.IDENTIFIER || tokenType == KtTokens.DOT) { + append(tokenText) + advance() + } + toString() + } + + +private +fun KotlinLexer.skipWhiteSpaceAndComments() { + while (tokenType in KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET) { + advance() + } +} + + +private +fun scriptClassNameForFile(file: File) = + NameUtils.getScriptNameForFile(file.name).asString() + + +private +fun CharSequence.kebabCaseToPascalCase() = + kebabCaseToCamelCase().capitalize() + + +private +fun CharSequence.kebabCaseToCamelCase() = + replace("-[a-z]".toRegex()) { it.value.drop(1).toUpperCase() } + + +private +fun CharSequence.asJavaIdentifier() = + replaceBy { if (it.isJavaIdentifierPart()) it else '_' } + + +private +inline fun CharSequence.replaceBy(f: (Char) -> Char) = + StringBuilder(length).let { builder -> + forEach { char -> builder.append(f(char)) } + builder.toString() + } Index: subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPluginTest.kt =================================================================== diff -u -N --- subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPluginTest.kt (revision 0) +++ subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/dsl/KotlinDslPluginTest.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,240 @@ +package org.gradle.kotlin.dsl.plugins.dsl + +import org.gradle.kotlin.dsl.fixtures.customDaemonRegistry +import org.gradle.kotlin.dsl.fixtures.customInstallation +import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest + +import org.gradle.testkit.runner.TaskOutcome + +import org.hamcrest.CoreMatchers.containsString +import org.hamcrest.CoreMatchers.equalTo + +import org.junit.Assert.assertThat +import org.junit.Test + +import java.io.File + + +class KotlinDslPluginTest : AbstractPluginTest() { + + @Test + fun `gradle kotlin dsl api dependency is added`() { + + withBuildScript(""" + + plugins { + `kotlin-dsl` + } + + """) + + withFile("src/main/kotlin/code.kt", """ + + // src/main/kotlin + import org.gradle.kotlin.dsl.GradleDsl + + // src/generated + import org.gradle.kotlin.dsl.embeddedKotlinVersion + + """) + + val result = buildWithPlugin("classes") + + assertThat(result.outcomeOf(":compileKotlin"), equalTo(TaskOutcome.SUCCESS)) + } + + @Test + fun `gradle kotlin dsl api is available for test implementation`() { + withBuildScript(""" + + plugins { + `java-gradle-plugin` + `kotlin-dsl` + } + + repositories { + jcenter() + } + + dependencies { + testCompile("junit:junit:4.12") + } + + """) + + withFile("src/main/kotlin/code.kt", """ + + import org.gradle.api.Plugin + import org.gradle.api.Project + import org.gradle.kotlin.dsl.embeddedKotlinVersion + + class MyPlugin : Plugin { + override fun apply(project: Project) { + project.run { + println("Plugin Using Embedded Kotlin " + embeddedKotlinVersion) + } + } + } + """) + + withFile("src/test/kotlin/test.kt", """ + + import org.gradle.testfixtures.ProjectBuilder + import org.junit.Test + import org.gradle.kotlin.dsl.* + + class MyTest { + + @Test + fun `my test`() { + ProjectBuilder.builder().build().run { + apply() + } + } + } + """) + + assertThat( + outputOf("test", "-i"), + containsString("Plugin Using Embedded Kotlin ")) + } + + @Test + fun `gradle kotlin dsl api is available in test-kit injected plugin classpath`() { + + withBuildScript(""" + + plugins { + `java-gradle-plugin` + `kotlin-dsl` + } + + repositories { + jcenter() + } + + dependencies { + testCompile("junit:junit:4.12") + testCompile(gradleTestKit()) + } + + gradlePlugin { + (plugins) { + "myPlugin" { + id = "my-plugin" + implementationClass = "my.MyPlugin" + } + } + } + + """) + + withFile("src/main/kotlin/my/code.kt", """ + package my + + import org.gradle.api.* + import org.gradle.kotlin.dsl.* + + class MyPlugin : Plugin { + override fun apply(project: Project) { + println("Plugin Using Embedded Kotlin " + embeddedKotlinVersion) + } + } + """) + + withFile("src/test/kotlin/test.kt", """ + + import java.io.File + + import org.gradle.testkit.runner.GradleRunner + + import org.hamcrest.CoreMatchers.containsString + import org.junit.Assert.assertThat + + import org.junit.Rule + import org.junit.Test + import org.junit.rules.TemporaryFolder + + class MyTest { + + @JvmField @Rule val temporaryFolder = TemporaryFolder() + + val projectRoot by lazy { + File(temporaryFolder.root, "test").apply { mkdirs() } + } + + @Test + fun `my test`() { + // given: + File(projectRoot, "build.gradle.kts") + .writeText("plugins { id(\"my-plugin\") }") + + // and: + System.setProperty("org.gradle.daemon.idletimeout", "1000") + System.setProperty("org.gradle.daemon.registry.base", "${escapedPathOf(customDaemonRegistry())}") + File(projectRoot, "gradle.properties").writeText("org.gradle.jvmargs=-Xmx128m") + + // and: + val runner = GradleRunner.create() + .withGradleInstallation(File("${escapedPathOf(customInstallation())}")) + .withProjectDir(projectRoot) + .withPluginClasspath() + .forwardOutput() + + // when: + val result = runner.withArguments("help").build() + + // then: + assertThat(result.output, containsString("Plugin Using Embedded Kotlin ")) + } + } + + """) + + assertThat( + outputOf("test", "-i"), + containsString("Plugin Using Embedded Kotlin ")) + } + + @Test + fun `sam-with-receiver kotlin compiler plugin is applied to production code`() { + + withBuildScript(""" + + plugins { + `kotlin-dsl` + } + + """) + + withFile("src/main/kotlin/code.kt", """ + + import org.gradle.api.Plugin + import org.gradle.api.Project + + class MyPlugin : Plugin { + override fun apply(project: Project) { + project.run { + copy { + from("build.gradle.kts") + into("build/build.gradle.kts.copy") + } + } + } + } + + """) + + val result = buildWithPlugin("classes") + + assertThat(result.outcomeOf(":compileKotlin"), equalTo(TaskOutcome.SUCCESS)) + } + + private + fun escapedPathOf(file: File) = + file.absolutePath.replace("\\", "\\\\") + + private + fun outputOf(vararg arguments: String) = + buildWithPlugin(*arguments).output +} Index: subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPluginTest.kt =================================================================== diff -u -N --- subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPluginTest.kt (revision 0) +++ subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/embedded/EmbeddedKotlinPluginTest.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,268 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl.plugins.embedded + +import org.gradle.kotlin.dsl.embeddedKotlinVersion +import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest + +import org.gradle.testkit.runner.TaskOutcome + +import org.hamcrest.CoreMatchers.containsString +import org.hamcrest.CoreMatchers.equalTo + +import org.junit.Assert.assertThat +import org.junit.Test + + +class EmbeddedKotlinPluginTest : AbstractPluginTest() { + + @Test + fun `applies the kotlin plugin`() { + + withBuildScript(""" + + plugins { + `embedded-kotlin` + } + + """) + + val result = buildWithPlugin("assemble") + + assertThat(result.outcomeOf(":compileKotlin"), equalTo(TaskOutcome.NO_SOURCE)) + } + + @Test + fun `adds stdlib and reflect as compile only dependencies`() { + withBuildScript(""" + + plugins { + `embedded-kotlin` + } + + tasks { + "assertions" { + doLast { + val requiredLibs = listOf("kotlin-stdlib-jdk8-$embeddedKotlinVersion.jar", "kotlin-reflect-$embeddedKotlinVersion.jar") + listOf("compileOnly", "testCompileOnly").forEach { configuration -> + require(configurations[configuration].files.map { it.name }.containsAll(requiredLibs), { + "Embedded Kotlin libraries not found in ${'$'}configuration" + }) + } + } + } + } + + """) + + buildWithPlugin("assertions") + } + + @Test + fun `all embedded kotlin dependencies are resolvable without any added repository`() { + + withBuildScript(""" + + plugins { + `embedded-kotlin` + } + + dependencies { + ${dependencyDeclarationsFor("compile", listOf("compiler-embeddable"))} + } + + println(repositories.map { it.name }) + configurations["compileClasspath"].files.map { println(it) } + + """) + + val result = buildWithPlugin("dependencies") + + assertThat(result.output, containsString("Embedded Kotlin Repository")) + listOf("stdlib", "reflect", "compiler-embeddable").forEach { + assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) + } + } + + @Test + fun `sources and javadoc of all embedded kotlin dependencies are resolvable with an added repository`() { + + withBuildScript(""" + + plugins { + `embedded-kotlin` + } + + repositories { + jcenter() + } + + dependencies { + ${dependencyDeclarationsFor("compile", listOf("stdlib", "reflect"))} + } + + configurations["compileClasspath"].files.forEach { + println(it) + } + + val components = + configurations + .compile + .incoming + .artifactView { lenient(true) } + .artifacts + .map { it.id.componentIdentifier } + + val resolvedComponents = + dependencies + .createArtifactResolutionQuery() + .forComponents(*components.toTypedArray()) + .withArtifacts( + JvmLibrary::class.java, + SourcesArtifact::class.java, + JavadocArtifact::class.java) + .execute() + .resolvedComponents + + inline fun printFileNamesOf() = + resolvedComponents + .flatMap { it.getArtifacts(T::class.java) } + .filterIsInstance() + .forEach { println(it.file.name) } + + printFileNamesOf() + printFileNamesOf() + """) + + val result = buildWithPlugin("help") + + listOf("stdlib", "reflect").forEach { + assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) + assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion-sources.jar")) + assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion-javadoc.jar")) + } + } + + @Test + fun `embedded kotlin modules versions are pinned to the embedded Kotlin version`() { + + withBuildScript(""" + + plugins { + `embedded-kotlin` + } + + repositories { + jcenter() + } + + dependencies { + ${dependencyDeclarationsFor("compile", listOf("stdlib", "reflect", "compiler-embeddable"), "1.1.1")} + compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:0.15") + } + + configurations["compileClasspath"].files.map { println(it) } + + """) + + val result = buildWithPlugin("dependencies") + + listOf("stdlib", "reflect", "compiler-embeddable").forEach { + assertThat(result.output, containsString("org.jetbrains.kotlin:kotlin-$it:1.1.1 -> $embeddedKotlinVersion")) + assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) + } + } + + @Test + fun `can add embedded dependencies to custom configuration`() { + + withBuildScript(""" + + plugins { + `embedded-kotlin` + } + + val customConfiguration by configurations.creating + customConfiguration.extendsFrom(configurations["embeddedKotlin"]) + + configurations["customConfiguration"].files.map { println(it) } + """) + + val result = buildWithPlugin("dependencies", "--configuration", "customConfiguration") + + listOf("stdlib", "reflect").forEach { + assertThat(result.output, containsString("org.jetbrains.kotlin:kotlin-$it:$embeddedKotlinVersion")) + assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) + } + } + + @Test + fun `embedded kotlin dependencies are pinned on custom configurations too`() { + withBuildScript(""" + + plugins { + `embedded-kotlin` + } + + val customConfiguration by configurations.creating + customConfiguration.extendsFrom(configurations["embeddedKotlin"]) + + dependencies { + ${dependencyDeclarationsFor("customConfiguration", listOf("stdlib", "reflect", "compiler-embeddable"), "1.1.1")} + customConfiguration("org.jetbrains.kotlinx:kotlinx-coroutines-core:0.15") + } + + repositories { + jcenter() + } + + configurations["customConfiguration"].files.map { println(it) } + """) + + val result = buildWithPlugin("dependencies", "--configuration", "customConfiguration") + + listOf("stdlib", "reflect", "compiler-embeddable").forEach { + assertThat(result.output, containsString("org.jetbrains.kotlin:kotlin-$it:1.1.1 -> $embeddedKotlinVersion")) + assertThat(result.output, containsString("kotlin-$it-$embeddedKotlinVersion.jar")) + } + } + + @Test + fun `can be used with GRADLE_METADATA feature preview enabled`() { + + withSettings("""enableFeaturePreview("GRADLE_METADATA")""") + + withBuildScript(""" + + plugins { + `embedded-kotlin` + } + + """) + + withFile("src/main/kotlin/source.kt", """var foo = "bar"""") + + val result = buildWithPlugin("assemble") + + assertThat(result.outcomeOf(":compileKotlin"), equalTo(TaskOutcome.SUCCESS)) + } + + private + fun dependencyDeclarationsFor(configuration: String, modules: List, version: String? = null) = + modules.map { + "$configuration(\"org.jetbrains.kotlin:kotlin-$it:${version ?: embeddedKotlinVersion}\")" + }.joinToString("\n") +} Index: subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPluginTest.kt =================================================================== diff -u -N --- subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPluginTest.kt (revision 0) +++ subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/PrecompiledScriptPluginTest.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,374 @@ +package org.gradle.kotlin.dsl.plugins.precompiled + +import com.nhaarman.mockito_kotlin.doReturn +import com.nhaarman.mockito_kotlin.mock +import com.nhaarman.mockito_kotlin.verify + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.initialization.Settings +import org.gradle.api.invocation.Gradle +import org.gradle.api.tasks.TaskContainer + +import org.gradle.kotlin.dsl.fixtures.AbstractPluginTest +import org.gradle.kotlin.dsl.fixtures.LeaksFileHandles +import org.gradle.kotlin.dsl.fixtures.assertFailsWith +import org.gradle.kotlin.dsl.fixtures.assertInstanceOf +import org.gradle.kotlin.dsl.fixtures.classLoaderFor +import org.gradle.kotlin.dsl.fixtures.joinLines +import org.gradle.kotlin.dsl.fixtures.withFolders + +import org.gradle.kotlin.dsl.precompile.PrecompiledInitScript +import org.gradle.kotlin.dsl.precompile.PrecompiledProjectScript +import org.gradle.kotlin.dsl.precompile.PrecompiledSettingsScript + +import org.gradle.testkit.runner.TaskOutcome + +import org.hamcrest.CoreMatchers.allOf +import org.hamcrest.CoreMatchers.containsString +import org.hamcrest.CoreMatchers.equalTo + +import org.hamcrest.MatcherAssert.assertThat +import org.junit.Test + + +class PrecompiledScriptPluginTest : AbstractPluginTest() { + + @Test + fun `Project scripts from regular source-sets are compiled via the PrecompiledProjectScript template`() { + + givenPrecompiledKotlinScript("my-project-script.gradle.kts", """ + + task("my-task") + + """) + + val project = mock() + + assertInstanceOf( + instantiatePrecompiledScriptOf( + project, + "My_project_script_gradle")) + + verify(project).task("my-task") + } + + @Test + fun `Settings scripts from regular source-sets are compiled via the PrecompiledSettingsScript template`() { + + givenPrecompiledKotlinScript("my-settings-script.settings.gradle.kts", """ + + include("my-project") + + """) + + val settings = mock() + + assertInstanceOf( + instantiatePrecompiledScriptOf( + settings, + "My_settings_script_settings_gradle")) + + verify(settings).include("my-project") + } + + @Test + fun `Gradle scripts from regular source-sets are compiled via the PrecompiledInitScript template`() { + + givenPrecompiledKotlinScript("my-gradle-script.init.gradle.kts", """ + + useLogger("my-logger") + + """) + + val gradle = mock() + + assertInstanceOf( + instantiatePrecompiledScriptOf( + gradle, + "My_gradle_script_init_gradle")) + + verify(gradle).useLogger("my-logger") + } + + @Test + fun `plugin adapter doesn't mask exceptions thrown by precompiled script`() { + + // given: + val expectedMessage = "Not on my watch!" + + withPrecompiledScriptPluginsPlus( + "kotlin-dsl", + "java-gradle-plugin") + + withFile("src/main/kotlin/my-project-script.gradle.kts", """ + throw IllegalStateException("$expectedMessage") + """) + + // when: + compileKotlin() + + // then: + @Suppress("unchecked_cast") + val pluginAdapter = + loadCompiledKotlinClass("MyProjectScriptPlugin") + .newInstance() as Plugin + + val exception = + assertFailsWith(IllegalStateException::class) { + pluginAdapter.apply(mock()) + } + + assertThat( + exception.message, + equalTo(expectedMessage)) + } + + @Test + fun `implicit imports are available to precompiled scripts`() { + + givenPrecompiledKotlinScript("my-project-script.gradle.kts", """ + + task("jar") + + """) + + val tasks = mock() + val project = mock() { + on { getTasks() } doReturn tasks + } + + instantiatePrecompiledScriptOf( + project, + "My_project_script_gradle") + + verify(tasks).create("jar", org.gradle.api.tasks.bundling.Jar::class.java) + } + + @Test + fun `precompiled script plugin ids are honored by java-gradle-plugin plugin`() { + + projectRoot.withFolders { + + "buildSrc" { + + "src/main/kotlin" { + + // Plugin id for script with no package declaration is simply + // the file name minus the script file extension. + + // Project plugins must be named `*.gradle.kts` + withFile("my-plugin.gradle.kts", """ + println("my-plugin applied!") + """) + + // Settings plugins must be named `*.settings.gradle.kts` + withFile("my-settings-plugin.settings.gradle.kts", """ + println("my-settings-plugin applied!") + """) + + // Gradle object plugins, a.k.a., precompiled init script plugins, + // must be named `*.init.gradle.kts` + withFile("my-init-plugin.init.gradle.kts", """ + println("my-init-plugin applied!") + """) + + // plugin id for script with package declaration is the + // package name dot the file name minus the `.gradle.kts` suffix + withFile("org/acme/my-other-plugin.gradle.kts", """ + package org.acme + + println("my-other-plugin applied!") + """) + } + + withFile("settings.gradle.kts", """ + + $pluginManagementBlock + + """) + + withFile( + "build.gradle.kts", + scriptWithPrecompiledScriptPluginsPlus( + "kotlin-dsl", + "java-gradle-plugin")) + } + } + + withSettings(""" + + // Apply Gradle plugin via type as it cannot be applied via id + // because `buildSrc` is not in the `gradle` object + // plugin search classpath + + gradle.apply() + + apply(plugin = "my-settings-plugin") + """) + + withBuildScript(""" + plugins { + id("my-plugin") + id("org.acme.my-other-plugin") + } + """) + + assertThat( + build("help").output, + allOf( + containsString("my-init-plugin applied!"), + containsString("my-settings-plugin applied!"), + containsString("my-plugin applied!"), + containsString("my-other-plugin applied!") + ) + ) + } + + @LeaksFileHandles + @Test + fun `precompiled script plugins can be published by maven-publish plugin`() { + + projectRoot.withFolders { + + "plugins" { + + "src/main/kotlin" { + + withFile("my-plugin.gradle.kts", """ + println("my-plugin applied!") + """) + + withFile("org/acme/my-other-plugin.gradle.kts", """ + package org.acme + + println("org.acme.my-other-plugin applied!") + """) + + withFile("org/acme/plugins/my-init.init.gradle.kts", """ + + package org.acme.plugins + + println("org.acme.plugins.my-init applied!") + """) + } + + withFile("settings.gradle.kts", """ + + $pluginManagementBlock + + """) + + withFile( "build.gradle.kts", """ + + plugins { + `kotlin-dsl` + `java-gradle-plugin` + `maven-publish` + } + + group = "org.acme" + + version = "0.1.0" + + $applyPrecompiledScriptPlugins + + publishing { + repositories { + maven(url = "../repository") + } + } + """) + } + } + + build(existing("plugins"), "publish") + + val repositoriesBlock = """ + repositories { + maven { url = uri("./repository") } + } + """ + + withSettings(""" + pluginManagement { + $repositoriesBlock + } + """) + + withBuildScript(""" + plugins { + id("my-plugin") version "0.1.0" + id("org.acme.my-other-plugin") version "0.1.0" + } + """) + + val initScript = + withFile("my-init-script.init.gradle.kts", """ + + initscript { + $repositoriesBlock + dependencies { + classpath("org.acme:plugins:0.1.0") + } + } + + apply() + + // TODO: can't apply plugin by id + // apply(plugin = "org.acme.plugins.my-init") + """) + + assertThat( + build("help", "-I", initScript.canonicalPath).output, + allOf( + containsString("org.acme.plugins.my-init applied!"), + containsString("my-plugin applied!"), + containsString("org.acme.my-other-plugin applied!") + ) + ) + } + + private + fun givenPrecompiledKotlinScript(fileName: String, code: String) { + withPrecompiledScriptPluginsPlus("kotlin-dsl") + withFile("src/main/kotlin/$fileName", code) + compileKotlin() + } + + private + inline fun instantiatePrecompiledScriptOf(target: T, className: String): Any = + loadCompiledKotlinClass(className) + .getConstructor(T::class.java) + .newInstance(target) + + private + fun loadCompiledKotlinClass(className: String) = + classLoaderFor(existing("build/classes/kotlin/main")) + .loadClass(className) + + private + fun withPrecompiledScriptPluginsPlus(vararg additionalPlugins: String) = + withBuildScript(scriptWithPrecompiledScriptPluginsPlus(*additionalPlugins)) + + private + fun scriptWithPrecompiledScriptPluginsPlus(vararg additionalPlugins: String): String = + """ + plugins { + ${additionalPlugins.asIterable().joinLines { "`$it`" }} + } + + $applyPrecompiledScriptPlugins + """ + + private + val applyPrecompiledScriptPlugins + get() = "apply<${PrecompiledScriptPlugins::class.qualifiedName}>()" + + private + fun compileKotlin() { + assertThat( + buildWithPlugin("classes").outcomeOf(":compileKotlin"), + equalTo(TaskOutcome.SUCCESS)) + } +} Index: subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPluginTest.kt =================================================================== diff -u -N --- subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPluginTest.kt (revision 0) +++ subprojects/plugins/src/test/kotlin/org/gradle/kotlin/dsl/plugins/precompiled/ScriptPluginTest.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,120 @@ +package org.gradle.kotlin.dsl.plugins.precompiled + +import org.gradle.kotlin.dsl.fixtures.TestWithTempFiles + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.CoreMatchers.startsWith +import org.hamcrest.MatcherAssert.assertThat + +import org.junit.Test + +import java.io.File + + +class ScriptPluginTest : TestWithTempFiles() { + + @Test + fun `plugin id is derived from script file name`() { + + val script = + newFile("my-script.gradle.kts") + + assertThat( + ScriptPlugin(script).id, + equalTo("my-script")) + } + + @Test + fun `plugin id is prefixed by package name if present`() { + + val script = + newFile("my-script.gradle.kts", """ + + package org.acme + + """) + + assertThat( + ScriptPlugin(script).id, + equalTo("org.acme.my-script")) + } + + @Test + fun `implementationClass is a valid Java identifier`() { + + val script = + newFile("my-script.with invalid characters.gradle.kts") + + assertThat( + ScriptPlugin(script).implementationClass, + equalTo("MyScript_with_invalid_charactersPlugin")) + } + + @Test + fun `plugin adapter is written to package sub-dir and starts with correct package declaration`() { + + val script = + newFile("my-script.gradle.kts", """ + + package org.acme + + """) + + val outputDir = + root.resolve("output") + + ScriptPlugin(script) + .writeScriptPluginAdapterTo(outputDir) + + val expectedFile = + outputDir.resolve("org/acme/MyScriptPlugin.kt") + + assertThat( + firstNonBlankLineOf(expectedFile), + equalTo("package org.acme")) + } + + @Test + fun `given no package declaration, plugin adapter is written directly to output dir`() { + + val script = + newFile("my-script.gradle.kts") + + val outputDir = + root.resolve("output").apply { mkdir() } + + ScriptPlugin(script) + .writeScriptPluginAdapterTo(outputDir) + + val expectedFile = + outputDir.resolve("MyScriptPlugin.kt") + + assertThat( + expectedFile.readText(), + startsWith(""" + /** + * Precompiled [my-script.gradle.kts][My_script_gradle] script plugin. + * + * @see My_script_gradle + */ + class MyScriptPlugin + """.trimIndent())) + } + + @Test + fun `can extract package name from script with Windows line endings`() { + + val script = + newFile("my-script.gradle.kts", "/*\r\n */\r\npackage org.acme\r\n") + + assertThat( + ScriptPlugin(script).packageName, + equalTo("org.acme")) + } + + private + fun firstNonBlankLineOf(expectedFile: File) = + expectedFile.bufferedReader().useLines { + it.first { it.isNotBlank() } + } +} Index: subprojects/provider-plugins/.gitignore =================================================================== diff -u -N --- subprojects/provider-plugins/.gitignore (revision 0) +++ subprojects/provider-plugins/.gitignore (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,2 @@ +/build +/out Index: subprojects/provider-plugins/build.gradle.kts =================================================================== diff -u -N --- subprojects/provider-plugins/build.gradle.kts (revision 0) +++ subprojects/provider-plugins/build.gradle.kts (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,15 @@ +import build.* + +plugins { + id("public-kotlin-dsl-module") +} + +base { + archivesBaseName = "gradle-kotlin-dsl-provider-plugins" +} + +dependencies { + compileOnly(gradleApi()) + + compile(project(":provider")) +} Index: subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultKotlinScriptBasePluginsApplicator.kt =================================================================== diff -u -N --- subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultKotlinScriptBasePluginsApplicator.kt (revision 0) +++ subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultKotlinScriptBasePluginsApplicator.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,46 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl.provider.plugins + +import org.gradle.api.Plugin +import org.gradle.api.Project + +import org.gradle.kotlin.dsl.accessors.tasks.PrintAccessors +import org.gradle.kotlin.dsl.accessors.tasks.UpdateProjectSchema +import org.gradle.kotlin.dsl.provider.KotlinScriptBasePluginsApplicator + + +class DefaultKotlinScriptBasePluginsApplicator : KotlinScriptBasePluginsApplicator { + override fun apply(project: Project) { + project.plugins.apply(KotlinScriptBasePlugin::class.java) + } +} + + +class KotlinScriptBasePlugin : Plugin { + override fun apply(project: Project): Unit = project.run { + rootProject.plugins.apply(KotlinScriptRootPlugin::class.java) + tasks.createLater("kotlinDslAccessorsReport", PrintAccessors::class.java) + } +} + + +class KotlinScriptRootPlugin : Plugin { + override fun apply(project: Project): Unit = project.run { + tasks.createLater("kotlinDslAccessorsSnapshot", UpdateProjectSchema::class.java) + } +} Index: subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultProjectSchemaProvider.kt =================================================================== diff -u -N --- subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultProjectSchemaProvider.kt (revision 0) +++ subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/DefaultProjectSchemaProvider.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,134 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl.provider.plugins + +import org.gradle.api.Project +import org.gradle.api.plugins.ExtensionAware +import org.gradle.api.plugins.ExtensionsSchema +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.api.reflect.HasPublicType +import org.gradle.api.reflect.TypeOf +import org.gradle.api.tasks.SourceSet + +import org.gradle.kotlin.dsl.accessors.ProjectSchema +import org.gradle.kotlin.dsl.accessors.ProjectSchemaEntry +import org.gradle.kotlin.dsl.accessors.ProjectSchemaProvider + + +class DefaultProjectSchemaProvider : ProjectSchemaProvider { + + override fun schemaFor(project: Project): ProjectSchema> = + targetSchemaFor(project, typeOfProject).let { targetSchema -> + ProjectSchema( + targetSchema.extensions, + targetSchema.conventions, + accessibleConfigurationsOf(project)) + } +} + + +private +data class ExtensionConventionSchema( + val extensions: List>>, + val conventions: List>> +) + + +private +fun targetSchemaFor(target: Any, targetType: TypeOf<*>): ExtensionConventionSchema { + + val extensions = mutableListOf>>() + val conventions = mutableListOf>>() + + fun collectSchemaOf(target: Any, targetType: TypeOf<*>) { + if (target is ExtensionAware) { + accessibleExtensionsSchema(target.extensions.extensionsSchema).forEach { schema -> + extensions.add(ProjectSchemaEntry(targetType, schema.name, schema.publicType)) + if (!schema.isDeferredConfigurable) { + collectSchemaOf(target.extensions.getByName(schema.name), schema.publicType) + } + } + } + if (target is Project) { + accessibleConventionsSchema(target.convention.plugins).forEach { name, type -> + conventions.add(ProjectSchemaEntry(targetType, name, type)) + collectSchemaOf(target.convention.plugins[name]!!, type) + } + sourceSetsOf(target)?.forEach { sourceSet -> + collectSchemaOf(sourceSet, typeOfSourceSet) + } + } + } + + collectSchemaOf(target, targetType) + + return ExtensionConventionSchema(extensions.distinct(), conventions.distinct()) +} + + +private +fun accessibleExtensionsSchema(extensionsSchema: ExtensionsSchema) = + extensionsSchema.filter { isPublic(it.name) } + + +private +fun accessibleConventionsSchema(plugins: Map) = + plugins.filterKeys(::isPublic).mapValues { inferPublicTypeOfConvention(it.value) } + + +private +fun sourceSetsOf(project: Project) = + project.convention.findPlugin(JavaPluginConvention::class.java)?.sourceSets + + +private +fun inferPublicTypeOfConvention(instance: Any) = + if (instance is HasPublicType) instance.publicType + else TypeOf.typeOf(instance::class.java.firstNonSyntheticOrSelf) + + +private +val Class<*>.firstNonSyntheticOrSelf + get() = firstNonSyntheticOrNull ?: this + + +private +val Class<*>.firstNonSyntheticOrNull: Class<*>? + get() = takeIf { !isSynthetic } ?: superclass?.firstNonSyntheticOrNull + + +private +fun accessibleConfigurationsOf(project: Project) = + project.configurations.names.filter(::isPublic) + + +private +fun isPublic(name: String): Boolean = + !name.startsWith("_") + + +private +val typeOfProject = typeOf() + + +private +val typeOfSourceSet = typeOf() + + +internal +inline fun typeOf(): TypeOf = + object : TypeOf() {} Index: subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/KotlinDslProviderPluginsServiceRegistry.kt =================================================================== diff -u -N --- subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/KotlinDslProviderPluginsServiceRegistry.kt (revision 0) +++ subprojects/provider-plugins/src/main/kotlin/org/gradle/kotlin/dsl/provider/plugins/KotlinDslProviderPluginsServiceRegistry.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,41 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl.provider.plugins + +import org.gradle.internal.service.ServiceRegistration +import org.gradle.internal.service.scopes.AbstractPluginServiceRegistry + + +class KotlinDslProviderPluginsServiceRegistry : AbstractPluginServiceRegistry() { + + override fun registerGradleUserHomeServices(registration: ServiceRegistration) { + registration.addProvider(GradleUserHomeServices) + } +} + + +internal +object GradleUserHomeServices { + + @Suppress("unused") + fun createProjectSchemaProvider() = + DefaultProjectSchemaProvider() + + @Suppress("unused") + fun createKotlinScriptBasePluginsApplicator() = + DefaultKotlinScriptBasePluginsApplicator() +} Index: subprojects/provider-plugins/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry =================================================================== diff -u -N --- subprojects/provider-plugins/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry (revision 0) +++ subprojects/provider-plugins/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1 @@ +org.gradle.kotlin.dsl.provider.plugins.KotlinDslProviderPluginsServiceRegistry Index: subprojects/provider/.gitignore =================================================================== diff -u -N --- subprojects/provider/.gitignore (revision 0) +++ subprojects/provider/.gitignore (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,3 @@ +/src/generated +/build +/out Index: subprojects/provider/build.gradle.kts =================================================================== diff -u -N --- subprojects/provider/build.gradle.kts (revision 0) +++ subprojects/provider/build.gradle.kts (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,80 @@ +import build.* + +import codegen.GenerateKotlinDependencyExtensions + +plugins { + id("public-kotlin-dsl-module") +} + +base { + archivesBaseName = "gradle-kotlin-dsl" +} + +dependencies { + compileOnly(gradleApi()) + + compile(project(":tooling-models")) + compile(futureKotlin("stdlib-jdk8")) + compile(futureKotlin("reflect")) + compile(futureKotlin("compiler-embeddable")) + compile(futureKotlin("sam-with-receiver-compiler-plugin")) { + isTransitive = false + } + + testCompile(project(":test-fixtures")) + testCompile("com.squareup.okhttp3:mockwebserver:3.9.1") +} + + +// --- Enable automatic generation of API extensions ------------------- +val apiExtensionsOutputDir = file("src/generated/kotlin") + +java.sourceSets["main"].kotlin { + srcDir(apiExtensionsOutputDir) +} + +val publishedPluginsVersion: String by rootProject.extra + +val generateKotlinDependencyExtensions by task { + outputFile = File(apiExtensionsOutputDir, "org/gradle/kotlin/dsl/KotlinDependencyExtensions.kt") + embeddedKotlinVersion = kotlinVersion + kotlinDslPluginsVersion = publishedPluginsVersion +} + +val generateExtensions by tasks.creating { + dependsOn(generateKotlinDependencyExtensions) +} + +val compileKotlin by tasks +compileKotlin.dependsOn(generateExtensions) + +val clean: Delete by tasks +clean.delete(apiExtensionsOutputDir) + + +// -- Version manifest properties -------------------------------------- +val versionsManifestOutputDir = file("$buildDir/versionsManifest") +val writeVersionsManifest by tasks.creating(WriteProperties::class) { + outputFile = versionsManifestOutputDir.resolve("gradle-kotlin-dsl-versions.properties") + property("provider", version) + property("kotlin", kotlinVersion) +} +val processResources by tasks.getting(ProcessResources::class) { + from(writeVersionsManifest) +} + +// -- Testing ---------------------------------------------------------- +val prepareIntegrationTestFixtures by rootProject.tasks +val customInstallation by rootProject.tasks +tasks { + "test" { + dependsOn(prepareIntegrationTestFixtures) + dependsOn(customInstallation) + } +} + +withParallelTests() + +// --- Utility functions ----------------------------------------------- +inline fun task(noinline configuration: T.() -> Unit) = tasks.creating(T::class, configuration) + Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ActionExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ActionExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ActionExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,25 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.Action + + +/** + * Enables function invocation syntax on [Action] references. + */ +inline operator fun Action.invoke(target: T) = execute(target) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurableFileCollectionExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,39 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.file.ConfigurableFileCollection + +import kotlin.reflect.KProperty + + +/** + * Property delegate for [ConfigurableFileCollection] instances. + * + * Example: `val aFileCollection by project.files()` + */ +operator fun ConfigurableFileCollection.getValue(receiver: Any?, property: KProperty<*>): ConfigurableFileCollection = + this + + +/** + * Property delegate for [ConfigurableFileCollection] instances. + * + * Example: `var aFileCollection by project.files()` + */ +operator fun ConfigurableFileCollection.setValue(receiver: Any?, property: KProperty<*>, value: Iterable<*>) = + setFrom(value) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConfigurationExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,34 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ModuleDependency + +import org.gradle.kotlin.dsl.support.excludeMapFor + + +/** + * Adds an exclude rule to exclude transitive dependencies for all dependencies of this configuration. + * You can also add exclude rules per-dependency. See [ModuleDependency.exclude]. + * + * @param group the optional group identifying the dependencies to be excluded. + * @param module the optional module name identifying the dependencies to be excluded. + * @return this + */ +fun Configuration.exclude(group: String? = null, module: String? = null): Configuration = + exclude(excludeMapFor(group, module)) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ContentFilterableExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,113 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl + +import org.gradle.api.file.ContentFilterable + +import java.io.FilterReader +import kotlin.reflect.KClass + + +/** + * Adds a content filter to be used during the copy. + * Multiple calls add additional filters to the filter chain. + * Each filter should implement [FilterReader]. + * Import `org.apache.tools.ant.filters.*` for access to all the standard Ant filters. + * + * Examples: + * + * ``` + * filter() + * filter() + * filter("lines" to 25, "skip" to 2) + * filter("tokens" to mapOf("copyright" to "2009", "version" to "2.3.1")) + * ``` + * + * @param T type of the filter to add + * @param properties map of filter properties + * @return this + */ +inline fun ContentFilterable.filter(vararg properties: Pair) = + if (properties.isEmpty()) filter(T::class.java) + else filter(mapOf(*properties), T::class.java) + + +/** + * Adds a content filter to be used during the copy. + * Multiple calls add additional filters to the filter chain. + * Each filter should implement [FilterReader]. + * Import `org.apache.tools.ant.filters.*` for access to all the standard Ant filters. + * + * Examples: + * + * ``` + * filter(mapOf("lines" to 25, "skip" to 2)) + * filter(mapOf("tokens" to mapOf("copyright" to "2009", "version" to "2.3.1"))) + * ``` + * + * @param T type of the filter to add + * @param properties map of filter properties + * @return this + */ +inline fun ContentFilterable.filter(properties: Map) = + if (properties.isEmpty()) filter(T::class.java) + else filter(properties, T::class.java) + + +/** + * Adds a content filter to be used during the copy. + * Multiple calls add additional filters to the filter chain. + * Each filter should implement [FilterReader]. + * Import `org.apache.tools.ant.filters.*` for access to all the standard Ant filters. + * + * Examples: + * + * ``` + * filter(StripJavaComments::class) + * filter(com.mycompany.project.CustomFilter::class) + * filter(HeadFilter::class, "lines" to 25, "skip" to 2) + * filter(ReplaceTokens::class, "tokens" to mapOf("copyright" to "2009", "version" to "2.3.1")) + * ``` + * + * @param filterType type of the filter to add + * @param properties map of filter properties + * @return this + */ +fun ContentFilterable.filter(filterType: KClass, vararg properties: Pair) = + if (properties.isEmpty()) filter(filterType.java) + else filter(mapOf(*properties), filterType.java) + + +/** + * Adds a content filter to be used during the copy. + * Multiple calls add additional filters to the filter chain. + * Each filter should implement [FilterReader]. + * Import `org.apache.tools.ant.filters.*` for access to all the standard Ant filters. + * + * Examples: + * + * ``` + * filter(HeadFilter::class, mapOf("lines" to 25, "skip" to 2)) + * filter(ReplaceTokens::class, mapOf("tokens" to mapOf("copyright" to "2009", "version" to "2.3.1"))) + * ``` + * + * @param filterType type of the filter to add + * @param properties map of filter properties + * @return this + */ +fun ContentFilterable.filter(filterType: KClass, properties: Map) = + if (properties.isEmpty()) filter(filterType.java) + else filter(properties, filterType.java) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConventionExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConventionExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ConventionExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,72 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.internal.HasConvention +import org.gradle.api.plugins.Convention +import kotlin.reflect.KClass + + +/** + * Looks for the convention plugin of a given name and casts it to the expected type [T]. + * + * If no convention is found or if the one found cannot be cast to the expected type it will throw an [IllegalStateException]. + * + * @param name convention plugin name + * @return the convention plugin, never null + * @throws [IllegalStateException] When the convention cannot be found or cast to the expected type. + */ +inline fun Convention.getPluginByName(name: String): T = + plugins[name]?.let { + (it as T?) ?: throw IllegalStateException("Convention '$name' of type '${it::class.java.name}' cannot be cast to '${T::class.java.name}'.") + } ?: throw IllegalStateException("A convention named '$name' could not be found.") + + +inline fun Convention.getPlugin() = + getPlugin(T::class) + + +fun Convention.getPlugin(conventionType: KClass): T = + getPlugin(conventionType.java) + + +inline fun Convention.findPlugin() = + findPlugin(T::class) + + +fun Convention.findPlugin(conventionType: KClass): T? = + findPlugin(conventionType.java) + + +/** + * Evaluates the given [function] against the convention plugin of the given [conventionType]. + * + * @param conventionType the type of the convention to be located. + * @param function function to be evaluated. + * @return the value returned by the given [function]. + * @throws [IllegalStateException] When the receiver does not support convention plugins, when there is no convention plugin of the given type, or when there are multiple such plugins. + * + * @see [Convention.getPlugin] + */ +inline fun Any.withConvention( + conventionType: KClass, + function: ConventionType.() -> ReturnType +): ReturnType = + when (this) { + is HasConvention -> convention.getPlugin(conventionType).run(function) + else -> throw IllegalStateException("Object `$this` doesn't support conventions!") + } Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/CopySpecExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/CopySpecExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/CopySpecExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,30 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.file.CopySpec + +import java.io.FilterReader + + +// Interim extensions until those methods are added to CopySpec +inline fun CopySpec.filter(vararg properties: Pair) = + filter(mapOf(*properties), T::class.java) + + +inline fun CopySpec.filter(properties: Map) = + filter(properties, T::class.java) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,283 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.artifacts.ClientModule +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.artifacts.ModuleDependency +import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.artifacts.ResolutionStrategy +import org.gradle.api.artifacts.dsl.DependencyHandler + +import org.gradle.internal.Cast.uncheckedCast + +import org.gradle.kotlin.dsl.support.excludeMapFor +import org.gradle.kotlin.dsl.support.mapOfNonNullValuesOf + + +/** + * Creates a dependency on a module without adding it to a configuration. + * + * @param group the group of the module to be added as a dependency. + * @param name the name of the module to be added as a dependency. + * @param version the optional version of the module to be added as a dependency. + * @param configuration the optional configuration of the module to be added as a dependency. + * @param classifier the optional classifier of the module artifact to be added as a dependency. + * @param ext the optional extension of the module artifact to be added as a dependency. + * + * @return The dependency. + * + * @see [DependencyHandler.create] + */ +fun DependencyHandler.create( + group: String, + name: String, + version: String? = null, + configuration: String? = null, + classifier: String? = null, + ext: String? = null +): ExternalModuleDependency = + + create( + mapOfNonNullValuesOf( + "group" to group, + "name" to name, + "version" to version, + "configuration" to configuration, + "classifier" to classifier, + "ext" to ext)) as ExternalModuleDependency + + +/** + * Creates a dependency on a client module without adding it to a configuration. + * + * @param group the group of the module to be added as a dependency. + * @param name the name of the module to be added as a dependency. + * @param version the optional version of the module to be added as a dependency. + * @param configuration the optional configuration of the module to be added as a dependency. + * @param classifier the optional classifier of the module artifact to be added as a dependency. + * @param ext the optional extension of the module artifact to be added as a dependency. + * + * @return The dependency. + * + * @see [DependencyHandler.create] + */ +fun DependencyHandler.module( + group: String, + name: String, + version: String? = null, + configuration: String? = null, + classifier: String? = null, + ext: String? = null +): ClientModule = + + module( + mapOfNonNullValuesOf( + "group" to group, + "name" to name, + "version" to version, + "configuration" to configuration, + "classifier" to classifier, + "ext" to ext)) as ClientModule + + +/** + * Creates a dependency on a client module without adding it to a configuration. + * + * @param group the group of the module to be added as a dependency. + * @param name the name of the module to be added as a dependency. + * @param version the optional version of the module to be added as a dependency. + * @param configuration the optional configuration of the module to be added as a dependency. + * @param classifier the optional classifier of the module artifact to be added as a dependency. + * @param ext the optional extension of the module artifact to be added as a dependency. + * @param clientModuleConfiguration The expression to use to configure the dependency. + * @return The dependency. + * + * @see [DependencyHandler.create] + */ +fun DependencyHandler.module( + group: String, + name: String, + version: String? = null, + configuration: String? = null, + classifier: String? = null, + ext: String? = null, + clientModuleConfiguration: ClientModuleScope.() -> Unit +): ClientModule = + + configureClientModule( + module( + mapOfNonNullValuesOf( + "group" to group, + "name" to name, + "version" to version, + "configuration" to configuration, + "classifier" to classifier, + "ext" to ext)) as ClientModule, + clientModuleConfiguration) + + +/** + * Creates a dependency on a client module without adding it to a configuration. + * + * @param notation The module notation, in one of the notations described at [DependencyHandler]. + * @param clientModuleConfiguration The expression to use to configure the dependency. + * @return The dependency. + */ +fun DependencyHandler.module( + notation: Any, + clientModuleConfiguration: ClientModuleScope.() -> Unit +): ClientModule = + + configureClientModule(module(notation) as ClientModule, clientModuleConfiguration) + + +private +inline fun DependencyHandler.configureClientModule( + module: ClientModule, + clientModuleConfiguration: ClientModuleScope.() -> Unit +): ClientModule = + module.apply { + ClientModuleScope(this@configureClientModule, this@apply).clientModuleConfiguration() + } + + +/** + * Receiver for [ClientModule] configuration blocks. + */ +class ClientModuleScope( + private val dependencyHandler: DependencyHandler, + val clientModule: ClientModule +) : ClientModule by clientModule { + + fun module( + group: String, + name: String, + version: String? = null, + configuration: String? = null, + classifier: String? = null, + ext: String? = null, + setup: ClientModuleScope.() -> Unit + ) { + + clientModule.addDependency( + dependencyHandler.module(group, name, version, configuration, classifier, ext, setup)) + } + + fun dependency(notation: Any) { + clientModule.addDependency( + dependencyHandler.create(notation) as ModuleDependency) + } + + fun dependency(notation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit) { + clientModule.addDependency( + create(notation, dependencyConfiguration)) + } + + fun dependencies(vararg notations: Any) { + notations.forEach { + clientModule.addDependency( + dependencyHandler.create(it) as ModuleDependency) + } + } + + private + fun create(notation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit) = + (dependencyHandler.create(notation) as ExternalModuleDependency).apply(dependencyConfiguration) +} + + +/** + * Creates a dependency on a project without adding it to a configuration. + * + * @param path the path of the project to be added as a dependency. + * @param configuration the optional configuration of the project to be added as a dependency. + * @return The dependency. + */ +fun DependencyHandler.project( + path: String, + configuration: String? = null +): ProjectDependency = + + uncheckedCast( + project( + if (configuration != null) mapOf("path" to path, "configuration" to configuration) + else mapOf("path" to path))) + + +/** + * Adds a dependency to the given configuration, and configures the dependency using the given expression. + * + * @param configuration The name of the configuration. + * @param dependencyNotation The dependency notation. + * @param dependencyConfiguration The expression to use to configure the dependency. + * @return The dependency. + */ +inline fun DependencyHandler.add( + configuration: String, + dependencyNotation: String, + dependencyConfiguration: ExternalModuleDependency.() -> Unit +): ExternalModuleDependency = + + add(configuration, create(dependencyNotation) as ExternalModuleDependency, dependencyConfiguration) + + +/** + * Adds a dependency to the given configuration, and configures the dependency using the given expression. + * + * @param configuration The name of the configuration. + * @param dependency The dependency. + * @param dependencyConfiguration The expression to use to configure the dependency. + * @return The dependency. + */ +inline fun DependencyHandler.add( + configuration: String, + dependency: T, + dependencyConfiguration: T.() -> Unit +): T = + + dependency.apply { + dependencyConfiguration() + add(configuration, this) + } + + +/** + * Adds an exclude rule to exclude transitive dependencies of this dependency. + * + * Excluding a particular transitive dependency does not guarantee that it does not show up + * in the dependencies of a given configuration. + * For example, some other dependency, which does not have any exclude rules, + * might pull in exactly the same transitive dependency. + * To guarantee that the transitive dependency is excluded from the entire configuration + * please use per-configuration exclude rules: [Configuration.getExcludeRules]. + * In fact, in majority of cases the actual intention of configuring per-dependency exclusions + * is really excluding a dependency from the entire configuration (or classpath). + * + * If your intention is to exclude a particular transitive dependency + * because you don't like the version it pulls in to the configuration + * then consider using the forced versions feature: [ResolutionStrategy.force]. + * + * @param group the optional group identifying the dependencies to be excluded. + * @param module the optional module name identifying the dependencies to be excluded. + * @return this + * + * @see [ModuleDependency.exclude] + */ +fun T.exclude(group: String? = null, module: String? = null): T = + uncheckedCast(exclude(excludeMapFor(group, module))) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerScope.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerScope.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DependencyHandlerScope.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,199 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.artifacts.ModuleDependency +import org.gradle.api.artifacts.dsl.DependencyHandler + + +/** + * Receiver for `dependencies` block providing convenient utilities for configuring dependencies. + * + * @see [DependencyHandler] + */ +class DependencyHandlerScope(val dependencies: DependencyHandler) : DependencyHandler by dependencies { + + /** + * Adds a dependency to the given configuration. + * + * @param dependencyNotation notation for the dependency to be added. + * @return The dependency. + * @see [DependencyHandler.add] + */ + operator fun String.invoke(dependencyNotation: Any): Dependency? = + dependencies.add(this, dependencyNotation) + + /** + * Adds a dependency to the given configuration. + * + * @param dependencyNotation notation for the dependency to be added. + * @param dependencyConfiguration expression to use to configure the dependency. + * @return The dependency. + * @see [DependencyHandler.add] + */ + inline operator fun String.invoke(dependencyNotation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency = + dependencies.add(this, dependencyNotation, dependencyConfiguration) + + /** + * Adds a dependency to the given configuration. + * + * @param group the group of the module to be added as a dependency. + * @param name the name of the module to be added as a dependency. + * @param version the optional version of the module to be added as a dependency. + * @param configuration the optional configuration of the module to be added as a dependency. + * @param classifier the optional classifier of the module artifact to be added as a dependency. + * @param ext the optional extension of the module artifact to be added as a dependency. + * @return The dependency. + * + * @see [DependencyHandler.add] + */ + operator fun String.invoke( + group: String, + name: String, + version: String? = null, + configuration: String? = null, + classifier: String? = null, + ext: String? = null + ): ExternalModuleDependency = + dependencies.create(group, name, version, configuration, classifier, ext).apply { add(this@invoke, this) } + + /** + * Adds a dependency to the given configuration. + * + * @param group the group of the module to be added as a dependency. + * @param name the name of the module to be added as a dependency. + * @param version the optional version of the module to be added as a dependency. + * @param configuration the optional configuration of the module to be added as a dependency. + * @param classifier the optional classifier of the module artifact to be added as a dependency. + * @param ext the optional extension of the module artifact to be added as a dependency. + * @param dependencyConfiguration expression to use to configure the dependency. + * @return The dependency. + * + * @see [DependencyHandler.create] + * @see [DependencyHandler.add] + */ + inline operator fun String.invoke( + group: String, + name: String, + version: String? = null, + configuration: String? = null, + classifier: String? = null, + ext: String? = null, + dependencyConfiguration: ExternalModuleDependency.() -> Unit + ): ExternalModuleDependency = + dependencies.add(this, create(group, name, version, configuration, classifier, ext), dependencyConfiguration) + + /** + * Adds a dependency to the given configuration. + * + * @param dependency dependency to be added. + * @param dependencyConfiguration expression to use to configure the dependency. + * @return The dependency. + * + * @see [DependencyHandler.add] + */ + inline operator fun String.invoke(dependency: T, dependencyConfiguration: T.() -> Unit): T = + dependencies.add(this, dependency, dependencyConfiguration) + + /** + * Adds a dependency to the given configuration. + * + * @param dependencyNotation notation for the dependency to be added. + * @return The dependency. + * @see [DependencyHandler.add] + */ + operator fun Configuration.invoke(dependencyNotation: Any): Dependency? = + add(name, dependencyNotation) + + /** + * Adds a dependency to the given configuration. + * + * @param dependencyNotation notation for the dependency to be added. + * @param dependencyConfiguration expression to use to configure the dependency. + * @return The dependency. + * @see [DependencyHandler.add] + */ + inline operator fun Configuration.invoke(dependencyNotation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency = + add(name, dependencyNotation, dependencyConfiguration) + + /** + * Adds a dependency to the given configuration. + * + * @param group the group of the module to be added as a dependency. + * @param name the name of the module to be added as a dependency. + * @param version the optional version of the module to be added as a dependency. + * @param configuration the optional configuration of the module to be added as a dependency. + * @param classifier the optional classifier of the module artifact to be added as a dependency. + * @param ext the optional extension of the module artifact to be added as a dependency. + * @return The dependency. + * + * @see [DependencyHandler.add] + */ + operator fun Configuration.invoke( + group: String, + name: String, + version: String? = null, + configuration: String? = null, + classifier: String? = null, + ext: String? = null + ): ExternalModuleDependency = + create(group, name, version, configuration, classifier, ext).apply { add(this@invoke.name, this) } + + /** + * Adds a dependency to the given configuration. + * + * @param group the group of the module to be added as a dependency. + * @param name the name of the module to be added as a dependency. + * @param version the optional version of the module to be added as a dependency. + * @param configuration the optional configuration of the module to be added as a dependency. + * @param classifier the optional classifier of the module artifact to be added as a dependency. + * @param ext the optional extension of the module artifact to be added as a dependency. + * @param dependencyConfiguration expression to use to configure the dependency. + * @return The dependency. + * + * @see [DependencyHandler.create] + * @see [DependencyHandler.add] + */ + inline operator fun Configuration.invoke( + group: String, + name: String, + version: String? = null, + configuration: String? = null, + classifier: String? = null, + ext: String? = null, + dependencyConfiguration: ExternalModuleDependency.() -> Unit + ): ExternalModuleDependency = + add(this.name, create(group, name, version, configuration, classifier, ext), dependencyConfiguration) + + /** + * Adds a dependency to the given configuration. + * + * @param dependency dependency to be added. + * @param dependencyConfiguration expression to use to configure the dependency. + * @return The dependency. + * + * @see [DependencyHandler.add] + */ + inline operator fun Configuration.invoke(dependency: T, dependencyConfiguration: T.() -> Unit): T = + add(name, dependency, dependencyConfiguration) + + inline operator fun invoke(configuration: DependencyHandlerScope.() -> Unit) = + configuration() +} Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DomainObjectCollectionExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DomainObjectCollectionExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/DomainObjectCollectionExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,47 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.DomainObjectCollection + + +/** + * Returns a collection containing the objects in this collection of the given type. Equivalent to calling + * {@code withType(type).all(configureAction)} + * + * @param S The type of objects to find. + * @param configuration The action to execute for each object in the resulting collection. + * @return The matching objects. Returns an empty collection if there are no such objects + * in this collection. + * @see [DomainObjectCollection.withType] + */ +inline fun DomainObjectCollection.withType(crossinline configuration: S.() -> Unit) = + withType(S::class.java, { it.configuration() }) + + +/** + * Returns a collection containing the objects in this collection of the given type. The + * returned collection is live, so that when matching objects are later added to this + * collection, they are also visible in the filtered collection. + * + * @param S The type of objects to find. + * @return The matching objects. Returns an empty collection if there are no such objects + * in this collection. + * @see [DomainObjectCollection.withType] + */ +inline fun DomainObjectCollection.withType() = + withType(S::class.java) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionAwareExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,49 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl + +import org.gradle.api.plugins.ExtensionAware +import kotlin.reflect.KClass + + +/** + * Returns the extension of the specified type. + * + * @param T the extension type. + */ +inline fun ExtensionAware.the(): T = + extensions.getByType(typeOf()) + + +/** + * Returns the extension of the specified [extensionType]. + * + * @param T the extension type. + * @param extensionType the reified extension type. + */ +fun ExtensionAware.the(extensionType: KClass): T = + extensions.getByType(extensionType.java) + + +/** + * Executes the given configuration block against the [extension][ExtensionAware] of the specified type. + * + * @param T the extension type. + * @param configuration the configuration block. + * @see [ExtensionAware] + */ +inline fun ExtensionAware.configure(noinline configuration: T.() -> Unit): Unit = + extensions.configure(typeOf(), configuration) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionContainerExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionContainerExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtensionContainerExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,59 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.UnknownDomainObjectException +import org.gradle.api.plugins.ExtensionContainer + +import kotlin.reflect.KProperty + + +/** + * Looks for the extension of a given name. If none found it will throw an exception. + * + * @param name extension name + * @return extension + * @throws [UnknownDomainObjectException] When the given extension is not found. + * + * @see [ExtensionContainer.getByName] + */ +operator fun ExtensionContainer.get(name: String): Any = + getByName(name) + + +/** + * Looks for the extension of a given name and casts it to the expected type [T]. + * + * If none found it will throw an [UnknownDomainObjectException]. + * If the extension is found but cannot be cast to the expected type it will throw an [IllegalStateException]. + * + * @param name extension name + * @return extension, never null + * @throws [UnknownDomainObjectException] When the given extension is not found. + * @throws [IllegalStateException] When the given extension cannot be cast to the expected type. + */ +@Suppress("extension_shadowed_by_member") +inline fun ExtensionContainer.getByName(name: String) = + getByName(name).let { + it as? T + ?: throw IllegalStateException( + "Element '$name' of type '${it::class.java.name}' from container '$this' cannot be cast to '${T::class.qualifiedName}'.") + } + + +inline operator fun ExtensionContainer.getValue(thisRef: Any?, property: KProperty<*>): T = + getByName(property.name) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ExtraPropertiesExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,118 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.InvalidUserCodeException +import org.gradle.api.plugins.ExtensionAware +import org.gradle.api.plugins.ExtensionContainer +import org.gradle.api.plugins.ExtraPropertiesExtension + +import org.gradle.internal.Cast.uncheckedCast + +import kotlin.reflect.KProperty + + +/** + * The extra properties extension in this object's extension container. + * + * @see [ExtensionContainer.getExtraProperties] + */ +val ExtensionAware.extra: ExtraPropertiesExtension + get() = extensions.extraProperties + + +operator fun ExtraPropertiesExtension.provideDelegate(receiver: Any?, property: KProperty<*>): MutablePropertyDelegate = + if (property.returnType.isMarkedNullable) NullableExtraPropertyDelegate(this, property.name) + else NonNullExtraPropertyDelegate(this, property.name) + + +private +class NonNullExtraPropertyDelegate( + private val extra: ExtraPropertiesExtension, + private val name: String +) : MutablePropertyDelegate { + + override fun getValue(receiver: Any?, property: KProperty<*>): T = + if (!extra.has(name)) cannotGetExtraProperty("does not exist") + else uncheckedCast(extra.get(name) ?: cannotGetExtraProperty("is null")) + + override fun setValue(receiver: Any?, property: KProperty<*>, value: T) = + extra.set(property.name, value) + + private + fun cannotGetExtraProperty(reason: String): Nothing = + throw InvalidUserCodeException("Cannot get non-null extra property '$name' as it $reason") +} + + +private +class NullableExtraPropertyDelegate( + private val extra: ExtraPropertiesExtension, + private val name: String +) : MutablePropertyDelegate { + + override fun getValue(receiver: Any?, property: KProperty<*>): T = + uncheckedCast(if (extra.has(name)) extra.get(name) else null) + + override fun setValue(receiver: Any?, property: KProperty<*>, value: T) = + extra.set(property.name, value) +} + + +/** + * Returns a property delegate provider that will initialize the extra property to the value provided + * by [initialValueProvider]. + * + * Usage: `val answer by extra { 42 }` + */ +inline operator fun ExtraPropertiesExtension.invoke(initialValueProvider: () -> T): InitialValueExtraPropertyDelegateProvider = + invoke(initialValueProvider()) + + +/** + * Returns a property delegate provider that will initialize the extra property to the given [initialValue]. + * + * Usage: `val answer by extra(42)` + */ +operator fun ExtraPropertiesExtension.invoke(initialValue: T): InitialValueExtraPropertyDelegateProvider = + InitialValueExtraPropertyDelegateProvider(this, initialValue) + + +class InitialValueExtraPropertyDelegateProvider( + val extra: ExtraPropertiesExtension, + val initialValue: T +) { + + operator fun provideDelegate(thisRef: Any?, property: kotlin.reflect.KProperty<*>): InitialValueExtraPropertyDelegate { + extra.set(property.name, initialValue) + return InitialValueExtraPropertyDelegate(extra) + } +} + + +/** + * Enables typed access to extra properties with initial value. + */ +class InitialValueExtraPropertyDelegate(val extra: ExtraPropertiesExtension) { + + operator fun setValue(receiver: Any?, property: kotlin.reflect.KProperty<*>, value: T) = + extra.set(property.name, value) + + @Suppress("unchecked_cast") + operator fun getValue(receiver: Any?, property: kotlin.reflect.KProperty<*>): T = + uncheckedCast(extra.get(property.name)) +} Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleDsl.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleDsl.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleDsl.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,26 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + + +/** + * Delimits a Gradle DSL. + * + * See [DslMarker] + */ +@DslMarker +annotation class GradleDsl Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GradleExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,33 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl + +import org.gradle.api.Plugin +import org.gradle.api.invocation.Gradle +import org.gradle.api.plugins.PluginAware + + +/** + * Applies the plugin of the given type [T]. Does nothing if the plugin has already been applied. + * + * The given class should implement the [Plugin] interface, and be parameterized for a + * compatible type of `this`. + * + * @param T the plugin type. + * @see [PluginAware.apply] + */ +inline fun > Gradle.apply() = + (this as PluginAware).apply() Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GroovyInteroperability.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GroovyInteroperability.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/GroovyInteroperability.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,238 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import groovy.lang.Closure +import groovy.lang.GroovyObject +import groovy.lang.MetaClass + +import org.gradle.internal.Cast.uncheckedCast + +import org.codehaus.groovy.runtime.InvokerHelper.getMetaClass + +import org.gradle.kotlin.dsl.support.unsafeLazy + + +/** + * Adapts a Kotlin function to a single argument Groovy [Closure]. + * + * @param T the expected type of the single argument to the closure. + * @param action the function to be adapted. + * + * @see [KotlinClosure1] + */ +fun Any.closureOf(action: T.() -> Unit): Closure = + KotlinClosure1(action, this, this) + + +/** + * Adapts a Kotlin function to a Groovy [Closure] that operates on the + * configured Closure delegate. + * + * @param T the expected type of the delegate argument to the closure. + * @param action the function to be adapted. + * + * @see [KotlinClosure1] + */ +fun Any.delegateClosureOf(action: T.() -> Unit) = + object : Closure(this, this) { + @Suppress("unused") // to be called dynamically by Groovy + fun doCall() = uncheckedCast(delegate).action() + } + + +/** + * Adapts a parameterless Kotlin function to a parameterless Groovy [Closure]. + * + * @param V the return type. + * @param function the function to be adapted. + * @param owner optional owner of the Closure. + * @param thisObject optional _this Object_ of the Closure. + * + * @see [Closure] + */ +open class KotlinClosure0( + val function: () -> V?, + owner: Any? = null, + thisObject: Any? = null +) : groovy.lang.Closure(owner, thisObject) { + + @Suppress("unused") // to be called dynamically by Groovy + fun doCall(): V? = function() +} + + +/** + * Adapts an unary Kotlin function to an unary Groovy [Closure]. + * + * @param T the type of the single argument to the closure. + * @param V the return type. + * @param function the function to be adapted. + * @param owner optional owner of the Closure. + * @param thisObject optional _this Object_ of the Closure. + * + * @see [Closure] + */ +class KotlinClosure1( + val function: T.() -> V?, + owner: Any? = null, + thisObject: Any? = null +) : Closure(owner, thisObject) { + + @Suppress("unused") // to be called dynamically by Groovy + fun doCall(it: T): V? = it.function() +} + + +/** + * Adapts a binary Kotlin function to a binary Groovy [Closure]. + * + * @param T the type of the first argument. + * @param U the type of the second argument. + * @param V the return type. + * @param function the function to be adapted. + * @param owner optional owner of the Closure. + * @param thisObject optional _this Object_ of the Closure. + * + * @see [Closure] + */ +class KotlinClosure2( + val function: (T, U) -> V?, + owner: Any? = null, + thisObject: Any? = null +) : Closure(owner, thisObject) { + + @Suppress("unused") // to be called dynamically by Groovy + fun doCall(t: T, u: U): V? = function(t, u) +} + + +operator fun Closure.invoke(): T = call() + + +operator fun Closure.invoke(x: Any?): T = call(x) + + +operator fun Closure.invoke(vararg xs: Any?): T = call(*xs) + + +/** + * Executes the given [builder] against this object's [GroovyBuilderScope]. + * + * @see [GroovyBuilderScope] + */ +inline fun Any.withGroovyBuilder(builder: GroovyBuilderScope.() -> T): T = + GroovyBuilderScope.of(this).builder() + + +/** + * Provides a dynamic dispatching DSL with Groovy semantics for better integration with + * plugins that rely on Groovy builders such as the core `maven` plugin. + * + * It supports Groovy keyword arguments and arbitrary nesting, for instance, the following Groovy code: + * + * ```Groovy + * repository(url: "scp://repos.mycompany.com/releases") { + * authentication(userName: "me", password: "myPassword") + * } + * ``` + * + * Can be mechanically translated to the following Kotlin with the aid of `withGroovyBuilder`: + * + * ```Kotlin + * withGroovyBuilder { + * "repository"("url" to "scp://repos.mycompany.com/releases") { + * "authentication"("userName" to "me", "password" to "myPassword") + * } + * } + * ``` + * + * @see [withGroovyBuilder] + */ +interface GroovyBuilderScope : GroovyObject { + + companion object { + + fun of(value: Any): GroovyBuilderScope = + when (value) { + is GroovyObject -> GroovyBuilderScopeForGroovyObject(value) + else -> GroovyBuilderScopeForRegularObject(value) + } + } + + val delegate: Any + + operator fun String.invoke(vararg arguments: Any?): Any? + + operator fun String.invoke(): Any? = + invoke(*emptyArray()) + + operator fun String.invoke(vararg arguments: Any?, builder: GroovyBuilderScope.() -> T): Any? = + invoke(*arguments, closureFor(builder)) + + operator fun String.invoke(builder: GroovyBuilderScope.() -> T): Any? = + invoke(closureFor(builder)) + + operator fun String.invoke(vararg keywordArguments: Pair, builder: GroovyBuilderScope.() -> T): Any? = + invoke(keywordArguments.toMap(), closureFor(builder)) + + operator fun String.invoke(vararg keywordArguments: Pair): Any? = + invoke(keywordArguments.toMap()) + + private + fun closureFor(builder: GroovyBuilderScope.() -> T): Closure = + object : Closure(this, this) { + @Suppress("unused") + fun doCall() = delegate.withGroovyBuilder(builder) + } +} + + +private +class GroovyBuilderScopeForGroovyObject(override val delegate: GroovyObject) : GroovyBuilderScope, GroovyObject by delegate { + + override fun String.invoke(vararg arguments: Any?): Any? = + delegate.invokeMethod(this, arguments) +} + + +private +class GroovyBuilderScopeForRegularObject(override val delegate: Any) : GroovyBuilderScope { + + private + val groovyMetaClass: MetaClass by unsafeLazy { + getMetaClass(delegate) + } + + override fun invokeMethod(name: String, args: Any?): Any? = + groovyMetaClass.invokeMethod(delegate, name, args) + + override fun setProperty(propertyName: String, newValue: Any?) = + groovyMetaClass.setProperty(delegate, propertyName, newValue) + + override fun getProperty(propertyName: String): Any = + groovyMetaClass.getProperty(delegate, propertyName) + + override fun setMetaClass(metaClass: MetaClass?) = + throw IllegalStateException() + + override fun getMetaClass(): MetaClass = + groovyMetaClass + + override fun String.invoke(vararg arguments: Any?): Any? = + groovyMetaClass.invokeMethod(delegate, this, arguments) +} Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinBuildScript.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinBuildScript.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinBuildScript.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,70 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.Project +import org.gradle.api.initialization.dsl.ScriptHandler + +import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptDependenciesResolver +import org.gradle.kotlin.dsl.support.KotlinScriptHost +import org.gradle.kotlin.dsl.support.internalError + +import org.gradle.plugin.use.PluginDependenciesSpec + +import kotlin.script.extensions.SamWithReceiverAnnotations +import kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments +import kotlin.script.templates.ScriptTemplateDefinition + + +/** + * Base class for Kotlin build scripts. + */ +@ScriptTemplateDefinition( + resolver = KotlinBuildScriptDependenciesResolver::class, + scriptFilePattern = ".*\\.gradle\\.kts") +@ScriptTemplateAdditionalCompilerArguments(["-Xjsr305=strict"]) +@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") +@GradleDsl +abstract class KotlinBuildScript( + private val host: KotlinScriptHost +) : Project by host.target { + + /** + * The [ScriptHandler] for this script. + */ + override fun getBuildscript(): ScriptHandler = + host.scriptHandler + + /** + * Configures the build script classpath for this project. + * + * @see [Project.buildscript] + */ + @Suppress("unused") + open fun buildscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit): Unit = + internalError() + + /** + * Configures the plugin dependencies for this project. + * + * @see [PluginDependenciesSpec] + */ + @Suppress("unused") + fun plugins(@Suppress("unused_parameter") block: PluginDependenciesSpecScope.() -> Unit): Unit = + throw Exception("The plugins {} block must not be used here. " + + "If you need to apply a plugin imperatively, please use apply() or apply(plugin = \"id\") instead.") +} Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinInitScript.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinInitScript.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinInitScript.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,407 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.Action +import org.gradle.api.PathValidation +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.ConfigurableFileTree +import org.gradle.api.file.CopySpec +import org.gradle.api.file.DeleteSpec +import org.gradle.api.file.FileTree +import org.gradle.api.initialization.dsl.ScriptHandler +import org.gradle.api.internal.file.DefaultFileOperations +import org.gradle.api.invocation.Gradle +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging +import org.gradle.api.logging.LoggingManager +import org.gradle.api.plugins.ObjectConfigurationAction +import org.gradle.api.plugins.PluginAware +import org.gradle.api.resources.ResourceHandler +import org.gradle.api.tasks.WorkResult + +import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptDependenciesResolver +import org.gradle.kotlin.dsl.support.KotlinScriptHost +import org.gradle.kotlin.dsl.support.internalError +import org.gradle.kotlin.dsl.support.serviceOf +import org.gradle.kotlin.dsl.support.unsafeLazy + +import org.gradle.process.ExecResult +import org.gradle.process.ExecSpec +import org.gradle.process.JavaExecSpec + +import java.io.File +import java.net.URI + +import kotlin.script.extensions.SamWithReceiverAnnotations +import kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments +import kotlin.script.templates.ScriptTemplateDefinition + + +/** + * Base class for Kotlin init scripts. + */ +@ScriptTemplateDefinition( + resolver = KotlinBuildScriptDependenciesResolver::class, + scriptFilePattern = ".+\\.init\\.gradle\\.kts") +@ScriptTemplateAdditionalCompilerArguments(["-Xjsr305=strict"]) +@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") +abstract class KotlinInitScript( + private val host: KotlinScriptHost +) : InitScriptApi(host.target) { + + /** + * The [ScriptHandler] for this script. + */ + val initscript + get() = host.scriptHandler + + /** + * Applies zero or more plugins or scripts. + *

+ * The given action is used to configure an [ObjectConfigurationAction], which “builds” the plugin application. + *

+ * @param action the action to configure an [ObjectConfigurationAction] with before “executing” it + * @see [PluginAware.apply] + */ + override fun apply(action: Action) = + host.applyObjectConfigurationAction(action) + + override val operations + get() = host.operations +} + + +/** + * Standard implementation of the API exposed to all types of [Gradle] scripts, + * precompiled and otherwise. + */ +abstract class InitScriptApi(target: Gradle) : Gradle by target { + + protected + abstract val operations: DefaultFileOperations + + /** + * Configures the classpath of the init script. + */ + @Suppress("unused") + open fun initscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit): Unit = + internalError() + + /** + * Logger for init scripts. You can use this in your init script to write log messages. + */ + @Suppress("unused") + val logger: Logger by unsafeLazy { Logging.getLogger(Gradle::class.java) } + + /** + * The [LoggingManager] which can be used to receive logging and to control the standard output/error capture for + * this script. By default, `System.out` is redirected to the Gradle logging system at the `QUIET` log level, + * and `System.err` is redirected at the `ERROR` log level. + */ + @Suppress("unused") + val logging by unsafeLazy { gradle.serviceOf() } + + /** + * Provides access to resource-specific utility methods, for example factory methods that create various resources. + */ + @Suppress("unused") + val resources: ResourceHandler by unsafeLazy { operations.resources } + + /** + * Returns the relative path from this script's target base directory to the given path. + * + * The given path object is (logically) resolved as described for [KotlinInitScript.file], + * from which a relative path is calculated. + * + * @param path The path to convert to a relative path. + * @return The relative path. + */ + @Suppress("unused") + fun relativePath(path: Any): String = + operations.relativePath(path) + + /** + * Resolves a file path to a URI, relative to this script's target base directory. + * + * Evaluates the provided path object as described for [KotlinInitScript.file], + * with the exception that any URI scheme is supported, not just `file:` URIs. + */ + @Suppress("unused") + fun uri(path: Any): URI = + operations.uri(path) + + /** + * Resolves a file path relative to this script's target base directory. + * + * If this script targets [org.gradle.api.Project], + * then `path` is resolved relative to the project directory. + * + * If this script targets [org.gradle.api.initialization.Settings], + * then `path` is resolved relative to the build root directory. + * + * Otherwise the file is resolved relative to the script itself. + * + * This method converts the supplied path based on its type: + * + * - A [CharSequence], including [String]. + * A string that starts with `file:` is treated as a file URL. + * - A [File]. + * If the file is an absolute file, it is returned as is. Otherwise it is resolved. + * - A [java.nio.file.Path]. + * The path must be associated with the default provider and is treated the same way as an instance of `File`. + * - A [URI] or [java.net.URL]. + * The URL's path is interpreted as the file path. Only `file:` URLs are supported. + * - A [org.gradle.api.file.Directory] or [org.gradle.api.file.RegularFile]. + * - A [org.gradle.api.provider.Provider] of any supported type. + * The provider's value is resolved recursively. + * - A [java.util.concurrent.Callable] that returns any supported type. + * The callable's return value is resolved recursively. + * + * @param path The object to resolve as a `File`. + * @return The resolved file. + */ + @Suppress("unused") + fun file(path: Any): File = + operations.file(path) + + /** + * Resolves a file path relative to this script's target base directory. + * + * @param path The object to resolve as a `File`. + * @param validation The validation to perform on the file. + * @return The resolved file. + * @see KotlinInitScript.file + */ + @Suppress("unused") + fun file(path: Any, validation: PathValidation): File = + operations.file(path, validation) + + /** + * Creates a [ConfigurableFileCollection] containing the given files. + * + * You can pass any of the following types to this method: + * + * - A [CharSequence], including [String] as defined by [KotlinInitScript.file]. + * - A [File] as defined by [KotlinInitScript.file]. + * - A [java.nio.file.Path] as defined by [KotlinInitScript.file]. + * - A [URI] or [java.net.URL] as defined by [KotlinInitScript.file]. + * - A [org.gradle.api.file.Directory] or [org.gradle.api.file.RegularFile] + * as defined by [KotlinInitScript.file]. + * - A [Sequence], [Array] or [Iterable] that contains objects of any supported type. + * The elements of the collection are recursively converted to files. + * - A [org.gradle.api.file.FileCollection]. + * The contents of the collection are included in the returned collection. + * - A [org.gradle.api.provider.Provider] of any supported type. + * The provider's value is recursively converted to files. If the provider represents an output of a task, + * that task is executed if the file collection is used as an input to another task. + * - A [java.util.concurrent.Callable] that returns any supported type. + * The callable's return value is recursively converted to files. + * A `null` return value is treated as an empty collection. + * - A [org.gradle.api.Task]. + * Converted to the task's output files. + * The task is executed if the file collection is used as an input to another task. + * - A [org.gradle.api.tasks.TaskOutputs]. + * Converted to the output files the related task. + * The task is executed if the file collection is used as an input to another task. + * - Anything else is treated as a failure. + * + * The returned file collection is lazy, so that the paths are evaluated only when the contents of the file + * collection are queried. The file collection is also live, so that it evaluates the above each time the contents + * of the collection is queried. + * + * The returned file collection maintains the iteration order of the supplied paths. + * + * The returned file collection maintains the details of the tasks that produce the files, + * so that these tasks are executed if this file collection is used as an input to some task. + * + * This method can also be used to create an empty collection, which can later be mutated to add elements. + * + * @param paths The paths to the files. May be empty. + * @return The file collection. + */ + @Suppress("unused") + fun files(vararg paths: Any): ConfigurableFileCollection = + operations.files(paths) + + /** + * Creates a [ConfigurableFileCollection] containing the given files. + * + * @param paths The contents of the file collection. Evaluated as per [KotlinInitScript.files]. + * @param configuration The block to use to configure the file collection. + * @return The file collection. + * @see KotlinInitScript.files + */ + @Suppress("unused") + fun files(paths: Any, configuration: ConfigurableFileCollection.() -> Unit): ConfigurableFileCollection = + operations.files(paths).also(configuration) + + /** + * Creates a new [ConfigurableFileTree] using the given base directory. + * + * The given `baseDir` path is evaluated as per [KotlinInitScript.file]. + * + * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are + * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are + * queried. + * + * @param baseDir The base directory of the file tree. Evaluated as per [KotlinInitScript.file]. + * @return The file tree. + */ + @Suppress("unused") + fun fileTree(baseDir: Any): ConfigurableFileTree = + operations.fileTree(baseDir) + + /** + * Creates a new [ConfigurableFileTree] using the given base directory. + * + * @param baseDir The base directory of the file tree. Evaluated as per [KotlinInitScript.file]. + * @param configuration The block to use to configure the file tree. + * @return The file tree. + * @see [KotlinInitScript.fileTree] + */ + @Suppress("unused") + fun fileTree(baseDir: Any, configuration: ConfigurableFileTree.() -> Unit): ConfigurableFileTree = + operations.fileTree(baseDir).also(configuration) + + /** + * Creates a new [FileTree] which contains the contents of the given ZIP file. + * + * The given `zipPath` path is evaluated as per [KotlinInitScript.file] + * + * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are + * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are + * queried. + * + * You can combine this method with the [KotlinInitScript.copy] method to unzip a ZIP file. + * + * @param zipPath The ZIP file. Evaluated as per [KotlinInitScript.file]. + * @return The file tree. + */ + @Suppress("unused") + fun zipTree(zipPath: Any): FileTree = + operations.zipTree(zipPath) + + /** + * Creates a new [FileTree] which contains the contents of the given TAR file. + * + * The given tarPath path can be: + * - an instance of [org.gradle.api.resources.Resource], + * - any other object is evaluated as per [KotlinInitScript.file]. + * + * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are + * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are + * queried. + * + * Unless custom implementation of resources is passed, + * the tar tree attempts to guess the compression based on the file extension. + * + * You can combine this method with the [KotlinInitScript.copy] method to unzip a ZIP file. + * + * @param tarPath The TAR file or an instance of [org.gradle.api.resources.Resource]. + * @return The file tree. + */ + @Suppress("unused") + fun tarTree(tarPath: Any): FileTree = + operations.tarTree(tarPath) + + /** + * Copies the specified files. + * + * @param configuration The block to use to configure the [CopySpec]. + * @return `WorkResult` that can be used to check if the copy did any work. + */ + @Suppress("unused") + fun copy(configuration: CopySpec.() -> Unit): WorkResult = + operations.copy(configuration) + + /** + * Creates a {@link CopySpec} which can later be used to copy files or create an archive. + * + * @return The created [CopySpec] + */ + @Suppress("unused") + fun copySpec(): CopySpec = + operations.copySpec() + + /** + * Creates a {@link CopySpec} which can later be used to copy files or create an archive. + * + * @param configuration The block to use to configure the [CopySpec]. + * @return The configured [CopySpec] + */ + @Suppress("unused") + fun copySpec(configuration: CopySpec.() -> Unit): CopySpec = + operations.copySpec().also(configuration) + + /** + * Creates a directory and returns a file pointing to it. + * + * @param path The path for the directory to be created. Evaluated as per [KotlinInitScript.file]. + * @return The created directory. + * @throws org.gradle.api.InvalidUserDataException If the path points to an existing file. + */ + @Suppress("unused") + fun mkdir(path: Any): File = + operations.mkdir(path) + + /** + * Deletes files and directories. + * + * This will not follow symlinks. If you need to follow symlinks too use [KotlinInitScript.delete]. + * + * @param paths Any type of object accepted by [KotlinInitScript.file] + * @return true if anything got deleted, false otherwise + */ + @Suppress("unused") + fun delete(vararg paths: Any): Boolean = + operations.delete(*paths) + + /** + * Deletes the specified files. + * + * @param configuration The block to use to configure the [DeleteSpec]. + * @return `WorkResult` that can be used to check if delete did any work. + */ + @Suppress("unused") + fun delete(configuration: DeleteSpec.() -> Unit): WorkResult = + operations.delete(configuration) + + /** + * Executes an external command. + * + * This method blocks until the process terminates, with its result being returned. + * + * @param configuration The block to use to configure the [ExecSpec]. + * @return The result of the execution. + */ + @Suppress("unused") + fun exec(configuration: ExecSpec.() -> Unit): ExecResult = + operations.exec(configuration) + + /** + * Executes an external Java process. + * + * This method blocks until the process terminates, with its result being returned. + * + * @param configuration The block to use to configure the [JavaExecSpec]. + * @return The result of the execution. + */ + @Suppress("unused") + fun javaexec(configuration: JavaExecSpec.() -> Unit): ExecResult = + operations.javaexec(configuration) +} Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinSettingsScript.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinSettingsScript.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/KotlinSettingsScript.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,452 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl + +import org.gradle.api.Action +import org.gradle.api.PathValidation +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.ConfigurableFileTree +import org.gradle.api.file.CopySpec +import org.gradle.api.file.DeleteSpec +import org.gradle.api.file.FileTree +import org.gradle.api.initialization.Settings +import org.gradle.api.initialization.dsl.ScriptHandler +import org.gradle.api.internal.GradleInternal +import org.gradle.api.internal.file.DefaultFileOperations +import org.gradle.api.internal.file.FileLookup +import org.gradle.api.internal.file.collections.DirectoryFileTreeFactory +import org.gradle.api.invocation.Gradle +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging +import org.gradle.api.logging.LoggingManager +import org.gradle.api.plugins.ObjectConfigurationAction +import org.gradle.api.resources.ResourceHandler +import org.gradle.api.tasks.WorkResult + +import org.gradle.internal.hash.FileHasher +import org.gradle.internal.hash.StreamHasher +import org.gradle.internal.reflect.Instantiator +import org.gradle.internal.resource.TextResourceLoader +import org.gradle.internal.service.ServiceRegistry + +import org.gradle.kotlin.dsl.resolver.KotlinBuildScriptDependenciesResolver +import org.gradle.kotlin.dsl.support.KotlinScriptHost +import org.gradle.kotlin.dsl.support.get +import org.gradle.kotlin.dsl.support.internalError +import org.gradle.kotlin.dsl.support.serviceOf +import org.gradle.kotlin.dsl.support.unsafeLazy + +import org.gradle.process.ExecResult +import org.gradle.process.ExecSpec +import org.gradle.process.JavaExecSpec +import org.gradle.process.internal.ExecFactory + +import java.io.File +import java.net.URI + +import kotlin.script.extensions.SamWithReceiverAnnotations +import kotlin.script.templates.ScriptTemplateAdditionalCompilerArguments +import kotlin.script.templates.ScriptTemplateDefinition + + +/** + * Base class for Kotlin settings scripts. + */ +@ScriptTemplateDefinition( + resolver = KotlinBuildScriptDependenciesResolver::class, + scriptFilePattern = "^(settings|.+\\.settings)\\.gradle\\.kts$") +@ScriptTemplateAdditionalCompilerArguments(["-Xjsr305=strict"]) +@SamWithReceiverAnnotations("org.gradle.api.HasImplicitReceiver") +abstract class KotlinSettingsScript( + private val host: KotlinScriptHost +) : SettingsScriptApi(host.target) { + + /** + * The [ScriptHandler] for this script. + */ + override fun getBuildscript(): ScriptHandler = + host.scriptHandler + + override val fileOperations: DefaultFileOperations + get() = host.operations + + /** + * Applies zero or more plugins or scripts. + * + * @param configuration the block to configure an {@link ObjectConfigurationAction} with before “executing” it + */ + override fun apply(configuration: ObjectConfigurationAction.() -> Unit) = + host.applyObjectConfigurationAction(Action { it.configuration() }) + + override fun apply(action: Action) = + host.applyObjectConfigurationAction(action) +} + + +/** + * Standard implementation of the API exposed to all types of [Settings] scripts, + * precompiled and otherwise. + */ +abstract class SettingsScriptApi(settings: Settings) : Settings by settings { + + protected + abstract val fileOperations: DefaultFileOperations + + /** + * Logger for settings. You can use this in your settings file to write log messages. + */ + @Suppress("unused") + val logger: Logger by unsafeLazy { Logging.getLogger(Settings::class.java) } + + /** + * The [LoggingManager] which can be used to receive logging and to control the standard output/error capture for + * this script. By default, `System.out` is redirected to the Gradle logging system at the `QUIET` log level, + * and `System.err` is redirected at the `ERROR` log level. + */ + @Suppress("unused") + val logging by unsafeLazy { settings.serviceOf() } + + /** + * Provides access to resource-specific utility methods, for example factory methods that create various resources. + */ + @Suppress("unused") + val resources: ResourceHandler by unsafeLazy { fileOperations.resources } + + /** + * Returns the relative path from this script's target base directory to the given path. + * + * The given path object is (logically) resolved as described for [KotlinSettingsScript.file], + * from which a relative path is calculated. + * + * @param path The path to convert to a relative path. + * @return The relative path. + */ + @Suppress("unused") + fun relativePath(path: Any): String = + fileOperations.relativePath(path) + + /** + * Resolves a file path to a URI, relative to this script's target base directory. + * + * Evaluates the provided path object as described for [KotlinSettingsScript.file], + * with the exception that any URI scheme is supported, not just `file:` URIs. + */ + @Suppress("unused") + fun uri(path: Any): URI = + fileOperations.uri(path) + + /** + * Resolves a file path relative to this script's target base directory. + * + * If this script targets [org.gradle.api.Project], + * then `path` is resolved relative to the project directory. + * + * If this script targets [org.gradle.api.initialization.Settings], + * then `path` is resolved relative to the build root directory. + * + * This method converts the supplied path based on its type: + * + * - A [CharSequence], including [String]. + * A string that starts with `file:` is treated as a file URL. + * - A [File]. + * If the file is an absolute file, it is returned as is. Otherwise it is resolved. + * - A [java.nio.file.Path]. + * The path must be associated with the default provider and is treated the same way as an instance of `File`. + * - A [URI] or [java.net.URL]. + * The URL's path is interpreted as the file path. Only `file:` URLs are supported. + * - A [org.gradle.api.file.Directory] or [org.gradle.api.file.RegularFile]. + * - A [org.gradle.api.provider.Provider] of any supported type. + * The provider's value is resolved recursively. + * - A [java.util.concurrent.Callable] that returns any supported type. + * The callable's return value is resolved recursively. + * + * @param path The object to resolve as a `File`. + * @return The resolved file. + */ + @Suppress("unused") + fun file(path: Any): File = + fileOperations.file(path) + + /** + * Resolves a file path relative to this script's target base directory. + * + * @param path The object to resolve as a `File`. + * @param validation The validation to perform on the file. + * @return The resolved file. + * @see KotlinSettingsScript.file + */ + @Suppress("unused") + fun file(path: Any, validation: PathValidation): File = + fileOperations.file(path, validation) + + /** + * Creates a [ConfigurableFileCollection] containing the given files. + * + * You can pass any of the following types to this method: + * + * - A [CharSequence], including [String] as defined by [KotlinSettingsScript.file]. + * - A [File] as defined by [KotlinSettingsScript.file]. + * - A [java.nio.file.Path] as defined by [KotlinSettingsScript.file]. + * - A [URI] or [java.net.URL] as defined by [KotlinSettingsScript.file]. + * - A [org.gradle.api.file.Directory] or [org.gradle.api.file.RegularFile] + * as defined by [KotlinSettingsScript.file]. + * - A [Sequence], [Array] or [Iterable] that contains objects of any supported type. + * The elements of the collection are recursively converted to files. + * - A [org.gradle.api.file.FileCollection]. + * The contents of the collection are included in the returned collection. + * - A [org.gradle.api.provider.Provider] of any supported type. + * The provider's value is recursively converted to files. If the provider represents an output of a task, + * that task is executed if the file collection is used as an input to another task. + * - A [java.util.concurrent.Callable] that returns any supported type. + * The callable's return value is recursively converted to files. + * A `null` return value is treated as an empty collection. + * - A [org.gradle.api.Task]. + * Converted to the task's output files. + * The task is executed if the file collection is used as an input to another task. + * - A [org.gradle.api.tasks.TaskOutputs]. + * Converted to the output files the related task. + * The task is executed if the file collection is used as an input to another task. + * - Anything else is treated as a failure. + * + * The returned file collection is lazy, so that the paths are evaluated only when the contents of the file + * collection are queried. The file collection is also live, so that it evaluates the above each time the contents + * of the collection is queried. + * + * The returned file collection maintains the iteration order of the supplied paths. + * + * The returned file collection maintains the details of the tasks that produce the files, + * so that these tasks are executed if this file collection is used as an input to some task. + * + * This method can also be used to create an empty collection, which can later be mutated to add elements. + * + * @param paths The paths to the files. May be empty. + * @return The file collection. + */ + @Suppress("unused") + fun files(vararg paths: Any): ConfigurableFileCollection = + fileOperations.files(paths) + + /** + * Creates a [ConfigurableFileCollection] containing the given files. + * + * @param paths The contents of the file collection. Evaluated as per [KotlinSettingsScript.files]. + * @param configuration The block to use to configure the file collection. + * @return The file collection. + * @see KotlinSettingsScript.files + */ + @Suppress("unused") + fun files(paths: Any, configuration: ConfigurableFileCollection.() -> Unit): ConfigurableFileCollection = + fileOperations.files(paths).also(configuration) + + /** + * Creates a new [ConfigurableFileTree] using the given base directory. + * + * The given `baseDir` path is evaluated as per [KotlinSettingsScript.file]. + * + * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are + * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are + * queried. + * + * @param baseDir The base directory of the file tree. Evaluated as per [KotlinSettingsScript.file]. + * @return The file tree. + */ + @Suppress("unused") + fun fileTree(baseDir: Any): ConfigurableFileTree = + fileOperations.fileTree(baseDir) + + /** + * Creates a new [ConfigurableFileTree] using the given base directory. + * + * @param baseDir The base directory of the file tree. Evaluated as per [KotlinSettingsScript.file]. + * @param configuration The block to use to configure the file tree. + * @return The file tree. + * @see [KotlinSettingsScript.fileTree] + */ + @Suppress("unused") + fun fileTree(baseDir: Any, configuration: ConfigurableFileTree.() -> Unit): ConfigurableFileTree = + fileOperations.fileTree(baseDir).also(configuration) + + /** + * Creates a new [FileTree] which contains the contents of the given ZIP file. + * + * The given `zipPath` path is evaluated as per [KotlinSettingsScript.file] + * + * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are + * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are + * queried. + * + * You can combine this method with the [KotlinSettingsScript.copy] method to unzip a ZIP file. + * + * @param zipPath The ZIP file. Evaluated as per [KotlinSettingsScript.file]. + * @return The file tree. + */ + @Suppress("unused") + fun zipTree(zipPath: Any): FileTree = + fileOperations.zipTree(zipPath) + + /** + * Creates a new [FileTree] which contains the contents of the given TAR file. + * + * The given tarPath path can be: + * - an instance of [org.gradle.api.resources.Resource], + * - any other object is evaluated as per [KotlinSettingsScript.file]. + * + * The returned file tree is lazy, so that it scans for files only when the contents of the file tree are + * queried. The file tree is also live, so that it scans for files each time the contents of the file tree are + * queried. + * + * Unless custom implementation of resources is passed, + * the tar tree attempts to guess the compression based on the file extension. + * + * You can combine this method with the [KotlinSettingsScript.copy] method to unzip a ZIP file. + * + * @param tarPath The TAR file or an instance of [org.gradle.api.resources.Resource]. + * @return The file tree. + */ + @Suppress("unused") + fun tarTree(tarPath: Any): FileTree = + fileOperations.tarTree(tarPath) + + /** + * Copies the specified files. + * + * @param configuration The block to use to configure the [CopySpec]. + * @return `WorkResult` that can be used to check if the copy did any work. + */ + @Suppress("unused") + fun copy(configuration: CopySpec.() -> Unit): WorkResult = + fileOperations.copy(configuration) + + /** + * Creates a {@link CopySpec} which can later be used to copy files or create an archive. + * + * @return The created [CopySpec] + */ + @Suppress("unused") + fun copySpec(): CopySpec = + fileOperations.copySpec() + + /** + * Creates a {@link CopySpec} which can later be used to copy files or create an archive. + * + * @param configuration The block to use to configure the [CopySpec]. + * @return The configured [CopySpec] + */ + @Suppress("unused") + fun copySpec(configuration: CopySpec.() -> Unit): CopySpec = + fileOperations.copySpec().also(configuration) + + /** + * Creates a directory and returns a file pointing to it. + * + * @param path The path for the directory to be created. Evaluated as per [KotlinSettingsScript.file]. + * @return The created directory. + * @throws org.gradle.api.InvalidUserDataException If the path points to an existing file. + */ + @Suppress("unused") + fun mkdir(path: Any): File = + fileOperations.mkdir(path) + + /** + * Deletes files and directories. + * + * This will not follow symlinks. If you need to follow symlinks too use [KotlinSettingsScript.delete]. + * + * @param paths Any type of object accepted by [KotlinSettingsScript.file] + * @return true if anything got deleted, false otherwise + */ + @Suppress("unused") + fun delete(vararg paths: Any): Boolean = + fileOperations.delete(*paths) + + /** + * Deletes the specified files. + * + * @param configuration The block to use to configure the [DeleteSpec]. + * @return `WorkResult` that can be used to check if delete did any work. + */ + @Suppress("unused") + fun delete(configuration: DeleteSpec.() -> Unit): WorkResult = + fileOperations.delete(configuration) + + /** + * Executes an external command. + * + * This method blocks until the process terminates, with its result being returned. + * + * @param configuration The block to use to configure the [ExecSpec]. + * @return The result of the execution. + */ + @Suppress("unused") + fun exec(configuration: ExecSpec.() -> Unit): ExecResult = + fileOperations.exec(configuration) + + /** + * Executes an external Java process. + * + * This method blocks until the process terminates, with its result being returned. + * + * @param configuration The block to use to configure the [JavaExecSpec]. + * @return The result of the execution. + */ + @Suppress("unused") + fun javaexec(configuration: JavaExecSpec.() -> Unit): ExecResult = + fileOperations.javaexec(configuration) + + /** + * Configures the build script classpath for settings. + * + * @see [Settings.getBuildscript] + */ + @Suppress("unused") + open fun buildscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit): Unit = + internalError() + + /** + * Applies zero or more plugins or scripts. + * + * @param configuration the block to configure an {@link ObjectConfigurationAction} with before “executing” it + */ + open fun apply(configuration: ObjectConfigurationAction.() -> Unit) = + settings.apply({ it.configuration() }) +} + + +internal +fun fileOperationsFor(settings: Settings): DefaultFileOperations = + fileOperationsFor(settings.gradle, settings.rootDir) + + +internal +fun fileOperationsFor(gradle: Gradle, baseDir: File?): DefaultFileOperations = + fileOperationsFor((gradle as GradleInternal).services, baseDir) + + +internal +fun fileOperationsFor(services: ServiceRegistry, baseDir: File?): DefaultFileOperations { + val fileLookup = services.get() + return DefaultFileOperations( + baseDir?.let { fileLookup.getFileResolver(it) } ?: fileLookup.fileResolver, + null, + null, + services.get(), + fileLookup, + services.get(), + services.get(), + services.get(), + services.get(), + services.get()) +} Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectCollectionExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,139 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.NamedDomainObjectCollection +import org.gradle.api.UnknownDomainObjectException + +import org.gradle.kotlin.dsl.support.illegalElementType + +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.full.safeCast + + +/** + * Locates an object by name and casts it to the expected type [T]. + * + * If an object with the given [name] is not found, [UnknownDomainObjectException] is thrown. + * If the object is found but cannot be cast to the expected type [T], [IllegalArgumentException] is thrown. + * + * @param name object name + * @return the object, never null + * @throws [UnknownDomainObjectException] When the given object is not found. + * @throws [IllegalArgumentException] When the given object cannot be cast to the expected type. + */ +@Suppress("extension_shadowed_by_member") +inline fun NamedDomainObjectCollection.getByName(name: String) = + getByName(name).let { + it as? T + ?: throw illegalElementType(this, name, T::class, it::class) + } + + +/** + * Locates an object by name and casts it to the expected [type]. + * + * If an object with the given [name] is not found, [UnknownDomainObjectException] is thrown. + * If the object is found but cannot be cast to the expected [type], [IllegalArgumentException] is thrown. + * + * @param name object name + * @param type expected type + * @return the object, never null + * @throws [UnknownDomainObjectException] When the given object is not found. + * @throws [IllegalArgumentException] When the given object cannot be cast to the expected type. + */ +fun NamedDomainObjectCollection.getByName(name: String, type: KClass): T = + getByName(name).let { + type.safeCast(it) + ?: throw illegalElementType(this, name, type, it::class) + } + + +/** + * Locates an object by name and casts it to the expected type [T] then configures it. + * + * If an object with the given [name] is not found, [UnknownDomainObjectException] is thrown. + * If the object is found but cannot be cast to the expected type [T], [IllegalArgumentException] is thrown. + * + * @param name object name + * @param configure configuration action to apply to the object before returning it + * @return the object, never null + * @throws [UnknownDomainObjectException] When the given object is not found. + * @throws [IllegalArgumentException] When the given object cannot be cast to the expected type. + */ +inline fun NamedDomainObjectCollection.getByName(name: String, configure: T.() -> Unit) = + getByName(name).also(configure) + + +/** + * Idiomatic way of referring to an existing element in a collection + * via a delegate property. + * + * `tasks { val jar by getting }` + */ +inline val > U.getting: U + get() = this + + +/** + * Idiomatic way of referring and configuring an existing element in a collection + * via a delegate property. + * + * `tasks { val jar by getting { group = "My" } }` + */ +fun > U.getting(configuration: T.() -> Unit) = + NamedDomainObjectCollectionDelegateProvider(this, configuration) + + +class NamedDomainObjectCollectionDelegateProvider( + val collection: NamedDomainObjectCollection, + val configuration: T.() -> Unit +) { + + operator fun provideDelegate(thisRef: Any?, property: kotlin.reflect.KProperty<*>): NamedDomainObjectCollection = + collection.apply { + getByName(property.name).apply(configuration) + } +} + + +/** + * Locates an object by name, failing if there is no such object. + * + * @param name The object name + * @return The object with the given name. + * @throws [UnknownDomainObjectException] when there is no such object in this collection. + * + * @see [NamedDomainObjectCollection.getByName] + */ +operator fun NamedDomainObjectCollection.get(name: String): T = + getByName(name) + + +/** + * Allows a [NamedDomainObjectCollection] to be used as a property delegate. + * + * @throws [UnknownDomainObjectException] upon property access when there is no such object in the given collection. + * + * @see [NamedDomainObjectCollection.getByName] + */ +inline operator fun NamedDomainObjectCollection.getValue(thisRef: Any?, property: KProperty<*>): U = + getByName(property.name).let { + it as? U + ?: throw illegalElementType(this, property.name, U::class, it::class) + } Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/NamedDomainObjectContainerExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,214 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.Action +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.PolymorphicDomainObjectContainer + +import kotlin.reflect.KClass +import kotlin.reflect.KProperty + + +/** + * Allows the container to be configured, creating missing objects as they are referenced. + * + * @param configuration The expression to configure this container with + * @return The container. + */ +inline operator fun > C.invoke( + configuration: NamedDomainObjectContainerScope.() -> Unit +): C = + + apply { + configuration(NamedDomainObjectContainerScope(this)) + } + + +/** + * Receiver for [NamedDomainObjectContainer] configuration blocks. + */ +class NamedDomainObjectContainerScope( + private val container: NamedDomainObjectContainer +) : NamedDomainObjectContainer by container, PolymorphicDomainObjectContainer { + + override fun create(name: String, type: Class): U = + polymorphicDomainObjectContainer().create(name, type) + + override fun create(name: String, type: Class, configuration: Action): U = + polymorphicDomainObjectContainer().create(name, type, configuration) + + override fun maybeCreate(name: String, type: Class): U = + polymorphicDomainObjectContainer().maybeCreate(name, type) + + override fun containerWithType(type: Class): NamedDomainObjectContainer = + polymorphicDomainObjectContainer().containerWithType(type) + + /** + * @see [NamedDomainObjectContainer.maybeCreate] + */ + inline operator fun String.invoke(configuration: T.() -> Unit): T = + this().apply(configuration) + + /** + * @see [NamedDomainObjectContainer.maybeCreate] + */ + operator fun String.invoke(): T = + container.maybeCreate(this) + + /** + * @see [PolymorphicDomainObjectContainer.maybeCreate] + */ + inline operator fun String.invoke(type: KClass, configuration: U.() -> Unit): U = + this(type).apply(configuration) + + /** + * @see [PolymorphicDomainObjectContainer.maybeCreate] + */ + operator fun String.invoke(type: KClass): U = + polymorphicDomainObjectContainer().maybeCreate(this, type.java) + + /** + * Cast this to [PolymorphicDomainObjectContainer] or throw [IllegalArgumentException]. + * + * We must rely on the dynamic cast and possible runtime failure here due to a Kotlin extension member limitation. + * Kotlin currently can't disambiguate between invoke operators with more specific receivers in a type hierarchy. + * + * See https://youtrack.jetbrains.com/issue/KT-15711 + */ + private + fun polymorphicDomainObjectContainer() = + container as? PolymorphicDomainObjectContainer + ?: throw IllegalArgumentException("Container '$container' is not polymorphic.") +} + + +/** + * Provides a property delegate that creates elements of the default collection type. + */ +val NamedDomainObjectContainer.creating + get() = NamedDomainObjectContainerDelegateProvider(this, {}) + + +/** + * Provides a property delegate that creates elements of the default collection type with the given [configuration]. + * + * `val myElement by myContainer.creating { myProperty = 42 }` + */ +fun NamedDomainObjectContainer.creating(configuration: T.() -> Unit) = + NamedDomainObjectContainerDelegateProvider(this, configuration) + + +/** + * A property delegate that creates elements in the given [NamedDomainObjectContainer]. + * + * See [creating] + */ +class NamedDomainObjectContainerDelegateProvider( + val container: NamedDomainObjectContainer, + val configuration: T.() -> Unit +) { + + operator fun provideDelegate(thisRef: Any?, property: KProperty<*>) = + container.apply { + create(property.name).apply(configuration) + } +} + + +/** + * Provides a property delegate that creates elements of the given [type]. + */ +fun PolymorphicDomainObjectContainer.creating(type: KClass) = + creating(type.java, {}) + + +/** + * Provides a property delegate that creates elements of the given [type] with the given [configuration]. + */ +fun PolymorphicDomainObjectContainer.creating(type: KClass, configuration: U.() -> Unit) = + creating(type.java, configuration) + + +/** + * Provides a property delegate that creates elements of the given [type] expressed as a [java.lang.Class] + * with the given [configuration]. + */ +fun PolymorphicDomainObjectContainer.creating(type: Class, configuration: U.() -> Unit) = + PolymorphicDomainObjectContainerDelegateProvider(this, type, configuration) + + +/** + * A property delegate that creates elements of the given [type] with the given [configuration] in the given [container]. + */ +class PolymorphicDomainObjectContainerDelegateProvider( + val container: PolymorphicDomainObjectContainer, + val type: Class, + val configuration: U.() -> Unit +) { + + @Suppress("unchecked_cast") + operator fun provideDelegate(thisRef: Any?, property: KProperty<*>) = + container.apply { + create(property.name, type).apply(configuration) + } as PolymorphicDomainObjectContainer +} + + +/** + * Provides a property delegate that gets elements of the given [type] and applies the given [configuration]. + */ +fun NamedDomainObjectContainer.getting(type: KClass, configuration: U.() -> Unit) = + PolymorphicDomainObjectContainerGettingDelegateProvider(this, type, configuration) + + +/** + * Provides a property delegate that gets elements of the given [type]. + */ +fun NamedDomainObjectContainer.getting(type: KClass) = + PolymorphicDomainObjectContainerGettingDelegate(this, type) + + +/** + * A property delegate that gets elements of the given [type] in the given [container]. + */ +class PolymorphicDomainObjectContainerGettingDelegate( + val container: NamedDomainObjectContainer, + val type: KClass +) { + + operator fun getValue(receiver: Any?, property: kotlin.reflect.KProperty<*>): U = + container.getByName(property.name, type) +} + + +/** + * A property delegate that gets elements of the given [type] from the given [container] + * and applies the given [configuration]. + */ +class PolymorphicDomainObjectContainerGettingDelegateProvider( + val container: NamedDomainObjectContainer, + val type: KClass, + val configuration: U.() -> Unit +) { + + @Suppress("unchecked_cast") + operator fun provideDelegate(thisRef: Any?, property: KProperty<*>) = + container.apply { + getByName(property.name, type).configuration() + } as NamedDomainObjectContainer +} Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ObjectConfigurationActionExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ObjectConfigurationActionExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ObjectConfigurationActionExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,31 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.Plugin +import org.gradle.api.plugins.ObjectConfigurationAction + + +/** + * Adds a Plugin to use to configure the target objects. This method may be called + * multiple times, to use multiple plugins. Scripts and plugins are applied in the order + * that they are added. + * + * @param T the plugin to apply. + */ +inline fun > ObjectConfigurationAction.plugin() = + this.plugin(T::class.java) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginAwareExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,70 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.plugins.PluginAware + + +/** + * Applies the given plugin or script. + * + * @param from a script to apply, evaluated as per [Project.file] + * @param plugin a id of the plugin to apply + * @param to the plugin target object or collection of objects, target is self when null + * @see [PluginAware.apply] + */ +fun PluginAware.apply(from: Any? = null, plugin: String? = null, to: Any? = null) { + require(from != null || plugin != null) { "At least one of 'from' or 'plugin' must be given." } + apply { + if (plugin != null) it.plugin(plugin) + if (from != null) it.from(from) + if (to != null) it.to(to) + } +} + + +/** + * Applies the plugin of the given type [T]. Does nothing if the plugin has already been applied. + * + * The given class should implement the [Plugin] interface. + * + * @param T the plugin type. + * @see [PluginAware.apply] + */ +inline fun > PluginAware.apply() { + apply { + it.plugin(T::class.java) + } +} + + +/** + * Applies the plugin of the given type [T] to the specified object. Does nothing if the plugin has already been applied. + * + * The given class should implement the [Plugin] interface. + * + * @param T the plugin type. + * @param to the plugin target object or collection of objects + * @see [PluginAware.apply] + */ +inline fun > PluginAware.apply(to: Any) { + apply { + it.plugin(T::class.java) + it.to(to) + } +} Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,33 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.kotlin.dsl + +import org.gradle.plugin.management.internal.autoapply.AutoAppliedBuildScanPlugin +import org.gradle.plugin.use.PluginDependenciesSpec +import org.gradle.plugin.use.PluginDependencySpec + + +/** + * The `build-scan` plugin. + * + * Visit the [Build Scan Plugin User Manual](https://docs.gradle.com/build-scan-plugin/) for additional information. + * + * By default, the applied plugin version will be the same as the one used by the `--scan` command line option. + * + * You can also use e.g. `` `build-scan` version "1.8" `` to request a different version. + */ +val PluginDependenciesSpec.`build-scan`: PluginDependencySpec + get() = id(AutoAppliedBuildScanPlugin.ID.id) version AutoAppliedBuildScanPlugin.VERSION Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScope.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScope.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PluginDependenciesSpecScope.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,49 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.plugin.use.PluginDependenciesSpec +import org.gradle.plugin.use.PluginDependencySpec + + +/** + * Receiver for the `plugins` block. + * + * This class exists for the sole purpose of marking the `plugins` block as a [GradleDsl] thus + * hiding all members provided by the outer [KotlinBuildScript] scope. + * + * @see [PluginDependenciesSpec] + */ +@GradleDsl +class PluginDependenciesSpecScope(plugins: PluginDependenciesSpec) : PluginDependenciesSpec by plugins + + +/** + * Specify the version of the plugin to depend on. + * + * Infix version of [PluginDependencySpec.version]. + */ +infix fun PluginDependencySpec.version(version: String?): PluginDependencySpec = version(version) + + +/** + * Specifies whether the plugin should be applied to the current project. Otherwise it is only put + * on the project's classpath. + * + * Infix version of [PluginDependencySpec.apply]. + */ +infix fun PluginDependencySpec.apply(apply: Boolean): PluginDependencySpec = apply(apply) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PolymorphicDomainObjectContainerExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PolymorphicDomainObjectContainerExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/PolymorphicDomainObjectContainerExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,71 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.InvalidUserDataException +import org.gradle.api.PolymorphicDomainObjectContainer + + +/** + * Creates a domain object with the specified name and type, adds it to the container, + * and configures it with the specified action. + * + * @param name the name of the domain object to be created + * @param configuration an action for configuring the domain object + * @param the type of the domain object to be created + * @return the created domain object + * @throws [InvalidUserDataException] if a domain object with the specified name already + * exists or the container does not support creating a domain object with the specified + * type + */ +inline fun PolymorphicDomainObjectContainer.create( + name: String, + crossinline configuration: U.() -> Unit +) = + + this.create(name, U::class.java, { configuration(it) }) + + +/** + * Creates a domain object with the specified name and type, and adds it to the container. + * + * @param name the name of the domain object to be created + * @param the type of the domain object to be created + * @return the created domain object + * @throws [InvalidUserDataException] if a domain object with the specified name already + * exists or the container does not support creating a domain object with the specified + * type + */ +@Suppress("extension_shadowed_by_member") +inline fun PolymorphicDomainObjectContainer.create(name: String) = + create(name, U::class.java) + + +/** + * Creates a domain object with the specified name and type if it does not exists, and adds it to the container. + * + * @param name the name of the domain object to be created + * @param the type of the domain object to be created + * @return the created domain object + * @throws [InvalidUserDataException] if a domain object with the specified name already + * exists or the container does not support creating a domain object with the specified + * type + * @throws [ClassCastException] if a domain object with the specified name exists with a different type + */ +@Suppress("extension_shadowed_by_member") +inline fun PolymorphicDomainObjectContainer.maybeCreate(name: String) = + maybeCreate(name, U::class.java) Index: subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ProjectExtensions.kt =================================================================== diff -u -N --- subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ProjectExtensions.kt (revision 0) +++ subprojects/provider/src/main/kotlin/org/gradle/kotlin/dsl/ProjectExtensions.kt (revision 071d76cf5c78736f00c22fd6240ed425df3acf51) @@ -0,0 +1,240 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.kotlin.dsl + +import org.gradle.api.DefaultTask +import org.gradle.api.Incubating +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.model.ObjectFactory + +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.dsl.RepositoryHandler + +import org.gradle.api.file.FileCollection + +import org.gradle.api.initialization.dsl.ScriptHandler + +import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency +import org.gradle.api.internal.file.DefaultFileCollectionFactory +import org.gradle.api.internal.file.FileCollectionInternal + +import org.gradle.api.plugins.Convention +import org.gradle.api.plugins.PluginAware + +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.PropertyState + +import org.gradle.api.tasks.TaskContainer + +import org.gradle.kotlin.dsl.provider.gradleKotlinDslOf +import org.gradle.kotlin.dsl.support.configureWith + +import java.io.File + +import kotlin.reflect.KClass +import kotlin.reflect.KProperty + + +fun Project.buildscript(action: ScriptHandlerScope.() -> Unit): Unit = + project.buildscript.configureWith(action) + + +/** + * Sets the default tasks of this project. These are used when no tasks names are provided when + * starting the build. + */ +@Suppress("nothing_to_inline") +inline fun Project.defaultTasks(vararg tasks: Task) { + defaultTasks(*tasks.map { it.name }.toTypedArray()) +} + + +/** + * Applies the plugin of the given type [T]. Does nothing if the plugin has already been applied. + * + * The given class should implement the [Plugin] interface, and be parameterized for a + * compatible type of `this`. + * + * @param T the plugin type. + * @see [PluginAware.apply] + */ +inline fun > Project.apply() = + (this as PluginAware).apply() + + +/** + * Executes the given configuration block against the [plugin convention] + * [Convention.getPlugin] or extension of the specified type. + * + * @param T the plugin convention type. + * @param configuration the configuration block. + * @see [Convention.getPlugin] + */ +inline fun Project.configure(noinline configuration: T.() -> Unit): Unit = + typeOf().let { type -> + convention.findByType(type)?.let(configuration) + ?: convention.findPlugin()?.let(configuration) + ?: convention.configure(type, configuration) + } + + +/** + * Returns the plugin convention or extension of the specified type. + */ +inline fun Project.the(): T = + typeOf().let { type -> + convention.findByType(type) + ?: convention.findPlugin(T::class.java) + ?: convention.getByType(type) + } + + +/** + * Returns the plugin convention or extension of the specified type. + */ +fun Project.the(extensionType: KClass): T = + convention.findByType(extensionType.java) + ?: convention.findPlugin(extensionType.java) + ?: convention.getByType(extensionType.java) + + +/** + * Creates a [Task] with the given [name] and [type], configures it with the given [configuration] action, + * and adds it to this project tasks container. + */ +inline fun Project.task(name: String, noinline configuration: type.() -> Unit) = + task(name, type::class, configuration) + + +/** + * Creates a [Task] with the given [name] and [type], and adds it to this project tasks container. + * + * @see [Project.getTasks] + * @see [TaskContainer.create] + */ +@Suppress("extension_shadowed_by_member") +inline fun Project.task(name: String) = + tasks.create(name, type::class.java) + + +fun Project.task(name: String, type: KClass, configuration: T.() -> Unit) = + createTask(name, type, configuration) + + +/** + * Creates a [Task] with the given [name] and [DefaultTask] type, configures it with the given [configuration] action, + * and adds it to this project tasks container. + */ +fun Project.task(name: String, configuration: Task.() -> Unit): DefaultTask = + createTask(name, DefaultTask::class, configuration) + + +fun Project.createTask(name: String, type: KClass, configuration: T.() -> Unit): T = + tasks.create(name, type.java, configuration) + + +/** + * Configures the repositories for this project. + * + * Executes the given configuration block against the [RepositoryHandler] for this + * project. + * + * @param configuration the configuration block. + */ +fun Project.repositories(configuration: RepositoryHandler.() -> Unit) = + repositories.configuration() + + +fun ScriptHandler.repositories(configuration: RepositoryHandler.() -> Unit) = + repositories.configuration() + + +/** + * Configures the dependencies for this project. + * + * Executes the given configuration block against the [DependencyHandlerScope] for this + * project. + * + * @param configuration the configuration block. + */ +fun Project.dependencies(configuration: DependencyHandlerScope.() -> Unit) = + DependencyHandlerScope(dependencies).configuration() + + +/** +