From d6becee2ce531f3e0aeb57e821c997de1df1c347 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Mon, 21 Aug 2023 19:21:44 +0200 Subject: [PATCH] [Gradle] Read 'local.properties' in project isolation compatible way ^KT-59826 In Progress --- .../gradle/plugin/PropertiesProvider.kt | 129 ++++++++---------- .../InternalGradlePropertiesUsageChecker.kt | 4 +- .../CustomPropertiesFileValueSource.kt | 52 +++++++ .../mpp/internal/deprecationDiagnostics.kt | 4 +- .../kotlin/gradle/utils/fileUtils.kt | 68 ++++++--- ...60388PlainJvmDependingOnJvmWithJavaTest.kt | 26 +++- .../kotlin/gradle/util/buildProject.kt | 14 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 2 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 2 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 2 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 2 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 2 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 2 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 2 +- .../kotlin/gradle/plugin/PluginWrappers.kt | 2 +- 15 files changed, 194 insertions(+), 119 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/CustomPropertiesFileValueSource.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt index 1a6ae2137ce..82ea02ecefd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt @@ -55,68 +55,57 @@ import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinIrJsGeneratedTSValidation import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrOutputGranularity import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader +import org.jetbrains.kotlin.gradle.utils.loadProperty +import org.jetbrains.kotlin.gradle.utils.localProperties import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.presetName import org.jetbrains.kotlin.statistics.metrics.StringMetrics -import org.jetbrains.kotlin.tooling.core.UnsafeApi import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly import org.jetbrains.kotlin.util.capitalizeDecapitalize.toUpperCaseAsciiOnly import org.jetbrains.kotlin.util.prefixIfNot import java.io.File -import java.util.* -@OptIn(UnsafeApi::class) internal class PropertiesProvider private constructor(private val project: Project) { - private val localProperties: Properties by lazy { - Properties().apply { - val localPropertiesFile = File(project.rootDir, "local.properties") - if (localPropertiesFile.isFile) { - localPropertiesFile.inputStream().use { - load(it) - } - } - } - } @Deprecated(message = "Please use kotlin.build.report.output=SINGLE_FILE and kotlin.build.report.single_file ") val singleBuildMetricsFile: File? - get() = this.property("kotlin.internal.single.build.metrics.file")?.let { File(it) } + get() = property("kotlin.internal.single.build.metrics.file").orNull?.let { File(it) } val buildReportSingleFile: File? - get() = this.property(PropertyNames.KOTLIN_BUILD_REPORT_SINGLE_FILE)?.let { File(it) } + get() = property(PropertyNames.KOTLIN_BUILD_REPORT_SINGLE_FILE).orNull?.let { File(it) } val buildReportOutputs: List - get() = this.property("kotlin.build.report.output")?.split(",") ?: emptyList() + get() = property("kotlin.build.report.output").orNull?.split(",") ?: emptyList() val buildReportLabel: String? - get() = this.property("kotlin.build.report.label") + get() = property("kotlin.build.report.label").orNull val buildReportFileOutputDir: File? - get() = this.property("kotlin.build.report.file.output_dir")?.let { File(it) } + get() = property("kotlin.build.report.file.output_dir").orNull?.let { File(it) } val buildReportHttpUrl: String? - get() = this.property(PropertyNames.KOTLIN_BUILD_REPORT_HTTP_URL) + get() = property(PropertyNames.KOTLIN_BUILD_REPORT_HTTP_URL).orNull val buildReportHttpUser: String? - get() = this.property("kotlin.build.report.http.user") + get() = property("kotlin.build.report.http.user").orNull val buildReportHttpPassword: String? - get() = this.property("kotlin.build.report.http.password") + get() = property("kotlin.build.report.http.password").orNull val buildReportHttpVerboseEnvironment: Boolean - get() = property("kotlin.build.report.http.verbose_environment")?.toBoolean() ?: false + get() = property("kotlin.build.report.http.verbose_environment").orNull?.toBoolean() ?: false val buildReportHttpIncludeGitBranchName: Boolean - get() = property("kotlin.build.report.http.include_git_branch.name")?.toBoolean() ?: false + get() = property("kotlin.build.report.http.include_git_branch.name").orNull?.toBoolean() ?: false val buildReportIncludeCompilerArguments: Boolean get() = booleanProperty("kotlin.build.report.include_compiler_arguments") ?: true val buildReportBuildScanCustomValuesLimit: Int - get() = property("kotlin.build.report.build_scan.custom_values_limit")?.toInt() ?: 1000 + get() = property("kotlin.build.report.build_scan.custom_values_limit").orNull?.toInt() ?: 1000 val buildReportBuildScanMetrics: String? - get() = property("kotlin.build.report.build_scan.metrics") + get() = property("kotlin.build.report.build_scan.metrics").orNull val buildReportMetrics: Boolean get() = booleanProperty("kotlin.build.report.metrics") ?: false @@ -126,7 +115,7 @@ internal class PropertiesProvider private constructor(private val project: Proje @Deprecated("Please use \"kotlin.build.report.file.output_dir\" property instead") val buildReportDir: File? - get() = this.property("kotlin.build.report.dir")?.let { File(it) } + get() = property("kotlin.build.report.dir").orNull?.let { File(it) } val incrementalJvm: Boolean? get() = booleanProperty("kotlin.incremental") @@ -144,22 +133,24 @@ internal class PropertiesProvider private constructor(private val project: Proje get() = booleanProperty(PropertyNames.KOTLIN_NATIVE_INCREMENTAL_COMPILATION) val jsIrOutputGranularity: KotlinJsIrOutputGranularity - get() = this.property("kotlin.js.ir.output.granularity")?.let { KotlinJsIrOutputGranularity.byArgument(it) } + get() = property("kotlin.js.ir.output.granularity").orNull?.let { KotlinJsIrOutputGranularity.byArgument(it) } ?: KotlinJsIrOutputGranularity.PER_MODULE val jsIrGeneratedTypeScriptValidationDevStrategy: KotlinIrJsGeneratedTSValidationStrategy - get() = this.property("kotlin.js.ir.development.typescript.validation.strategy")?.let { - KotlinIrJsGeneratedTSValidationStrategy.byArgument( - it - ) - } ?: KotlinIrJsGeneratedTSValidationStrategy.IGNORE + get() = property("kotlin.js.ir.development.typescript.validation.strategy") + .orNull?.let { + KotlinIrJsGeneratedTSValidationStrategy.byArgument( + it + ) + } ?: KotlinIrJsGeneratedTSValidationStrategy.IGNORE val jsIrGeneratedTypeScriptValidationProdStrategy: KotlinIrJsGeneratedTSValidationStrategy - get() = this.property("kotlin.js.ir.production.typescript.validation.strategy")?.let { - KotlinIrJsGeneratedTSValidationStrategy.byArgument( - it - ) - } ?: KotlinIrJsGeneratedTSValidationStrategy.IGNORE + get() = property("kotlin.js.ir.production.typescript.validation.strategy") + .orNull?.let { + KotlinIrJsGeneratedTSValidationStrategy.byArgument( + it + ) + } ?: KotlinIrJsGeneratedTSValidationStrategy.IGNORE val incrementalMultiplatform: Boolean? get() = booleanProperty("kotlin.incremental.multiplatform") @@ -251,7 +242,7 @@ internal class PropertiesProvider private constructor(private val project: Proje get() = booleanProperty(KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN) ?: false val mppAndroidSourceSetLayoutVersion: Int? - get() = this.property(KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION)?.toIntOrNull() + get() = this.property(KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION).orNull?.toIntOrNull() val ignoreMppAndroidSourceSetLayoutV2AndroidStyleDirs: Boolean get() = booleanProperty(KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_ANDROID_STYLE_NO_WARN) ?: false @@ -280,7 +271,7 @@ internal class PropertiesProvider private constructor(private val project: Proje * - prebuilt - Includes all platform libraries. */ val nativeDistributionType: String? - get() = this.property("kotlin.native.distribution.type") + get() = property("kotlin.native.distribution.type").orNull /** * Allows overriding Kotlin/Native base download url. @@ -288,7 +279,7 @@ internal class PropertiesProvider private constructor(private val project: Proje * When Kotlin/native will try to download native compiler, it will append compiler version and os type to this url. */ val nativeBaseDownloadUrl: String - get() = this.property("kotlin.native.distribution.baseDownloadUrl") ?: NativeCompilerDownloader.BASE_DOWNLOAD_URL + get() = property("kotlin.native.distribution.baseDownloadUrl").orNull ?: NativeCompilerDownloader.BASE_DOWNLOAD_URL /** * Allows downloading Kotlin/Native distribution with maven. @@ -332,7 +323,7 @@ internal class PropertiesProvider private constructor(private val project: Proje * Allows a user to specify free compiler arguments for K/N linker. */ val nativeLinkArgs: List - get() = this.property("kotlin.native.linkArgs").orEmpty().split(' ').filterNot { it.isBlank() } + get() = property("kotlin.native.linkArgs").orNull.orEmpty().split(' ').filterNot { it.isBlank() } /** * Forces to run a compilation in a separate JVM. @@ -390,7 +381,7 @@ internal class PropertiesProvider private constructor(private val project: Proje } val commonizerLogLevel: String? - get() = this.property("kotlin.mpp.commonizerLogLevel") + get() = property("kotlin.mpp.commonizerLogLevel").orNull val enableNativeDistributionCommonizationCache: Boolean get() = booleanProperty("kotlin.mpp.enableNativeDistributionCommonizationCache") ?: true @@ -408,25 +399,25 @@ internal class PropertiesProvider private constructor(private val project: Proje * Dependencies caching strategy for all targets that support caches. */ val nativeCacheKind: NativeCacheKind? - get() = this.property("kotlin.native.cacheKind")?.let { NativeCacheKind.byCompilerArgument(it) } + get() = property("kotlin.native.cacheKind").orNull?.let { NativeCacheKind.byCompilerArgument(it) } /** * Dependencies caching strategy for [target]. */ fun nativeCacheKindForTarget(target: KonanTarget): NativeCacheKind? = - this.property("kotlin.native.cacheKind.${target.presetName}")?.let { NativeCacheKind.byCompilerArgument(it) } + property("kotlin.native.cacheKind.${target.presetName}").orNull?.let { NativeCacheKind.byCompilerArgument(it) } /** * Dependencies caching orchestration machinery. */ val nativeCacheOrchestration: NativeCacheOrchestration? - get() = this.property(PropertyNames.KOTLIN_NATIVE_CACHE_ORCHESTRATION)?.let { NativeCacheOrchestration.byCompilerArgument(it) } + get() = property(PropertyNames.KOTLIN_NATIVE_CACHE_ORCHESTRATION).orNull?.let { NativeCacheOrchestration.byCompilerArgument(it) } /** * Native backend threads. */ val nativeParallelThreads: Int? - get() = this.property(PropertyNames.KOTLIN_NATIVE_PARALLEL_THREADS)?.toInt() + get() = this.property(PropertyNames.KOTLIN_NATIVE_PARALLEL_THREADS).orNull?.toInt() /** * Ignore overflow in [org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessageOutputStreamHandler] @@ -441,7 +432,7 @@ internal class PropertiesProvider private constructor(private val project: Proje * Use Kotlin/JS backend compiler type */ val jsCompiler: KotlinJsCompilerType? - get() = this.property(jsCompilerProperty)?.let { KotlinJsCompilerType.byArgumentOrNull(it) } + get() = this.property(jsCompilerProperty).orNull?.let { KotlinJsCompilerType.byArgumentOrNull(it) } /** * Use Kotlin/JS backend compiler publishing attribute @@ -480,11 +471,11 @@ internal class PropertiesProvider private constructor(private val project: Proje ) val kotlinDaemonJvmArgs: String? - get() = this.property("kotlin.daemon.jvmargs") + get() = property("kotlin.daemon.jvmargs").orNull val kotlinCompilerExecutionStrategy: KotlinCompilerExecutionStrategy get() = KotlinCompilerExecutionStrategy.fromProperty( - this.property("kotlin.compiler.execution.strategy")?.toLowerCaseAsciiOnly() + this.property("kotlin.compiler.execution.strategy").orNull?.toLowerCaseAsciiOnly() ) val kotlinDaemonUseFallbackStrategy: Boolean @@ -534,10 +525,10 @@ internal class PropertiesProvider private constructor(private val project: Proje get() = booleanProperty(KOTLIN_INTERNAL_DIAGNOSTICS_SHOW_STACKTRACE) val suppressedGradlePluginWarnings: List - get() = property(PropertyNames.KOTLIN_SUPPRESS_GRADLE_PLUGIN_WARNINGS)?.split(",").orEmpty() + get() = property(PropertyNames.KOTLIN_SUPPRESS_GRADLE_PLUGIN_WARNINGS).orNull?.split(",").orEmpty() val suppressedGradlePluginErrors: List - get() = property(PropertyNames.KOTLIN_SUPPRESS_GRADLE_PLUGIN_ERRORS)?.split(",").orEmpty() + get() = property(PropertyNames.KOTLIN_SUPPRESS_GRADLE_PLUGIN_ERRORS).orNull?.split(",").orEmpty() val suppressExperimentalArtifactsDslWarning: Boolean get() = booleanProperty(KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING) ?: false @@ -547,7 +538,7 @@ internal class PropertiesProvider private constructor(private val project: Proje * This property takes precedence over the 'KONAN_DATA_DIR' environment variable. */ val konanDataDir: String? - get() = property(PropertyNames.KONAN_DATA_DIR) + get() = property(PropertyNames.KONAN_DATA_DIR).orNull /** * Allows suppressing the diagnostic [KotlinToolingDiagnostics.BuildToolsApiVersionInconsistency]. @@ -561,49 +552,37 @@ internal class PropertiesProvider private constructor(private val project: Proje * @see KOTLIN_JS_KARMA_BROWSERS */ fun jsKarmaBrowsers(target: KotlinTarget? = null): String? = - target?.name?.prefixIfNot("$KOTLIN_JS_KARMA_BROWSERS.")?.let(::property) ?: property(KOTLIN_JS_KARMA_BROWSERS) + target?.name?.prefixIfNot("$KOTLIN_JS_KARMA_BROWSERS.")?.let { property(it).orNull } + ?: property(KOTLIN_JS_KARMA_BROWSERS).orNull private fun propertyWithDeprecatedVariant(propName: String, deprecatedPropName: String): String? { - val deprecatedProperty = this.property(deprecatedPropName) + val deprecatedProperty = property(deprecatedPropName).orNull if (deprecatedProperty != null) { project.reportDiagnosticOncePerBuild(KotlinToolingDiagnostics.DeprecatedPropertyWithReplacement(deprecatedProperty, propName)) } - return this.property(propName) ?: deprecatedProperty + return property(propName).orNull ?: deprecatedProperty } private fun booleanProperty(propName: String): Boolean? = - this.property(propName)?.toBoolean() + property(propName).orNull?.toBoolean() private inline fun > enumProperty( propName: String, defaultValue: T, - ): T = this.property(propName)?.let { enumValueOf(it.toUpperCaseAsciiOnly()) } ?: defaultValue + ): T = this.property(propName).orNull?.let { enumValueOf(it.toUpperCaseAsciiOnly()) } ?: defaultValue - /** - * Looks up the property in the following sources with decreasing priority: - * 1. Project properties (-P, gradle.properties, etc...) - * 2. `local.properties` - * - * Please prefer using dedicated properties for proper defaults handling. - * Use this API only if you specifically need declared project properties disregarding defaults. - */ - @UnsafeApi - internal fun property(propName: String): String? = - if (project.hasProperty(propName)) { - project.property(propName) as? String - } else { - localProperties.getProperty(propName) - } + private val localProperties = project.localProperties + internal fun property(propName: String): Provider = project.loadProperty(propName, localProperties) private fun propertiesWithPrefix(prefix: String): Map { val result: MutableMap = mutableMapOf() project.properties.forEach { (name, value) -> if (name.startsWith(prefix) && value is String) { - result.put(name, value) + result[name] = value } } - localProperties.forEach { (name, value) -> - if (name is String && name.startsWith(prefix) && value is String) { + localProperties.orNull?.forEach { (name, value) -> + if (name.startsWith(prefix)) { // Project properties have higher priority. result.putIfAbsent(name, value) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/InternalGradlePropertiesUsageChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/InternalGradlePropertiesUsageChecker.kt index 0d02d822143..bf26b700a29 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/InternalGradlePropertiesUsageChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/InternalGradlePropertiesUsageChecker.kt @@ -12,15 +12,13 @@ import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector -import org.jetbrains.kotlin.tooling.core.UnsafeApi internal object InternalGradlePropertiesUsageChecker : KotlinGradleProjectChecker { override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) { KotlinPluginLifecycle.Stage.ReadyForExecution.await() val internalPropertiesUsed = PropertiesProvider.PropertyNames.allInternalProperties().filter { name -> - @OptIn(UnsafeApi::class) - kotlinPropertiesProvider.property(name) != null + kotlinPropertiesProvider.property(name).orNull != null } val internalPropertiesFiltered = internalPropertiesUsed.minus(PropertiesProvider.PropertyNames.MPP_13X_FLAGS_SET_BY_PLUGIN) if (internalPropertiesFiltered.isEmpty()) return diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/CustomPropertiesFileValueSource.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/CustomPropertiesFileValueSource.kt new file mode 100644 index 00000000000..b3235fec032 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/CustomPropertiesFileValueSource.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.internal + +import org.gradle.api.Describable +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.ValueSource +import org.gradle.api.provider.ValueSourceParameters +import java.util.* + +/** + * Allow loading a properties file content in configuration cache and project isolation compatible way by specifying + * [Parameters.propertiesFile]. + * + * Returned type is `Map` due to the following [bug in Gradle](https://github.com/gradle/gradle/pull/24846) which + * prevents proper serialization of [Properties] type. + * + * If the file does not exist - returned provider will be empty. + * + * Usage: + * ``` + * project + * .providers + * .of(CustomFileValueSource::class.java) { + * it.parameters.propertiesFile.set(project.layout.projectDirectory.file("my-properties-file-to-load")) + * } + * ``` + */ +internal abstract class CustomPropertiesFileValueSource : ValueSource, CustomPropertiesFileValueSource.Parameters>, + Describable { + + interface Parameters : ValueSourceParameters { + val propertiesFile: RegularFileProperty + } + + override fun getDisplayName(): String = "properties file ${parameters.propertiesFile.get().asFile.absolutePath}" + + override fun obtain(): Map? { + val customFile = parameters.propertiesFile.get().asFile + return if (customFile.exists()) { + customFile.bufferedReader().use { + @Suppress("UNCHECKED_CAST") + Properties().apply { load(it) }.toMap() as Map + } + } else { + null + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/deprecationDiagnostics.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/deprecationDiagnostics.kt index 2132b9fc6b3..8c36642b81a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/deprecationDiagnostics.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/deprecationDiagnostics.kt @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_DEPENDENCY_PROPAGATION import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics import org.jetbrains.kotlin.gradle.plugin.diagnostics.kotlinToolingDiagnosticsCollector -import org.jetbrains.kotlin.tooling.core.UnsafeApi internal fun runDeprecationDiagnostics(project: Project) { checkAndReportDeprecatedMppProperties(project) @@ -32,8 +31,7 @@ private fun checkAndReportDeprecatedMppProperties(project: Project) { if (propertyName in propertiesSetByPlugin && projectProperties.mpp13XFlagsSetByPlugin) return@mapNotNull null - @OptIn(UnsafeApi::class) - propertyName.takeIf { projectProperties.property(propertyName) != null } + propertyName.takeIf { projectProperties.property(propertyName).orNull != null } } if (usedProperties.isEmpty()) return diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt index ae37b616569..aed46814b8a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/fileUtils.kt @@ -9,16 +9,16 @@ import org.gradle.api.Project import org.gradle.api.file.Directory import org.gradle.api.file.RegularFile import org.gradle.api.provider.Provider +import org.jetbrains.kotlin.gradle.plugin.extraProperties +import org.jetbrains.kotlin.gradle.plugin.getOrNull +import org.jetbrains.kotlin.gradle.plugin.internal.CustomPropertiesFileValueSource +import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor +import org.jetbrains.kotlin.gradle.plugin.internal.usedAtConfigurationTime import java.io.File import java.io.IOException import java.nio.file.Files import java.nio.file.Paths - -internal fun File.isJavaFile() = - extension.equals("java", ignoreCase = true) - -internal fun File.isKotlinFile(sourceFilesExtensions: List): Boolean = - !isJavaFile() && sourceFilesExtensions.any { it.equals(extension, ignoreCase = true) } +import java.util.* /** * Create all possible case-sensitive permutations for given [String]. @@ -52,9 +52,6 @@ internal fun File.relativeOrAbsolute(base: File): String = internal fun Iterable.pathsAsStringRelativeTo(base: File): String = map { it.relativeOrAbsolute(base) }.sorted().joinToString() -internal fun File.relativeToRoot(project: Project): String = - relativeOrAbsolute(project.rootProject.rootDir) - internal fun Iterable.toPathsArray(): Array = map { it.normalize().absolutePath }.toTypedArray() @@ -89,22 +86,13 @@ internal fun File.absolutePathWithoutExtension(): String = internal fun File.listFilesOrEmpty() = (if (exists()) listFiles() else null).orEmpty() -internal inline fun withTemporaryDirectory(prefix: String, action: (directory: File) -> T): T { - val directory = Files.createTempDirectory(prefix).toFile() - return try { - action(directory) - } finally { - directory.deleteRecursively() - } -} - fun contentEquals(file1: File, file2: File): Boolean { file1.useLines { seq1 -> file2.useLines { seq2 -> val iterator1 = seq1.iterator() val iterator2 = seq2.iterator() - while(iterator1.hasNext() == iterator2.hasNext()) { + while (iterator1.hasNext() == iterator2.hasNext()) { if (!iterator1.hasNext()) return true @@ -130,7 +118,6 @@ internal fun Provider.getFile(): File = get().asFile @JvmName("getDirectoryAsFile") // avoids jvm signature clash internal fun Provider.getFile(): File = get().asFile - /** * Checks if the file exists, taking into account compatibility with different versions of Gradle. * It should be used instead of [File.exists] in checking UPD inputs. See KT-54232 for more info. @@ -144,4 +131,43 @@ internal fun File.existsCompat(): Boolean = true } else { exists() - } \ No newline at end of file + } + +/** + * Looks up the property in the following sources with decreasing priority: + * 1. Current project extra properties + * 2. Project Gradle properties (-P, gradle.properties, etc...) + * 3. `local.properties` file located in the rootDir + * + * If multiple properties are loaded from a same caller, it is better to cache `localProperties` into local variable. + */ +internal fun Project.loadProperty( + propName: String, + localPropertiesProvider: Provider> = localProperties +): Provider = providers + .provider { + extraProperties.getOrNull(propName) as? String + } + .orElse( + project.providers + .gradleProperty(propName) + .usedAtConfigurationTime(configurationTimePropertiesAccessor) + ) + .orElse( + @Suppress("TYPE_MISMATCH") + localPropertiesProvider.map { it[propName] } + ) + +/** + * Loads 'local.properties' file content as [Properties]. + * + * If it does not exist, returned [Provider] will be empty. + */ +internal val Project.localProperties: Provider> + get() = providers + .of(CustomPropertiesFileValueSource::class.java) { + it.parameters.propertiesFile.set( + project.rootDir.resolve("local.properties") + ) + } + .usedAtConfigurationTime(configurationTimePropertiesAccessor) diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/regressionTests/KT60388PlainJvmDependingOnJvmWithJavaTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/regressionTests/KT60388PlainJvmDependingOnJvmWithJavaTest.kt index 2302938f8fa..1d2e33266e5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/regressionTests/KT60388PlainJvmDependingOnJvmWithJavaTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/regressionTests/KT60388PlainJvmDependingOnJvmWithJavaTest.kt @@ -20,14 +20,20 @@ import kotlin.test.Test import kotlin.test.fail class KT60388PlainJvmDependingOnJvmWithJavaTest { - private val rootProject = buildProject { - allprojects { project -> project.enableDefaultStdlibDependency(false) } - } + private val rootProject = buildProject() @Test fun `test - plain jvm - depends on - jvm withJava`() { - val producer = buildProjectWithMPP(projectBuilder = { withName("producer").withParent(rootProject) }) - val consumer = buildProjectWithJvm(projectBuilder = { withName("consumer").withParent(rootProject) }) + val producer = buildProjectWithMPP( + projectBuilder = { withName("producer").withParent(rootProject) }, + preApplyCode = { + enableDefaultStdlibDependency(false) + } + ) + val consumer = buildProjectWithJvm( + projectBuilder = { withName("consumer").withParent(rootProject) }, + preApplyCode = { enableDefaultStdlibDependency(false) } + ) producer.multiplatformExtension.apply { jvm().withJava() @@ -44,8 +50,14 @@ class KT60388PlainJvmDependingOnJvmWithJavaTest { @Test fun `test - plain jvm - depends on - jvm withJava and java plugin`() { - val producer = buildProjectWithMPP(projectBuilder = { withName("producer").withParent(rootProject) }) - val consumer = buildProjectWithJvm(projectBuilder = { withName("consumer").withParent(rootProject) }) + val producer = buildProjectWithMPP( + projectBuilder = { withName("producer").withParent(rootProject) }, + preApplyCode = { enableDefaultStdlibDependency(false) } + ) + val consumer = buildProjectWithJvm( + projectBuilder = { withName("consumer").withParent(rootProject) }, + preApplyCode = { enableDefaultStdlibDependency(false) } + ) producer.multiplatformExtension.apply { producer.plugins.apply("java") diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/buildProject.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/buildProject.kt index 730c5716a3b..ce4399db4d3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/buildProject.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/buildProject.kt @@ -37,7 +37,12 @@ fun buildProject( .apply(configureProject) .let { it as ProjectInternal } -fun buildProjectWithMPP(projectBuilder: ProjectBuilder.() -> Unit = { }, code: Project.() -> Unit = {}) = buildProject(projectBuilder) { +fun buildProjectWithMPP( + projectBuilder: ProjectBuilder.() -> Unit = { }, + preApplyCode: Project.() -> Unit = {}, + code: Project.() -> Unit = {} +) = buildProject(projectBuilder) { + preApplyCode() project.applyMultiplatformPlugin() disableLegacyWarning(project) code() @@ -48,7 +53,12 @@ fun buildProjectWithKPM(projectBuilder: ProjectBuilder.() -> Unit = { }, code: P code() } -fun buildProjectWithJvm(projectBuilder: ProjectBuilder.() -> Unit = {}, code: Project.() -> Unit = {}) = buildProject(projectBuilder) { +fun buildProjectWithJvm( + projectBuilder: ProjectBuilder.() -> Unit = {}, + preApplyCode: Project.() -> Unit = {}, + code: Project.() -> Unit = {} +) = buildProject(projectBuilder) { + preApplyCode() project.applyKotlinJvmPlugin() code() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/gradle70/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/gradle70/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt index 4180d9d2f38..52c74016128 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/gradle70/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/gradle70/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -131,8 +131,8 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) project.applyPlugin() + warnAboutKotlin12xMppDeprecation(project) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/gradle71/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/gradle71/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt index 382186a5a90..c4a5901b633 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/gradle71/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/gradle71/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -136,8 +136,8 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) project.applyPlugin() + warnAboutKotlin12xMppDeprecation(project) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/gradle74/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/gradle74/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt index 5ced077079d..9b45ccd1a6a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/gradle74/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/gradle74/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -134,8 +134,8 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) project.applyPlugin() + warnAboutKotlin12xMppDeprecation(project) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/gradle75/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/gradle75/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt index 7e741506d8f..0cc6c512418 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/gradle75/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/gradle75/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -133,8 +133,8 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) project.applyPlugin() + warnAboutKotlin12xMppDeprecation(project) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/gradle76/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/gradle76/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt index a8c7d2b394b..003155429d9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/gradle76/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/gradle76/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -133,8 +133,8 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) project.applyPlugin() + warnAboutKotlin12xMppDeprecation(project) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/gradle80/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/gradle80/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt index dbfd019ad26..bc2e7722e15 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/gradle80/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/gradle80/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -133,8 +133,8 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) project.applyPlugin() + warnAboutKotlin12xMppDeprecation(project) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/gradle81/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/gradle81/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt index e736fb33fd6..48c3dc26874 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/gradle81/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/gradle81/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -133,8 +133,8 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) project.applyPlugin() + warnAboutKotlin12xMppDeprecation(project) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt index da6b5a55536..f1cf49747eb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/PluginWrappers.kt @@ -135,8 +135,8 @@ open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase( open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") { override fun apply(project: Project) { - warnAboutKotlin12xMppDeprecation(project) project.applyPlugin() + warnAboutKotlin12xMppDeprecation(project) } }