From 2fce6a4af9044de7975392474a6eb3b8c3985bd5 Mon Sep 17 00:00:00 2001 From: Ivan Gavrilovic Date: Mon, 1 Feb 2021 15:40:29 +0000 Subject: [PATCH] Locate build history when file is outside of root project dir Support use-cases when the build dir is outside of root project dir. Many projects set up output dir as /../out//build to be able to clean build dir more easily. This commit adds support to build history file detection and it tries to find build history files for artifacts that are: - under root project dir (a default structure) - under root project's build dir parent (to support typical custom setup) Fixes https://youtrack.jetbrains.com/issue/KT-40875 Test: BaseIncrementalCompilationMultiProjectIT --- .../incremental/IncrementalModuleInfo.kt | 3 +- .../multiproject/ModulesApiHistory.kt | 20 +++++++++---- ...ncrementaMultiModulelCompilerRunnerTest.kt | 2 +- .../ModulesApiHistoryAndroidTest.kt | 1 + .../IncrementalCompilationMultiProjectIT.kt | 28 +++++++++++++++++++ .../GradleKotlinCompilerRunner.kt | 1 + 6 files changed, 48 insertions(+), 7 deletions(-) diff --git a/build-common/src/org/jetbrains/kotlin/incremental/IncrementalModuleInfo.kt b/build-common/src/org/jetbrains/kotlin/incremental/IncrementalModuleInfo.kt index a49ec4eb04a..30ee30d35e1 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/IncrementalModuleInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/IncrementalModuleInfo.kt @@ -21,6 +21,7 @@ data class IncrementalModuleEntry( class IncrementalModuleInfo( val projectRoot: File, + val rootProjectBuildDir: File, val dirToModule: Map, val nameToModules: Map>, val jarToClassListFile: Map, @@ -28,6 +29,6 @@ class IncrementalModuleInfo( val jarToModule: Map ) : Serializable { companion object { - private const val serialVersionUID = 0L + private const val serialVersionUID = 1L } } \ No newline at end of file diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt index 8951733c126..ce7ac983cad 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.incremental.multiproject -import org.jetbrains.kotlin.incremental.IncrementalModuleEntry import org.jetbrains.kotlin.incremental.IncrementalModuleInfo import org.jetbrains.kotlin.incremental.util.Either import java.io.File @@ -23,7 +22,14 @@ object EmptyModulesApiHistory : ModulesApiHistory { } abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory { - protected val projectRootPath: Path = Paths.get(modulesInfo.projectRoot.absolutePath) + // All project build dirs should have this dir as their parent. For a default project setup, this will + // be the same as root project path. Some projects map output outside of the root project dir, typically + // with //build, and in that case, this path will be . + // This is using set in order to de-dup paths, and avoid duplicate checks when possible. + protected val possibleParentsToBuildDirs: Set = setOf( + Paths.get(modulesInfo.rootProjectBuildDir.parentFile.absolutePath), + Paths.get(modulesInfo.projectRoot.absolutePath) + ) private val dirToHistoryFileCache = HashMap>() override fun historyFilesForChangedFiles(changedFiles: Set): Either> { @@ -76,7 +82,7 @@ abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModul when { module != null -> setOf(module.buildHistoryFile) - parent != null && projectRootPath.isParentOf(parent) -> { + parent != null && isInProjectBuildDir(parent) -> { val parentHistory = getBuildHistoryForDir(parent) when (parentHistory) { is Either.Success> -> parentHistory.value @@ -90,6 +96,10 @@ abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModul return Either.Success(history) } + protected fun isInProjectBuildDir(file: File): Boolean { + return possibleParentsToBuildDirs.any { it.isParentOf(file) } + } + protected abstract fun getBuildHistoryFilesForJar(jar: File): Either> } @@ -145,14 +155,14 @@ class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiH override fun getBuildHistoryFilesForJar(jar: File): Either> { // Module detection is expensive, so we don't don it for jars outside of project dir - if (!projectRootPath.isParentOf(jar)) return Either.Error("Non-project jar is modified $jar") + if (!isInProjectBuildDir(jar)) return Either.Error("Non-project jar is modified $jar") val jarPath = Paths.get(jar.absolutePath) return getHistoryForModuleNames(jarPath, getPossibleModuleNamesFromJar(jarPath)) } override fun getBuildHistoryForDir(file: File): Either> { - if (!projectRootPath.isParentOf(file)) return Either.Error("Non-project file while looking for history $file") + if (!isInProjectBuildDir(file)) return Either.Error("Non-project file while looking for history $file") // check both meta-inf and META-INF directories val moduleNames = diff --git a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementaMultiModulelCompilerRunnerTest.kt b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementaMultiModulelCompilerRunnerTest.kt index c46bee28e71..2c25c1f3612 100644 --- a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementaMultiModulelCompilerRunnerTest.kt +++ b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementaMultiModulelCompilerRunnerTest.kt @@ -32,7 +32,7 @@ abstract class AbstractIncrementalMultiModuleCompilerRunnerTest() protected val incrementalModuleInfo: IncrementalModuleInfo by lazy { - IncrementalModuleInfo(workingDir, dirToModule, nameToModules, jarToClassListFile, jarToModule) + IncrementalModuleInfo(workingDir, workingDir, dirToModule, nameToModules, jarToClassListFile, jarToModule) } protected abstract val modulesApiHistory: ApiHistory diff --git a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistoryAndroidTest.kt b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistoryAndroidTest.kt index bb3ec09aacc..c783c7de358 100644 --- a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistoryAndroidTest.kt +++ b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistoryAndroidTest.kt @@ -56,6 +56,7 @@ class ModulesApiHistoryAndroidTest { val info = IncrementalModuleInfo( projectRoot = projectRoot, + rootProjectBuildDir = projectRoot.resolve("build"), dirToModule = mapOf(appKotlinDestination to appEntry, libKotlinDestination to libEntry), nameToModules = mapOf("app" to setOf(appEntry), "lib" to setOf(libEntry)), jarToClassListFile = mapOf(), diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt index e14da624cf5..65be9b10dac 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/IncrementalCompilationMultiProjectIT.kt @@ -347,5 +347,33 @@ open class A { assertCompiledKotlinSources(project.relativize(aaKt)) } } + + /** Regression test for KT-40875. */ + @Test + fun testMoveFunctionFromLibWithRemappedBuildDirs() { + val project = defaultProject() + project.setupWorkingDir() + project.projectDir.resolve("build.gradle").appendText(""" + + allprojects { + it.buildDir = new File(rootDir, "../out" + it.path.replace(":", "/") + "/build") + } + """.trimIndent()) + project.build("build") { + assertSuccessful() + } + + val barUseABKt = project.projectDir.getFileByName("barUseAB.kt") + val barInApp = File(project.projectDir, "app/src/main/kotlin/bar").apply { mkdirs() } + barUseABKt.copyTo(File(barInApp, barUseABKt.name)) + barUseABKt.delete() + + project.build("build") { + assertSuccessful() + val affectedSources = project.projectDir.getFilesByNames("fooCallUseAB.kt", "barUseAB.kt") + val relativePaths = project.relativize(affectedSources) + assertCompiledKotlinSources(relativePaths) + } + } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt index 5bbb9eacf11..fb4fc14b5a2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt @@ -257,6 +257,7 @@ internal open class GradleCompilerRunner(protected val taskProvider: GradleCompi return IncrementalModuleInfo( projectRoot = gradle.rootProject.projectDir, + rootProjectBuildDir = gradle.rootProject.buildDir, dirToModule = dirToModule, nameToModules = nameToModules, jarToClassListFile = jarToClassListFile,