[IC] Relocatable IC caches for projects with custom buildDir
IC caches often contain file paths. To make them relocatable, we need
to convert these file paths into relative paths, relative to a base
directory.
- If the file paths are source files, we can use the root project
directory as base.
- If the file paths are class files, we should use the classes
directory as base (before this commit, we used the root project
directory in both cases, that's why we hit KT-58547).
The key changes in this commit include:
- RelocatableFileToPathConverter: converts paths to relative paths
- IncrementalCompilationContext: contains 2 different path converters,
one for source files and one for class files
- SourceToOutputFilesMap: maps source files to class files using the
above path converters
- IncrementalCompilerRunner: creates the path converters based on file
locations
Test: RelocatableFileToPathConverterTest unit test
SourceToOutputFilesMapTest unit test
BuildCacheRelocationIT.testCustomBuildDirectory integration test
^KT-58547 Fixed
This commit is contained in:
@@ -7,14 +7,13 @@ package org.jetbrains.kotlin.incremental
|
||||
|
||||
import org.jetbrains.kotlin.build.report.DoNothingICReporter
|
||||
import org.jetbrains.kotlin.build.report.ICReporter
|
||||
import org.jetbrains.kotlin.incremental.storage.FileToAbsolutePathConverter
|
||||
import org.jetbrains.kotlin.incremental.storage.FileToPathConverter
|
||||
import org.jetbrains.kotlin.incremental.storage.IncrementalFileToPathConverter
|
||||
import java.io.File
|
||||
|
||||
private fun createDefaultPathConverter(rootProjectDir: File?) = IncrementalFileToPathConverter(rootProjectDir)
|
||||
|
||||
class IncrementalCompilationContext(
|
||||
val pathConverter: FileToPathConverter,
|
||||
// The root directories of source files and class files are different, so we may need different `FileToPathConverter`s
|
||||
val pathConverterForSourceFiles: FileToPathConverter = FileToAbsolutePathConverter,
|
||||
val pathConverterForOutputFiles: FileToPathConverter = FileToAbsolutePathConverter,
|
||||
val storeFullFqNamesInLookupCache: Boolean = false,
|
||||
val transaction: CompilationTransaction = NonRecoverableCompilationTransaction(),
|
||||
val reporter: ICReporter = DoNothingICReporter,
|
||||
@@ -29,19 +28,7 @@ class IncrementalCompilationContext(
|
||||
*/
|
||||
val keepIncrementalCompilationCachesInMemory: Boolean = false,
|
||||
) {
|
||||
constructor(
|
||||
rootProjectDir: File?,
|
||||
storeFullFqNamesInLookupCache: Boolean = false,
|
||||
transaction: CompilationTransaction = NonRecoverableCompilationTransaction(),
|
||||
reporter: ICReporter = DoNothingICReporter,
|
||||
trackChangesInLookupCache: Boolean = false,
|
||||
keepIncrementalCompilationCachesInMemory: Boolean = false,
|
||||
) : this(
|
||||
createDefaultPathConverter(rootProjectDir),
|
||||
storeFullFqNamesInLookupCache,
|
||||
transaction,
|
||||
reporter,
|
||||
trackChangesInLookupCache,
|
||||
keepIncrementalCompilationCachesInMemory
|
||||
)
|
||||
// FIXME: Remove `pathConverter` and require its users to decide whether to use `pathConverterForSourceFiles` or
|
||||
// `pathConverterForClassFiles`
|
||||
val pathConverter = pathConverterForSourceFiles
|
||||
}
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.incremental.storage
|
||||
|
||||
import java.io.File
|
||||
|
||||
/** Converts a [File] to a path of type [String] to store in IC caches, and vice versa. */
|
||||
interface FileToPathConverter {
|
||||
fun toPath(file: File): String
|
||||
fun toFile(path: String): File
|
||||
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.incremental.storage
|
||||
|
||||
import java.io.File
|
||||
|
||||
open class IncrementalFileToPathConverter(val rootProjectDir: File?) : FileToPathConverter {
|
||||
//project root dir
|
||||
private val projectDirPath = rootProjectDir?.normalize()?.absolutePath
|
||||
|
||||
override fun toPath(file: File): String {
|
||||
val path = file.normalize().absolutePath
|
||||
return when {
|
||||
projectDirPath == null || !path.startsWith(projectDirPath) -> path
|
||||
else -> PROJECT_DIR_PLACEHOLDER + path.substring(projectDirPath.length)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toFile(path: String): File =
|
||||
when {
|
||||
rootProjectDir != null && path.startsWith(PROJECT_DIR_PLACEHOLDER) -> rootProjectDir.resolve(path.substring(PATH_PREFIX.length))
|
||||
else -> File(path)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val PROJECT_DIR_PLACEHOLDER = "${'$'}PROJECT_DIR$"
|
||||
//use only for prefix length because it OS dependent
|
||||
private const val PATH_PREFIX = "$PROJECT_DIR_PLACEHOLDER/"
|
||||
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental.storage
|
||||
|
||||
interface LazyStorage<K, V> {
|
||||
import java.io.Closeable
|
||||
|
||||
interface LazyStorage<K, V> : Closeable {
|
||||
val keys: Collection<K>
|
||||
operator fun contains(key: K): Boolean
|
||||
operator fun get(key: K): V?
|
||||
@@ -24,7 +26,7 @@ interface LazyStorage<K, V> {
|
||||
fun remove(key: K)
|
||||
fun clean()
|
||||
fun flush(memoryCachesOnly: Boolean)
|
||||
fun close()
|
||||
override fun close()
|
||||
}
|
||||
|
||||
interface AppendableLazyStorage<K, V> : LazyStorage<K, V> {
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.incremental.storage
|
||||
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* [FileToPathConverter] which converts a [File] to a Unix-style relative path, which is relative to a base directory ([baseDir]), and vice
|
||||
* versa.
|
||||
*
|
||||
* This is to support build cache relocatability
|
||||
* (https://docs.gradle.org/current/userguide/build_cache_concepts.html#relocatability).
|
||||
*/
|
||||
class RelocatableFileToPathConverter(private val baseDir: File) : FileToPathConverter {
|
||||
|
||||
private val unixStyleBaseDirPathPrefix = "${baseDir.invariantSeparatorsPath}/"
|
||||
|
||||
override fun toPath(file: File): String {
|
||||
check(file.invariantSeparatorsPath.startsWith(unixStyleBaseDirPathPrefix)) {
|
||||
"The given file '${file.path}' is located outside the base directory '${baseDir.path}'"
|
||||
}
|
||||
return file.relativeTo(baseDir).invariantSeparatorsPath
|
||||
}
|
||||
|
||||
override fun toFile(path: String): File {
|
||||
// Note: The given path is Unix-style but baseDir could be Windows-style; call normalize() so that the style of the returned file's
|
||||
// path is consistent with baseDir.
|
||||
return baseDir.resolve(path).normalize()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* File locations to support build cache relocatability (see [RelocatableFileToPathConverter]).
|
||||
*
|
||||
* These are the root directories of
|
||||
* - Source files
|
||||
* - Output files, which include .class files and possibly additional output files such as `.java` stub files for KaptGenerateStubs tasks.
|
||||
*
|
||||
* Ideally, they should be the most specific root directories (e.g., `/path/to/MyApplication/app/src/main/kotlin` for source files and
|
||||
* `/path/to/MyApplication/app/build/tmp/kotlin-classes/debug` for output .class files). However, for simplicity we are using the root
|
||||
* project directory ([rootProjectDir]) for source files and ([buildDir]) for output files.
|
||||
*/
|
||||
class FileLocations(
|
||||
val rootProjectDir: File,
|
||||
val buildDir: File,
|
||||
) {
|
||||
|
||||
fun getRelocatablePathConverterForSourceFiles() = RelocatableFileToPathConverter(rootProjectDir)
|
||||
|
||||
fun getRelocatablePathConverterForOutputFiles() = RelocatableFileToPathConverter(buildDir)
|
||||
}
|
||||
Reference in New Issue
Block a user