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 <root_project>/../out/<project_name>/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
This commit is contained in:
committed by
nataliya.valtman
parent
5de34b052f
commit
2fce6a4af9
@@ -21,6 +21,7 @@ data class IncrementalModuleEntry(
|
||||
|
||||
class IncrementalModuleInfo(
|
||||
val projectRoot: File,
|
||||
val rootProjectBuildDir: File,
|
||||
val dirToModule: Map<File, IncrementalModuleEntry>,
|
||||
val nameToModules: Map<String, Set<IncrementalModuleEntry>>,
|
||||
val jarToClassListFile: Map<File, File>,
|
||||
@@ -28,6 +29,6 @@ class IncrementalModuleInfo(
|
||||
val jarToModule: Map<File, IncrementalModuleEntry>
|
||||
) : Serializable {
|
||||
companion object {
|
||||
private const val serialVersionUID = 0L
|
||||
private const val serialVersionUID = 1L
|
||||
}
|
||||
}
|
||||
+15
-5
@@ -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 <some_dir>/<project_path>/build, and in that case, this path will be <some_dir>.
|
||||
// This is using set in order to de-dup paths, and avoid duplicate checks when possible.
|
||||
protected val possibleParentsToBuildDirs: Set<Path> = setOf(
|
||||
Paths.get(modulesInfo.rootProjectBuildDir.parentFile.absolutePath),
|
||||
Paths.get(modulesInfo.projectRoot.absolutePath)
|
||||
)
|
||||
private val dirToHistoryFileCache = HashMap<File, Set<File>>()
|
||||
|
||||
override fun historyFilesForChangedFiles(changedFiles: Set<File>): Either<Set<File>> {
|
||||
@@ -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<Set<File>> -> 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<Set<File>>
|
||||
}
|
||||
|
||||
@@ -145,14 +155,14 @@ class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiH
|
||||
|
||||
override fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
||||
// 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<Set<File>> {
|
||||
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 =
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ abstract class AbstractIncrementalMultiModuleCompilerRunnerTest<Args : CommonCom
|
||||
private val jarToModule = mutableMapOf<File, IncrementalModuleEntry>()
|
||||
|
||||
protected val incrementalModuleInfo: IncrementalModuleInfo by lazy {
|
||||
IncrementalModuleInfo(workingDir, dirToModule, nameToModules, jarToClassListFile, jarToModule)
|
||||
IncrementalModuleInfo(workingDir, workingDir, dirToModule, nameToModules, jarToClassListFile, jarToModule)
|
||||
}
|
||||
|
||||
protected abstract val modulesApiHistory: ApiHistory
|
||||
|
||||
+1
@@ -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(),
|
||||
|
||||
+28
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user