Implement inter-project JS IC with Gradle
#KT-25025 fixed
This commit is contained in:
+3
-1
@@ -23,7 +23,9 @@ class IncrementalModuleInfo(
|
|||||||
val projectRoot: File,
|
val projectRoot: File,
|
||||||
val dirToModule: Map<File, IncrementalModuleEntry>,
|
val dirToModule: Map<File, IncrementalModuleEntry>,
|
||||||
val nameToModules: Map<String, Set<IncrementalModuleEntry>>,
|
val nameToModules: Map<String, Set<IncrementalModuleEntry>>,
|
||||||
val jarToClassListFile: Map<File, File>
|
val jarToClassListFile: Map<File, File>,
|
||||||
|
// only for js
|
||||||
|
val jarToModule: Map<File, IncrementalModuleEntry>
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
companion object {
|
companion object {
|
||||||
private const val serialVersionUID = 0L
|
private const val serialVersionUID = 0L
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
|
|||||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
||||||
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
|
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
|
||||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryAndroid
|
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryAndroid
|
||||||
|
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJs
|
||||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
|
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
|
||||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||||
import org.jetbrains.kotlin.modules.Module
|
import org.jetbrains.kotlin.modules.Module
|
||||||
@@ -475,8 +476,14 @@ class CompileServiceImpl(
|
|||||||
incrementalCompilationOptions.customCacheVersionFileName,
|
incrementalCompilationOptions.customCacheVersionFileName,
|
||||||
workingDir,
|
workingDir,
|
||||||
enabled = true)
|
enabled = true)
|
||||||
|
val modulesApiHistory = ModulesApiHistoryJs(incrementalCompilationOptions.modulesInfo)
|
||||||
val compiler = IncrementalJsCompilerRunner(workingDir, versions, reporter)
|
val compiler = IncrementalJsCompilerRunner(
|
||||||
|
workingDir = workingDir,
|
||||||
|
cacheVersions = versions,
|
||||||
|
reporter = reporter,
|
||||||
|
buildHistoryFile = incrementalCompilationOptions.multiModuleICSettings.buildHistoryFile,
|
||||||
|
modulesApiHistory = modulesApiHistory
|
||||||
|
)
|
||||||
return compiler.compile(allKotlinFiles, args, compilerMessageCollector, changedFiles)
|
return compiler.compile(allKotlinFiles, args, compilerMessageCollector, changedFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-1
@@ -41,6 +41,7 @@ abstract class IncrementalCompilerRunner<
|
|||||||
cacheDirName: String,
|
cacheDirName: String,
|
||||||
protected val cacheVersions: List<CacheVersion>,
|
protected val cacheVersions: List<CacheVersion>,
|
||||||
protected val reporter: ICReporter,
|
protected val reporter: ICReporter,
|
||||||
|
private val buildHistoryFile: File,
|
||||||
private val localStateDirs: Collection<File> = emptyList()
|
private val localStateDirs: Collection<File> = emptyList()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -299,11 +300,20 @@ abstract class IncrementalCompilerRunner<
|
|||||||
|
|
||||||
open fun runWithNoDirtyKotlinSources(caches: CacheManager): Boolean = false
|
open fun runWithNoDirtyKotlinSources(caches: CacheManager): Boolean = false
|
||||||
|
|
||||||
protected open fun processChangesAfterBuild(
|
private fun processChangesAfterBuild(
|
||||||
compilationMode: CompilationMode,
|
compilationMode: CompilationMode,
|
||||||
currentBuildInfo: BuildInfo,
|
currentBuildInfo: BuildInfo,
|
||||||
dirtyData: DirtyData
|
dirtyData: DirtyData
|
||||||
) {
|
) {
|
||||||
|
val prevDiffs = BuildDiffsStorage.readFromFile(buildHistoryFile, reporter)?.buildDiffs ?: emptyList()
|
||||||
|
val newDiff = if (compilationMode is CompilationMode.Incremental) {
|
||||||
|
BuildDifference(currentBuildInfo.startTS, true, dirtyData)
|
||||||
|
} else {
|
||||||
|
val emptyDirtyData = DirtyData()
|
||||||
|
BuildDifference(currentBuildInfo.startTS, false, emptyDirtyData)
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildDiffsStorage.writeToFile(buildHistoryFile, BuildDiffsStorage(prevDiffs + newDiff), reporter)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
+30
-15
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.incremental
|
package org.jetbrains.kotlin.incremental
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
|
||||||
import org.jetbrains.kotlin.build.GeneratedFile
|
import org.jetbrains.kotlin.build.GeneratedFile
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||||
@@ -27,6 +26,8 @@ import org.jetbrains.kotlin.config.Services
|
|||||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||||
import org.jetbrains.kotlin.incremental.js.*
|
import org.jetbrains.kotlin.incremental.js.*
|
||||||
|
import org.jetbrains.kotlin.incremental.multiproject.EmptyModulesApiHistory
|
||||||
|
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
fun makeJsIncrementally(
|
fun makeJsIncrementally(
|
||||||
@@ -40,9 +41,13 @@ fun makeJsIncrementally(
|
|||||||
val versions = commonCacheVersions(cachesDir, isIncremental) + standaloneCacheVersion(cachesDir, isIncremental)
|
val versions = commonCacheVersions(cachesDir, isIncremental) + standaloneCacheVersion(cachesDir, isIncremental)
|
||||||
val allKotlinFiles = sourceRoots.asSequence().flatMap { it.walk() }
|
val allKotlinFiles = sourceRoots.asSequence().flatMap { it.walk() }
|
||||||
.filter { it.isFile && it.extension.equals("kt", ignoreCase = true) }.toList()
|
.filter { it.isFile && it.extension.equals("kt", ignoreCase = true) }.toList()
|
||||||
|
val buildHistoryFile = File(cachesDir, "build-history.bin")
|
||||||
|
|
||||||
withJsIC {
|
withJsIC {
|
||||||
val compiler = IncrementalJsCompilerRunner(cachesDir, versions, reporter)
|
val compiler = IncrementalJsCompilerRunner(
|
||||||
|
cachesDir, versions, reporter,
|
||||||
|
buildHistoryFile = buildHistoryFile,
|
||||||
|
modulesApiHistory = EmptyModulesApiHistory)
|
||||||
compiler.compile(allKotlinFiles, args, messageCollector, providedChangedFiles = null)
|
compiler.compile(allKotlinFiles, args, messageCollector, providedChangedFiles = null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,12 +66,15 @@ inline fun <R> withJsIC(fn: () -> R): R {
|
|||||||
class IncrementalJsCompilerRunner(
|
class IncrementalJsCompilerRunner(
|
||||||
workingDir: File,
|
workingDir: File,
|
||||||
cacheVersions: List<CacheVersion>,
|
cacheVersions: List<CacheVersion>,
|
||||||
reporter: ICReporter
|
reporter: ICReporter,
|
||||||
|
buildHistoryFile: File,
|
||||||
|
private val modulesApiHistory: ModulesApiHistory
|
||||||
) : IncrementalCompilerRunner<K2JSCompilerArguments, IncrementalJsCachesManager>(
|
) : IncrementalCompilerRunner<K2JSCompilerArguments, IncrementalJsCachesManager>(
|
||||||
workingDir,
|
workingDir,
|
||||||
"caches-js",
|
"caches-js",
|
||||||
cacheVersions,
|
cacheVersions,
|
||||||
reporter
|
reporter,
|
||||||
|
buildHistoryFile = buildHistoryFile
|
||||||
) {
|
) {
|
||||||
override fun isICEnabled(): Boolean =
|
override fun isICEnabled(): Boolean =
|
||||||
IncrementalCompilation.isEnabledForJs()
|
IncrementalCompilation.isEnabledForJs()
|
||||||
@@ -78,21 +86,28 @@ class IncrementalJsCompilerRunner(
|
|||||||
File(args.outputFile).parentFile
|
File(args.outputFile).parentFile
|
||||||
|
|
||||||
override fun calculateSourcesToCompile(caches: IncrementalJsCachesManager, changedFiles: ChangedFiles.Known, args: K2JSCompilerArguments): CompilationMode {
|
override fun calculateSourcesToCompile(caches: IncrementalJsCachesManager, changedFiles: ChangedFiles.Known, args: K2JSCompilerArguments): CompilationMode {
|
||||||
if (BuildInfo.read(lastBuildInfoFile) == null) return CompilationMode.Rebuild { "No information on previous build" }
|
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
|
||||||
|
?: return CompilationMode.Rebuild { "No information on previous build" }
|
||||||
val libs = (args.libraries ?: "").split(File.pathSeparator).mapTo(HashSet()) { File(it) }
|
|
||||||
val libsDirs = libs.filter { it.isDirectory }
|
|
||||||
|
|
||||||
val changedLib = changedFiles.allAsSequence.find { it in libs }
|
|
||||||
?: changedFiles.allAsSequence.find { changedFile ->
|
|
||||||
libsDirs.any { libDir -> FileUtil.isAncestor(libDir, changedFile, true) }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changedLib != null) return CompilationMode.Rebuild { "Library has been changed: $changedLib" }
|
|
||||||
|
|
||||||
val dirtyFiles = DirtyFilesContainer(caches, reporter)
|
val dirtyFiles = DirtyFilesContainer(caches, reporter)
|
||||||
initDirtyFiles(dirtyFiles, changedFiles)
|
initDirtyFiles(dirtyFiles, changedFiles)
|
||||||
|
|
||||||
|
val libs = (args.libraries ?: "").split(File.pathSeparator).map { File(it) }
|
||||||
|
val classpathChanges = getClasspathChanges(libs, changedFiles, lastBuildInfo, modulesApiHistory, reporter)
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE") // for sealed when
|
||||||
|
val unused = when (classpathChanges) {
|
||||||
|
is ChangesEither.Unknown -> return CompilationMode.Rebuild {
|
||||||
|
// todo: we can recompile all files incrementally (not cleaning caches), so rebuild won't propagate
|
||||||
|
"Could not get classpath's changes${classpathChanges.reason?.let { ": $it" }}"
|
||||||
|
}
|
||||||
|
is ChangesEither.Known -> {
|
||||||
|
dirtyFiles.addByDirtySymbols(classpathChanges.lookupSymbols)
|
||||||
|
dirtyFiles.addByDirtyClasses(classpathChanges.fqNames)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles)
|
val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles)
|
||||||
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
|
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
|
||||||
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
|
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
|
||||||
|
|||||||
+3
-72
@@ -104,7 +104,7 @@ class IncrementalJvmCompilerRunner(
|
|||||||
cacheVersions: List<CacheVersion>,
|
cacheVersions: List<CacheVersion>,
|
||||||
reporter: ICReporter,
|
reporter: ICReporter,
|
||||||
private val usePreciseJavaTracking: Boolean,
|
private val usePreciseJavaTracking: Boolean,
|
||||||
private val buildHistoryFile: File,
|
buildHistoryFile: File,
|
||||||
localStateDirs: Collection<File>,
|
localStateDirs: Collection<File>,
|
||||||
private val modulesApiHistory: ModulesApiHistory
|
private val modulesApiHistory: ModulesApiHistory
|
||||||
) : IncrementalCompilerRunner<K2JVMCompilerArguments, IncrementalJvmCachesManager>(
|
) : IncrementalCompilerRunner<K2JVMCompilerArguments, IncrementalJvmCachesManager>(
|
||||||
@@ -112,7 +112,8 @@ class IncrementalJvmCompilerRunner(
|
|||||||
"caches-jvm",
|
"caches-jvm",
|
||||||
cacheVersions,
|
cacheVersions,
|
||||||
reporter,
|
reporter,
|
||||||
localStateDirs = localStateDirs
|
localStateDirs = localStateDirs,
|
||||||
|
buildHistoryFile = buildHistoryFile
|
||||||
) {
|
) {
|
||||||
override fun isICEnabled(): Boolean =
|
override fun isICEnabled(): Boolean =
|
||||||
IncrementalCompilation.isEnabledForJvm()
|
IncrementalCompilation.isEnabledForJvm()
|
||||||
@@ -310,22 +311,6 @@ class IncrementalJvmCompilerRunner(
|
|||||||
override fun additionalDirtyLookupSymbols(): Iterable<LookupSymbol> =
|
override fun additionalDirtyLookupSymbols(): Iterable<LookupSymbol> =
|
||||||
javaFilesProcessor?.allChangedSymbols ?: emptyList()
|
javaFilesProcessor?.allChangedSymbols ?: emptyList()
|
||||||
|
|
||||||
override fun processChangesAfterBuild(
|
|
||||||
compilationMode: CompilationMode,
|
|
||||||
currentBuildInfo: BuildInfo,
|
|
||||||
dirtyData: DirtyData
|
|
||||||
) {
|
|
||||||
val prevDiffs = BuildDiffsStorage.readFromFile(buildHistoryFile, reporter)?.buildDiffs ?: emptyList()
|
|
||||||
val newDiff = if (compilationMode is CompilationMode.Incremental) {
|
|
||||||
BuildDifference(currentBuildInfo.startTS, true, dirtyData)
|
|
||||||
} else {
|
|
||||||
val emptyDirtyData = DirtyData()
|
|
||||||
BuildDifference(currentBuildInfo.startTS, false, emptyDirtyData)
|
|
||||||
}
|
|
||||||
|
|
||||||
BuildDiffsStorage.writeToFile(buildHistoryFile, BuildDiffsStorage(prevDiffs + newDiff), reporter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun makeServices(
|
override fun makeServices(
|
||||||
args: K2JVMCompilerArguments,
|
args: K2JVMCompilerArguments,
|
||||||
lookupTracker: LookupTracker,
|
lookupTracker: LookupTracker,
|
||||||
@@ -387,57 +372,3 @@ var K2JVMCompilerArguments.destinationAsFile: File
|
|||||||
var K2JVMCompilerArguments.classpathAsList: List<File>
|
var K2JVMCompilerArguments.classpathAsList: List<File>
|
||||||
get() = classpath.orEmpty().split(File.pathSeparator).map(::File)
|
get() = classpath.orEmpty().split(File.pathSeparator).map(::File)
|
||||||
set(value) { classpath = value.joinToString(separator = File.pathSeparator, transform = { it.path }) }
|
set(value) { classpath = value.joinToString(separator = File.pathSeparator, transform = { it.path }) }
|
||||||
|
|
||||||
private fun getClasspathChanges(
|
|
||||||
classpath: List<File>,
|
|
||||||
changedFiles: ChangedFiles.Known,
|
|
||||||
lastBuildInfo: BuildInfo,
|
|
||||||
modulesApiHistory: ModulesApiHistory,
|
|
||||||
reporter: ICReporter?
|
|
||||||
): ChangesEither {
|
|
||||||
val classpathSet = HashSet<File>()
|
|
||||||
for (file in classpath) {
|
|
||||||
when {
|
|
||||||
file.isFile -> classpathSet.add(file)
|
|
||||||
file.isDirectory -> file.walk().filterTo(classpathSet) { it.isFile }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val modifiedClasspath = changedFiles.modified.filterTo(HashSet()) { it in classpathSet }
|
|
||||||
val removedClasspath = changedFiles.removed.filterTo(HashSet()) { it in classpathSet }
|
|
||||||
|
|
||||||
// todo: removed classes could be processed normally
|
|
||||||
if (removedClasspath.isNotEmpty()) return ChangesEither.Unknown("Some files are removed from classpath $removedClasspath")
|
|
||||||
|
|
||||||
if (modifiedClasspath.isEmpty()) return ChangesEither.Known()
|
|
||||||
|
|
||||||
val lastBuildTS = lastBuildInfo.startTS
|
|
||||||
|
|
||||||
val symbols = HashSet<LookupSymbol>()
|
|
||||||
val fqNames = HashSet<FqName>()
|
|
||||||
|
|
||||||
val historyFilesEither = modulesApiHistory.historyFilesForChangedFiles(modifiedClasspath)
|
|
||||||
val historyFiles = when (historyFilesEither) {
|
|
||||||
is Either.Success<Set<File>> -> historyFilesEither.value
|
|
||||||
is Either.Error -> return ChangesEither.Unknown(historyFilesEither.reason)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (historyFile in historyFiles) {
|
|
||||||
val allBuilds = BuildDiffsStorage.readDiffsFromFile(historyFile, reporter = reporter)
|
|
||||||
?: return ChangesEither.Unknown("Could not read diffs from $historyFile")
|
|
||||||
val (knownBuilds, newBuilds) = allBuilds.partition { it.ts <= lastBuildTS }
|
|
||||||
if (knownBuilds.isEmpty()) {
|
|
||||||
return ChangesEither.Unknown("No previously known builds for $historyFile")
|
|
||||||
}
|
|
||||||
|
|
||||||
for (buildDiff in newBuilds) {
|
|
||||||
if (!buildDiff.isIncremental) return ChangesEither.Unknown("Non-incremental build from dependency $historyFile")
|
|
||||||
|
|
||||||
val dirtyData = buildDiff.dirtyData
|
|
||||||
symbols.addAll(dirtyData.dirtyLookupSymbols)
|
|
||||||
fqNames.addAll(dirtyData.dirtyClassesFqNames)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ChangesEither.Known(symbols, fqNames)
|
|
||||||
}
|
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
|
||||||
|
import org.jetbrains.kotlin.incremental.util.Either
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal fun getClasspathChanges(
|
||||||
|
classpath: List<File>,
|
||||||
|
changedFiles: ChangedFiles.Known,
|
||||||
|
lastBuildInfo: BuildInfo,
|
||||||
|
modulesApiHistory: ModulesApiHistory,
|
||||||
|
reporter: ICReporter?
|
||||||
|
): ChangesEither {
|
||||||
|
val classpathSet = HashSet<File>()
|
||||||
|
for (file in classpath) {
|
||||||
|
when {
|
||||||
|
file.isFile -> classpathSet.add(file)
|
||||||
|
file.isDirectory -> file.walk().filterTo(classpathSet) { it.isFile }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val modifiedClasspath = changedFiles.modified.filterTo(HashSet()) { it in classpathSet }
|
||||||
|
val removedClasspath = changedFiles.removed.filterTo(HashSet()) { it in classpathSet }
|
||||||
|
|
||||||
|
// todo: removed classes could be processed normally
|
||||||
|
if (removedClasspath.isNotEmpty()) return ChangesEither.Unknown("Some files are removed from classpath $removedClasspath")
|
||||||
|
|
||||||
|
if (modifiedClasspath.isEmpty()) return ChangesEither.Known()
|
||||||
|
|
||||||
|
val lastBuildTS = lastBuildInfo.startTS
|
||||||
|
|
||||||
|
val symbols = HashSet<LookupSymbol>()
|
||||||
|
val fqNames = HashSet<FqName>()
|
||||||
|
|
||||||
|
val historyFilesEither = modulesApiHistory.historyFilesForChangedFiles(modifiedClasspath)
|
||||||
|
val historyFiles = when (historyFilesEither) {
|
||||||
|
is Either.Success<Set<File>> -> historyFilesEither.value
|
||||||
|
is Either.Error -> return ChangesEither.Unknown(historyFilesEither.reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (historyFile in historyFiles) {
|
||||||
|
val allBuilds = BuildDiffsStorage.readDiffsFromFile(historyFile, reporter = reporter)
|
||||||
|
?: return ChangesEither.Unknown("Could not read diffs from $historyFile")
|
||||||
|
val (knownBuilds, newBuilds) = allBuilds.partition { it.ts <= lastBuildTS }
|
||||||
|
if (knownBuilds.isEmpty()) {
|
||||||
|
return ChangesEither.Unknown("No previously known builds for $historyFile")
|
||||||
|
}
|
||||||
|
|
||||||
|
for (buildDiff in newBuilds) {
|
||||||
|
if (!buildDiff.isIncremental) return ChangesEither.Unknown("Non-incremental build from dependency $historyFile")
|
||||||
|
|
||||||
|
val dirtyData = buildDiff.dirtyData
|
||||||
|
symbols.addAll(dirtyData.dirtyLookupSymbols)
|
||||||
|
fqNames.addAll(dirtyData.dirtyClassesFqNames)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChangesEither.Known(symbols, fqNames)
|
||||||
|
}
|
||||||
+18
-3
@@ -22,7 +22,7 @@ object EmptyModulesApiHistory : ModulesApiHistory {
|
|||||||
Either.Error("Multi-module IC is not configured")
|
Either.Error("Multi-module IC is not configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory {
|
abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory {
|
||||||
protected val projectRootPath: Path = Paths.get(modulesInfo.projectRoot.absolutePath)
|
protected val projectRootPath: Path = Paths.get(modulesInfo.projectRoot.absolutePath)
|
||||||
private val dirToHistoryFileCache = HashMap<File, Set<File>>()
|
private val dirToHistoryFileCache = HashMap<File, Set<File>>()
|
||||||
|
|
||||||
@@ -86,7 +86,11 @@ open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo
|
|||||||
return Either.Success(history)
|
return Either.Success(history)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
protected abstract fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>>
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModulesApiHistoryJvm(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
|
||||||
|
override fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
||||||
val classListFile = modulesInfo.jarToClassListFile[jar] ?: return Either.Error("Unknown jar: $jar")
|
val classListFile = modulesInfo.jarToClassListFile[jar] ?: return Either.Error("Unknown jar: $jar")
|
||||||
if (!classListFile.isFile) return Either.Error("Class list file does not exist $classListFile")
|
if (!classListFile.isFile) return Either.Error("Class list file does not exist $classListFile")
|
||||||
|
|
||||||
@@ -109,7 +113,18 @@ open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryJvm(modulesInfo) {
|
class ModulesApiHistoryJs(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
|
||||||
|
override fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
||||||
|
val moduleEntry = modulesInfo.jarToModule[jar]
|
||||||
|
|
||||||
|
return when {
|
||||||
|
moduleEntry != null -> Either.Success(setOf(moduleEntry.buildHistoryFile))
|
||||||
|
else -> Either.Error("No module is found for jar $jar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
|
||||||
private val delegate = ModulesApiHistoryJvm(modulesInfo)
|
private val delegate = ModulesApiHistoryJvm(modulesInfo)
|
||||||
|
|
||||||
override fun historyFilesForChangedFiles(changedFiles: Set<File>): Either<Set<File>> {
|
override fun historyFilesForChangedFiles(changedFiles: Set<File>): Either<Set<File>> {
|
||||||
|
|||||||
+2
-1
@@ -58,7 +58,8 @@ class ModulesApiHistoryAndroidTest {
|
|||||||
projectRoot = projectRoot,
|
projectRoot = projectRoot,
|
||||||
dirToModule = mapOf(appKotlinDestination to appEntry, libKotlinDestination to libEntry),
|
dirToModule = mapOf(appKotlinDestination to appEntry, libKotlinDestination to libEntry),
|
||||||
nameToModules = mapOf("app" to setOf(appEntry), "lib" to setOf(libEntry)),
|
nameToModules = mapOf("app" to setOf(appEntry), "lib" to setOf(libEntry)),
|
||||||
jarToClassListFile = mapOf()
|
jarToClassListFile = mapOf(),
|
||||||
|
jarToModule = mapOf()
|
||||||
)
|
)
|
||||||
|
|
||||||
androidHistory = ModulesApiHistoryAndroid(info)
|
androidHistory = ModulesApiHistoryAndroid(info)
|
||||||
|
|||||||
+4
-1
@@ -529,7 +529,10 @@ abstract class BaseGradleIT {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add("-Pkotlin_version=" + options.kotlinVersion)
|
add("-Pkotlin_version=" + options.kotlinVersion)
|
||||||
options.incremental?.let { add("-Pkotlin.incremental=$it") }
|
options.incremental?.let {
|
||||||
|
add("-Pkotlin.incremental=$it")
|
||||||
|
add("-Pkotlin.incremental.js=$it")
|
||||||
|
}
|
||||||
options.usePreciseJavaTracking?.let { add("-Pkotlin.incremental.usePreciseJavaTracking=$it") }
|
options.usePreciseJavaTracking?.let { add("-Pkotlin.incremental.usePreciseJavaTracking=$it") }
|
||||||
options.androidGradlePluginVersion?.let { add("-Pandroid_tools_version=$it") }
|
options.androidGradlePluginVersion?.let { add("-Pandroid_tools_version=$it") }
|
||||||
if (options.debug) {
|
if (options.debug) {
|
||||||
|
|||||||
+201
-166
@@ -8,10 +8,35 @@ import org.junit.Assert
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class IncrementalCompilationMultiProjectIT : BaseGradleIT() {
|
class IncrementalCompilationJsMultiProjectIT : BaseIncrementalCompilationMultiProjectIT() {
|
||||||
override fun defaultBuildOptions(): BuildOptions =
|
override fun defaultProject(): Project {
|
||||||
super.defaultBuildOptions().copy(withDaemon = true, incremental = true)
|
val project = Project("incrementalMultiproject")
|
||||||
|
project.setupWorkingDir()
|
||||||
|
|
||||||
|
for (subProject in arrayOf("app", "lib")) {
|
||||||
|
val subProjectDir = project.projectDir.resolve(subProject)
|
||||||
|
subProjectDir.resolve("src/main/java").deleteRecursively()
|
||||||
|
val buildGradle = subProjectDir.resolve("build.gradle")
|
||||||
|
val buildJsGradle = subProjectDir.resolve("build-js.gradle")
|
||||||
|
buildJsGradle.copyTo(buildGradle, overwrite = true)
|
||||||
|
buildJsGradle.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
return project
|
||||||
|
}
|
||||||
|
|
||||||
|
override val additionalLibDependencies: String =
|
||||||
|
"implementation \"org.jetbrains.kotlin:kotlin-test-js:${'$'}kotlin_version\""
|
||||||
|
}
|
||||||
|
|
||||||
|
class IncrementalCompilationJvmMultiProjectIT : BaseIncrementalCompilationMultiProjectIT() {
|
||||||
|
override val additionalLibDependencies: String =
|
||||||
|
"implementation \"org.jetbrains.kotlin:kotlin-stdlib:${'$'}kotlin_version\""
|
||||||
|
|
||||||
|
override fun defaultProject(): Project =
|
||||||
|
Project("incrementalMultiproject")
|
||||||
|
|
||||||
|
// todo: do the same for js backend
|
||||||
@Test
|
@Test
|
||||||
fun testDuplicatedClass() {
|
fun testDuplicatedClass() {
|
||||||
val project = Project("duplicatedClass")
|
val project = Project("duplicatedClass")
|
||||||
@@ -28,174 +53,12 @@ class IncrementalCompilationMultiProjectIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMoveFunctionFromLib() {
|
|
||||||
val project = Project("incrementalMultiproject")
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
val barUseABKt = project.projectDir.getFileByName("barUseAB.kt")
|
|
||||||
val barInApp = File(project.projectDir, "app/src/main/java/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, weakTesting = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testAddNewMethodToLib() {
|
|
||||||
val project = Project("incrementalMultiproject")
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
val aKt = project.projectDir.getFileByName("A.kt")
|
|
||||||
aKt.writeText(
|
|
||||||
"""
|
|
||||||
package bar
|
|
||||||
|
|
||||||
open class A {
|
|
||||||
fun a() {}
|
|
||||||
fun newA() {}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
val affectedSources = project.projectDir.getFilesByNames("A.kt", "B.kt", "AA.kt", "BB.kt")
|
|
||||||
val relativePaths = project.relativize(affectedSources)
|
|
||||||
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testLibClassBecameFinal() {
|
|
||||||
val project = Project("incrementalMultiproject")
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
val bKt = project.projectDir.getFileByName("B.kt")
|
|
||||||
bKt.modify { it.replace("open class", "class") }
|
|
||||||
|
|
||||||
project.build("build") {
|
|
||||||
assertFailed()
|
|
||||||
val affectedSources = project.projectDir.getFilesByNames(
|
|
||||||
"B.kt", "barUseAB.kt", "barUseB.kt",
|
|
||||||
"BB.kt", "fooCallUseAB.kt", "fooUseB.kt"
|
|
||||||
)
|
|
||||||
val relativePaths = project.relativize(affectedSources)
|
|
||||||
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCleanBuildLib() {
|
|
||||||
val project = Project("incrementalMultiproject")
|
|
||||||
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
project.build(":lib:clean") {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change file so Gradle won't skip :app:compile
|
|
||||||
project.projectFile("BarDummy.kt").modify {
|
|
||||||
it.replace("class BarDummy", "open class BarDummy")
|
|
||||||
}
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
val affectedSources = project.projectDir.allKotlinFiles()
|
|
||||||
val relativePaths = project.relativize(affectedSources)
|
|
||||||
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val aaKt = project.projectFile("AA.kt")
|
|
||||||
aaKt.modify { "$it " }
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
assertCompiledKotlinSources(project.relativize(aaKt), weakTesting = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testAddDependencyToLib() {
|
|
||||||
val project = Project("incrementalMultiproject")
|
|
||||||
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
val libBuildGradle = File(project.projectDir, "lib/build.gradle")
|
|
||||||
Assert.assertTrue("$libBuildGradle does not exist", libBuildGradle.exists())
|
|
||||||
libBuildGradle.modify {
|
|
||||||
"""
|
|
||||||
$it
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation 'junit:junit:4.12'
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
// Change file so Gradle won't skip :app:compile
|
|
||||||
project.projectFile("BarDummy.kt").modify {
|
|
||||||
it.replace("class BarDummy", "open class BarDummy")
|
|
||||||
}
|
|
||||||
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
val affectedSources = project.projectDir.allKotlinFiles()
|
|
||||||
val relativePaths = project.relativize(affectedSources)
|
|
||||||
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val aaKt = project.projectFile("AA.kt")
|
|
||||||
aaKt.modify { "$it " }
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
assertCompiledKotlinSources(project.relativize(aaKt), weakTesting = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testCompileErrorInLib() {
|
|
||||||
val project = Project("incrementalMultiproject")
|
|
||||||
project.build("build") {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
val bKt = project.projectDir.getFileByName("B.kt")
|
|
||||||
bKt.delete()
|
|
||||||
|
|
||||||
project.build("build") {
|
|
||||||
assertFailed()
|
|
||||||
}
|
|
||||||
|
|
||||||
project.projectDir.getFileByName("barUseB.kt").delete()
|
|
||||||
project.projectDir.getFileByName("barUseAB.kt").delete()
|
|
||||||
|
|
||||||
project.build("build") {
|
|
||||||
assertFailed()
|
|
||||||
val affectedSources = project.projectDir.allKotlinFiles()
|
|
||||||
val relativePaths = project.relativize(affectedSources)
|
|
||||||
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks that multi-project ic is disabled when there is a task that outputs to javaDestination dir
|
// checks that multi-project ic is disabled when there is a task that outputs to javaDestination dir
|
||||||
// that is not JavaCompile or KotlinCompile
|
// that is not JavaCompile or KotlinCompile
|
||||||
@Test
|
@Test
|
||||||
fun testCompileLibWithGroovy() {
|
fun testCompileLibWithGroovy() {
|
||||||
val project = Project("incrementalMultiproject")
|
val project = defaultProject()
|
||||||
project.setupWorkingDir()
|
project.setupWorkingDir()
|
||||||
val lib = File(project.projectDir, "lib")
|
val lib = File(project.projectDir, "lib")
|
||||||
val libBuildGradle = File(lib, "build.gradle")
|
val libBuildGradle = File(lib, "build.gradle")
|
||||||
@@ -234,3 +97,175 @@ open class A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class BaseIncrementalCompilationMultiProjectIT : BaseGradleIT() {
|
||||||
|
override fun defaultBuildOptions(): BuildOptions =
|
||||||
|
super.defaultBuildOptions().copy(withDaemon = true, incremental = true)
|
||||||
|
|
||||||
|
protected abstract fun defaultProject(): Project
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMoveFunctionFromLib() {
|
||||||
|
val project = defaultProject()
|
||||||
|
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, weakTesting = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAddNewMethodToLib() {
|
||||||
|
val project = defaultProject()
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
val aKt = project.projectDir.getFileByName("A.kt")
|
||||||
|
aKt.writeText(
|
||||||
|
"""
|
||||||
|
package bar
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
fun a() {}
|
||||||
|
fun newA() {}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
val affectedSources = project.projectDir.getFilesByNames("A.kt", "B.kt", "AA.kt", "BB.kt")
|
||||||
|
val relativePaths = project.relativize(affectedSources)
|
||||||
|
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLibClassBecameFinal() {
|
||||||
|
val project = defaultProject()
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bKt = project.projectDir.getFileByName("B.kt")
|
||||||
|
bKt.modify { it.replace("open class", "class") }
|
||||||
|
|
||||||
|
project.build("build") {
|
||||||
|
assertFailed()
|
||||||
|
val affectedSources = project.projectDir.getFilesByNames(
|
||||||
|
"B.kt", "barUseAB.kt", "barUseB.kt",
|
||||||
|
"BB.kt", "fooCallUseAB.kt", "fooUseB.kt"
|
||||||
|
)
|
||||||
|
val relativePaths = project.relativize(affectedSources)
|
||||||
|
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCleanBuildLib() {
|
||||||
|
val project = defaultProject()
|
||||||
|
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build(":lib:clean") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change file so Gradle won't skip :app:compile
|
||||||
|
project.projectFile("BarDummy.kt").modify {
|
||||||
|
it.replace("class BarDummy", "open class BarDummy")
|
||||||
|
}
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
val affectedSources = project.projectDir.allKotlinFiles()
|
||||||
|
val relativePaths = project.relativize(affectedSources)
|
||||||
|
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val aaKt = project.projectFile("AA.kt")
|
||||||
|
aaKt.modify { "$it " }
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertCompiledKotlinSources(project.relativize(aaKt), weakTesting = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract val additionalLibDependencies: String
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAddDependencyToLib() {
|
||||||
|
val project = defaultProject()
|
||||||
|
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
val libBuildGradle = File(project.projectDir, "lib/build.gradle")
|
||||||
|
Assert.assertTrue("$libBuildGradle does not exist", libBuildGradle.exists())
|
||||||
|
libBuildGradle.modify {
|
||||||
|
"""
|
||||||
|
$it
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
$additionalLibDependencies
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
// Change file so Gradle won't skip :app:compile
|
||||||
|
project.projectFile("BarDummy.kt").modify {
|
||||||
|
it.replace("class BarDummy", "open class BarDummy")
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
val affectedSources = project.projectDir.allKotlinFiles()
|
||||||
|
val relativePaths = project.relativize(affectedSources)
|
||||||
|
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val aaKt = project.projectFile("AA.kt")
|
||||||
|
aaKt.modify { "$it " }
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertCompiledKotlinSources(project.relativize(aaKt), weakTesting = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCompileErrorInLib() {
|
||||||
|
val project = defaultProject()
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bKt = project.projectDir.getFileByName("B.kt")
|
||||||
|
bKt.delete()
|
||||||
|
|
||||||
|
project.build("build") {
|
||||||
|
assertFailed()
|
||||||
|
}
|
||||||
|
|
||||||
|
project.projectDir.getFileByName("barUseB.kt").delete()
|
||||||
|
project.projectDir.getFileByName("barUseAB.kt").delete()
|
||||||
|
|
||||||
|
project.build("build") {
|
||||||
|
assertFailed()
|
||||||
|
val affectedSources = project.projectDir.allKotlinFiles()
|
||||||
|
val relativePaths = project.relativize(affectedSources)
|
||||||
|
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.gradle
|
|||||||
import org.gradle.api.logging.LogLevel
|
import org.gradle.api.logging.LogLevel
|
||||||
import org.jetbrains.kotlin.gradle.tasks.USING_EXPERIMENTAL_JS_INCREMENTAL_COMPILATION_MESSAGE
|
import org.jetbrains.kotlin.gradle.tasks.USING_EXPERIMENTAL_JS_INCREMENTAL_COMPILATION_MESSAGE
|
||||||
import org.jetbrains.kotlin.gradle.util.getFileByName
|
import org.jetbrains.kotlin.gradle.util.getFileByName
|
||||||
|
import org.jetbrains.kotlin.gradle.util.getFilesByNames
|
||||||
import org.jetbrains.kotlin.gradle.util.modify
|
import org.jetbrains.kotlin.gradle.util.modify
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -334,7 +335,8 @@ class Kotlin2JsGradlePluginIT : BaseGradleIT() {
|
|||||||
build("build") {
|
build("build") {
|
||||||
assertSuccessful()
|
assertSuccessful()
|
||||||
assertContains(USING_EXPERIMENTAL_JS_INCREMENTAL_COMPILATION_MESSAGE)
|
assertContains(USING_EXPERIMENTAL_JS_INCREMENTAL_COMPILATION_MESSAGE)
|
||||||
assertCompiledKotlinSources(project.relativize(allKotlinFiles - projectFile("DummyInLibMain.kt")))
|
val affectedFiles = project.projectDir.getFilesByNames("A.kt", "useAInLibMain.kt", "useAInAppMain.kt", "useAInAppTest.kt")
|
||||||
|
assertCompiledKotlinSources(project.relativize(affectedFiles))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
apply plugin: 'kotlin2js'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':lib')
|
||||||
|
// do not remove until KT-25488 is fixed
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
import bar.*
|
||||||
|
|
||||||
|
class AAA : A() {
|
||||||
|
fun aa() {}
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
apply plugin: 'kotlin2js'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// do not remove until KT-25488 is fixed
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
|
||||||
|
}
|
||||||
+1
@@ -1,5 +1,6 @@
|
|||||||
package bar
|
package bar
|
||||||
|
|
||||||
fun useAB(b: B) {
|
fun useAB(b: B) {
|
||||||
|
// todo b.a()
|
||||||
b.b()
|
b.b()
|
||||||
}
|
}
|
||||||
+30
-7
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
|||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||||
import org.gradle.api.invocation.Gradle
|
import org.gradle.api.invocation.Gradle
|
||||||
|
import org.gradle.api.plugins.JavaPluginConvention
|
||||||
|
import org.gradle.jvm.tasks.Jar
|
||||||
import org.jetbrains.kotlin.config.Services
|
import org.jetbrains.kotlin.config.Services
|
||||||
import org.jetbrains.kotlin.daemon.client.CompileServiceSession
|
import org.jetbrains.kotlin.daemon.client.CompileServiceSession
|
||||||
import org.jetbrains.kotlin.daemon.common.*
|
import org.jetbrains.kotlin.daemon.common.*
|
||||||
@@ -37,8 +39,9 @@ import org.jetbrains.kotlin.gradle.incremental.GRADLE_CACHE_VERSION
|
|||||||
import org.jetbrains.kotlin.gradle.incremental.GRADLE_CACHE_VERSION_FILE_NAME
|
import org.jetbrains.kotlin.gradle.incremental.GRADLE_CACHE_VERSION_FILE_NAME
|
||||||
import org.jetbrains.kotlin.gradle.utils.relativeToRoot
|
import org.jetbrains.kotlin.gradle.utils.relativeToRoot
|
||||||
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
|
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||||
import org.jetbrains.kotlin.gradle.tasks.InspectClassesForMultiModuleIC
|
import org.jetbrains.kotlin.gradle.tasks.InspectClassesForMultiModuleIC
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||||
import org.jetbrains.kotlin.gradle.utils.newTmpFile
|
import org.jetbrains.kotlin.gradle.utils.newTmpFile
|
||||||
import org.jetbrains.kotlin.incremental.*
|
import org.jetbrains.kotlin.incremental.*
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@@ -358,15 +361,22 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil
|
|||||||
val dirToModule = HashMap<File, IncrementalModuleEntry>()
|
val dirToModule = HashMap<File, IncrementalModuleEntry>()
|
||||||
val nameToModules = HashMap<String, HashSet<IncrementalModuleEntry>>()
|
val nameToModules = HashMap<String, HashSet<IncrementalModuleEntry>>()
|
||||||
val jarToClassListFile = HashMap<File, File>()
|
val jarToClassListFile = HashMap<File, File>()
|
||||||
|
val jarToModule = HashMap<File, IncrementalModuleEntry>()
|
||||||
|
|
||||||
for (project in gradle.rootProject.allprojects) {
|
for (project in gradle.rootProject.allprojects) {
|
||||||
for (task in project.tasks) {
|
for (task in project.tasks) {
|
||||||
when (task) {
|
when (task) {
|
||||||
is KotlinCompile -> {
|
is AbstractKotlinCompile<*> -> {
|
||||||
val module = IncrementalModuleEntry(project.path, task.moduleName, project.buildDir, task.buildHistoryFile)
|
val module = IncrementalModuleEntry(project.path, task.moduleName, project.buildDir, task.buildHistoryFile)
|
||||||
dirToModule[task.destinationDir] = module
|
dirToModule[task.destinationDir] = module
|
||||||
task.javaOutputDir?.let { dirToModule[it] = module }
|
task.javaOutputDir?.let { dirToModule[it] = module }
|
||||||
nameToModules.getOrPut(module.name) { HashSet() }.add(module)
|
nameToModules.getOrPut(module.name) { HashSet() }.add(module)
|
||||||
|
|
||||||
|
if (task is Kotlin2JsCompile) {
|
||||||
|
jarForSourceSet(project, task.sourceSetName)?.let {
|
||||||
|
jarToModule[it] = module
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is InspectClassesForMultiModuleIC -> {
|
is InspectClassesForMultiModuleIC -> {
|
||||||
jarToClassListFile[File(task.archivePath)] = task.classesListFile
|
jarToClassListFile[File(task.archivePath)] = task.classesListFile
|
||||||
@@ -375,11 +385,24 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return IncrementalModuleInfo(gradle.rootProject.projectDir, dirToModule, nameToModules, jarToClassListFile)
|
return IncrementalModuleInfo(
|
||||||
.also {
|
projectRoot = gradle.rootProject.projectDir,
|
||||||
cachedGradle = WeakReference(gradle)
|
dirToModule = dirToModule,
|
||||||
cachedModulesInfo = it
|
nameToModules = nameToModules,
|
||||||
}
|
jarToClassListFile = jarToClassListFile,
|
||||||
|
jarToModule = jarToModule
|
||||||
|
).also {
|
||||||
|
cachedGradle = WeakReference(gradle)
|
||||||
|
cachedModulesInfo = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun jarForSourceSet(project: Project, sourceSetName: String): File? {
|
||||||
|
val javaConvention = project.convention.findPlugin(JavaPluginConvention::class.java)
|
||||||
|
?: return null
|
||||||
|
val sourceSet = javaConvention.sourceSets.findByName(sourceSetName) ?: return null
|
||||||
|
val jarTask = project.tasks.findByName(sourceSet.jarTaskName) as? Jar
|
||||||
|
return jarTask?.archivePath
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
|||||||
+3
-1
@@ -527,7 +527,9 @@ open class Kotlin2JsCompile() : AbstractKotlinCompile<K2JSCompilerArguments>(),
|
|||||||
computedCompilerClasspath,
|
computedCompilerClasspath,
|
||||||
if (hasFilesInTaskBuildDirectory()) changedFiles else ChangedFiles.Unknown(),
|
if (hasFilesInTaskBuildDirectory()) changedFiles else ChangedFiles.Unknown(),
|
||||||
taskBuildDirectory,
|
taskBuildDirectory,
|
||||||
messageCollector, outputItemCollector, args,
|
messageCollector,
|
||||||
|
outputItemCollector,
|
||||||
|
args,
|
||||||
multiModuleICSettings = multiModuleICSettings
|
multiModuleICSettings = multiModuleICSettings
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user