Fix clearing IC caches on rebuild

Previously IC caches in Gradle were not cleared correctly on rebuild,
because only `clean` method was called, but `flush` and `close`
were not.
This commit is contained in:
Alexey Tsvetkov
2019-01-17 22:52:25 +03:00
parent 7dcdba7e1a
commit 9176f9b254
18 changed files with 166 additions and 98 deletions
@@ -46,25 +46,25 @@ open class CompilationOptions(
}
class IncrementalCompilationOptions(
val areFileChangesKnown: Boolean,
val modifiedFiles: List<File>?,
val deletedFiles: List<File>?,
val workingDir: File,
compilerMode: CompilerMode,
targetPlatform: CompileService.TargetPlatform,
/** @See [ReportCategory] */
val areFileChangesKnown: Boolean,
val modifiedFiles: List<File>?,
val deletedFiles: List<File>?,
val workingDir: File,
compilerMode: CompilerMode,
targetPlatform: CompileService.TargetPlatform,
/** @See [ReportCategory] */
reportCategories: Array<Int>,
/** @See [ReportSeverity] */
/** @See [ReportSeverity] */
reportSeverity: Int,
/** @See [CompilationResultCategory]] */
/** @See [CompilationResultCategory]] */
requestedCompilationResults: Array<Int>,
val usePreciseJavaTracking: Boolean,
/**
val usePreciseJavaTracking: Boolean,
/**
* Directories that should be cleared when IC decides to rebuild
*/
val localStateDirs: List<File>,
val multiModuleICSettings: MultiModuleICSettings,
val modulesInfo: IncrementalModuleInfo
val outputFiles: List<File>,
val multiModuleICSettings: MultiModuleICSettings,
val modulesInfo: IncrementalModuleInfo
) : CompilationOptions(compilerMode, targetPlatform, reportCategories, reportSeverity, requestedCompilationResults) {
companion object {
const val serialVersionUID: Long = 0
@@ -79,7 +79,7 @@ class IncrementalCompilationOptions(
"workingDir=$workingDir, " +
"multiModuleICSettings=$multiModuleICSettings, " +
"usePreciseJavaTracking=$usePreciseJavaTracking" +
"localStateDirs=$localStateDirs" +
"outputFiles=$outputFiles" +
")"
}
}
@@ -582,7 +582,7 @@ class CompileServiceImpl(
javaSourceRoots,
reporter,
buildHistoryFile = incrementalCompilationOptions.multiModuleICSettings.buildHistoryFile,
localStateDirs = incrementalCompilationOptions.localStateDirs,
outputFiles = incrementalCompilationOptions.outputFiles,
usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking,
modulesApiHistory = modulesApiHistory,
kotlinSourceFilesExtensions = allKotlinExtensions
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.incremental.storage.BasicMapsOwner
import java.io.File
abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache<*>>(
protected val cachesRootDir: File,
cachesRootDir: File,
protected val reporter: ICReporter
) {
private val caches = arrayListOf<BasicMapsOwner>()
@@ -35,11 +35,6 @@ abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache
val lookupCache: LookupStorage = LookupStorage(lookupCacheDir).apply { registerCache() }
abstract val platformCache: PlatformCache
fun clean() {
caches.forEach { it.clean() }
cachesRootDir.deleteRecursively()
}
fun close(flush: Boolean = false): Boolean {
var successful = true
@@ -47,8 +42,7 @@ abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache
if (flush) {
try {
cache.flush(false)
}
catch (e: Throwable) {
} catch (e: Throwable) {
successful = false
reporter.report { "Exception when flushing cache ${cache.javaClass}: $e" }
}
@@ -56,8 +50,7 @@ abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache
try {
cache.close()
}
catch (e: Throwable) {
} catch (e: Throwable) {
successful = false
reporter.report { "Exception when closing cache ${cache.javaClass}: $e" }
}
@@ -38,11 +38,13 @@ abstract class IncrementalCompilerRunner<
Args : CommonCompilerArguments,
CacheManager : IncrementalCachesManager<*>
>(
workingDir: File,
private val workingDir: File,
cacheDirName: String,
protected val reporter: ICReporter,
private val buildHistoryFile: File,
private val localStateDirs: Collection<File> = emptyList()
// there might be some additional output directories (e.g. for generated java in kapt)
// to remove them correctly on rebuild, we pass them as additional argument
private val outputFiles: Collection<File> = emptyList()
) {
protected val cacheDirectory = File(workingDir, cacheDirName)
@@ -67,19 +69,8 @@ abstract class IncrementalCompilerRunner<
fun rebuild(reason: () -> String): ExitCode {
reporter.report(reason)
caches.clean()
dirtySourcesSinceLastTimeFile.delete()
reporter.report { "Deleting output directories on rebuild:" }
for (dir in sequenceOf(destinationDir(args)) + localStateDirs.asSequence()) {
if (!dir.isDirectory) continue
dir.deleteRecursively()
dir.mkdirs()
reporter.report { "deleted $dir" }
}
caches.close(false)
clearLocalStateOnRebuild(args)
caches = createCacheManager(args)
if (providedChangedFiles == null) {
caches.inputsCache.sourceSnapshotMap.compareAndUpdate(allSourceFiles)
@@ -111,6 +102,34 @@ abstract class IncrementalCompilerRunner<
}
}
private fun clearLocalStateOnRebuild(args: Args) {
val destinationDir = destinationDir(args)
reporter.report { "Clearing output on rebuild" }
for (file in sequenceOf(destinationDir, workingDir) + outputFiles.asSequence()) {
val deleted: Boolean? = when {
file.isDirectory -> {
reporter.report { "Deleting directory $file" }
file.deleteRecursively()
}
file.isFile -> {
reporter.report { "Deleting $file" }
file.delete()
}
else -> null
}
if (deleted == false) {
reporter.report { "Could not delete $file" }
}
}
assert(!destinationDir.exists()) { "Could not delete destination dir $destinationDir" }
assert(!workingDir.exists()) { "Could not delete caches dir $workingDir" }
destinationDir.mkdirs()
workingDir.mkdirs()
}
private fun sourcesToCompile(caches: CacheManager, changedFiles: ChangedFiles, args: Args): CompilationMode =
when (changedFiles) {
is ChangedFiles.Known -> calculateSourcesToCompile(caches, changedFiles, args)
@@ -65,15 +65,15 @@ fun makeIncrementally(
withIC {
val compiler = IncrementalJvmCompilerRunner(
cachesDir,
sourceRoots.map { JvmSourceRoot(it, null) }.toSet(),
reporter,
// Use precise setting in case of non-Gradle build
usePreciseJavaTracking = true,
localStateDirs = emptyList(),
buildHistoryFile = buildHistoryFile,
modulesApiHistory = EmptyModulesApiHistory,
kotlinSourceFilesExtensions = kotlinExtensions
cachesDir,
sourceRoots.map { JvmSourceRoot(it, null) }.toSet(),
reporter,
// Use precise setting in case of non-Gradle build
usePreciseJavaTracking = true,
outputFiles = emptyList(),
buildHistoryFile = buildHistoryFile,
modulesApiHistory = EmptyModulesApiHistory,
kotlinSourceFilesExtensions = kotlinExtensions
)
compiler.compile(sourceFiles, args, messageCollector, providedChangedFiles = null)
}
@@ -102,15 +102,15 @@ class IncrementalJvmCompilerRunner(
reporter: ICReporter,
private val usePreciseJavaTracking: Boolean,
buildHistoryFile: File,
localStateDirs: Collection<File>,
outputFiles: Collection<File>,
private val modulesApiHistory: ModulesApiHistory,
override val kotlinSourceFilesExtensions: List<String> = DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
) : IncrementalCompilerRunner<K2JVMCompilerArguments, IncrementalJvmCachesManager>(
workingDir,
"caches-jvm",
reporter,
localStateDirs = localStateDirs,
buildHistoryFile = buildHistoryFile
outputFiles = outputFiles,
buildHistoryFile = buildHistoryFile
) {
override fun isICEnabled(): Boolean =
IncrementalCompilation.isEnabledForJvm()
@@ -1,9 +1,6 @@
package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.util.allKotlinFiles
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.*
import org.junit.Assert
import org.junit.Test
import java.io.File
@@ -285,5 +282,31 @@ open class A {
assertCompiledKotlinSources(project.relativize(affectedFiles))
}
}
@Test
fun testRemoveLibFromClasspath() {
val project = defaultProject()
project.build("build") {
assertSuccessful()
}
val appBuildGradle = project.projectDir.resolve("app/build.gradle")
val appBuildGradleContent = appBuildGradle.readText()
appBuildGradle.modify { it.checkedReplace("compile project(':lib')", "") }
val aaKt = project.projectDir.getFileByName("AA.kt")
aaKt.addNewLine()
project.build("build") {
assertFailed()
}
appBuildGradle.writeText(appBuildGradleContent)
aaKt.addNewLine()
project.build("build") {
assertSuccessful()
assertCompiledKotlinSources(project.relativize(aaKt))
}
}
}
@@ -25,6 +25,10 @@ fun File.modify(transform: (String) -> String) {
writeText(transform(readText()))
}
fun File.addNewLine() {
modify { "$it\n" }
}
fun createTempDir(prefix: String): File =
Files.createTempDirectory(prefix).toFile().apply {
deleteOnExit()
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.compilerRunner
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.tasks.findToolsJar
@@ -14,7 +15,7 @@ internal class GradleCompilerEnvironment(
val compilerClasspath: List<File>,
messageCollector: GradlePrintingMessageCollector,
outputItemsCollector: OutputItemsCollector,
val localStateDirectories: List<File>,
val outputFiles: FileCollection,
val incrementalCompilationEnvironment: IncrementalCompilationEnvironment? = null
) : CompilerEnvironment(Services.EMPTY, messageCollector, outputItemsCollector) {
val toolsJar: File? by lazy { findToolsJar() }
@@ -140,7 +140,7 @@ internal open class GradleCompilerRunner(protected val task: Task) {
incrementalCompilationEnvironment = incrementalCompilationEnvironment,
incrementalModuleInfo = modulesInfo,
buildFile = buildFile,
localStateDirectories = environment.localStateDirectories,
outputFiles = environment.outputFiles.toList(),
taskPath = task.path
)
TaskLoggers.put(task.path, task.logger)
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.gradle.logging.*
import org.jetbrains.kotlin.gradle.tasks.clearLocalStateDirectories
import org.jetbrains.kotlin.gradle.tasks.throwGradleExceptionIfError
import org.jetbrains.kotlin.gradle.utils.stackTraceAsString
import org.jetbrains.kotlin.incremental.ChangedFiles
@@ -49,7 +48,7 @@ internal class GradleKotlinCompilerWorkArguments(
val incrementalCompilationEnvironment: IncrementalCompilationEnvironment?,
val incrementalModuleInfo: IncrementalModuleInfo?,
val buildFile: File?,
val localStateDirectories: List<File>,
val outputFiles: List<File>,
val taskPath: String
) : Serializable {
companion object {
@@ -77,7 +76,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
private val incrementalCompilationEnvironment = config.incrementalCompilationEnvironment
private val incrementalModuleInfo = config.incrementalModuleInfo
private val buildFile = config.buildFile
private val localStateDirectories = config.localStateDirectories
private val outputFiles = config.outputFiles
private val taskPath = config.taskPath
private val log: KotlinLogger =
@@ -232,7 +231,7 @@ internal class GradleKotlinCompilerWork @Inject constructor(
compilerMode = CompilerMode.INCREMENTAL_COMPILER,
targetPlatform = targetPlatform,
usePreciseJavaTracking = icEnv.usePreciseJavaTracking,
localStateDirs = localStateDirectories,
outputFiles = outputFiles,
multiModuleICSettings = icEnv.multiModuleICSettings,
modulesInfo = incrementalModuleInfo!!
)
@@ -5,6 +5,7 @@ import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.ConventionTask
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.cacheOnlyIfEnabledForKotlin
import org.jetbrains.kotlin.gradle.tasks.isBuildCacheSupported
@@ -13,7 +14,7 @@ import java.io.File
import java.util.jar.JarFile
@CacheableTask
abstract class KaptTask : ConventionTask() {
abstract class KaptTask : ConventionTask(), TaskWithLocalState {
init {
cacheOnlyIfEnabledForKotlin()
@@ -24,6 +25,8 @@ abstract class KaptTask : ConventionTask() {
}
}
override fun localStateDirectories(): FileCollection = project.files()
@get:Internal
internal lateinit var kotlinCompileTask: KotlinCompile
@@ -17,11 +17,11 @@ import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.tasks.clearLocalStateDirectories
import org.jetbrains.kotlin.gradle.tasks.localStateDirectories
import org.jetbrains.kotlin.gradle.tasks.clearLocalState
import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray
open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<K2JVMCompilerArguments> {
@@ -56,7 +56,7 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<K2JV
fun compile() {
logger.debug("Running kapt annotation processing using the Kotlin compiler")
checkAnnotationProcessorClasspath()
clearLocalStateDirectories()
clearLocalState()
val args = prepareCompilerArguments()
@@ -64,7 +64,7 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<K2JV
val outputItemCollector = OutputItemsCollectorImpl()
val environment = GradleCompilerEnvironment(
compilerClasspath, messageCollector, outputItemCollector,
localStateDirectories = localStateDirectories()
outputFiles = allOutputFiles()
)
if (environment.toolsJar == null && !isAtLeastJava9) {
throw GradleException("Could not find tools.jar in system classpath, which is required for kapt to work")
@@ -13,7 +13,7 @@ import org.gradle.workers.IsolationMode
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper
import org.jetbrains.kotlin.gradle.tasks.clearLocalStateDirectories
import org.jetbrains.kotlin.gradle.tasks.clearLocalState
import org.jetbrains.kotlin.gradle.tasks.findKotlinStdlibClasspath
import org.jetbrains.kotlin.gradle.tasks.findToolsJar
import org.jetbrains.kotlin.utils.PathUtil
@@ -48,7 +48,7 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor
fun compile() {
logger.info("Running kapt annotation processing using the Gradle Worker API")
checkAnnotationProcessorClasspath()
clearLocalStateDirectories()
clearLocalState()
val compileClasspath = classpath.files.toMutableList()
if (project.plugins.none { it is KotlinAndroidPluginWrapper }) {
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2019 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.gradle.internal.tasks
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.utils.outputsCompatible
internal interface TaskWithLocalState : Task {
fun localStateDirectories(): FileCollection
}
internal fun TaskWithLocalState.allOutputFiles(): FileCollection =
outputsCompatible.files + localStateDirectories()
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompile
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.fillDefaultValues
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.incremental.ChangedFiles
import java.io.File
@@ -70,7 +71,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
val compilerRunner = compilerRunner()
val environment = GradleCompilerEnvironment(
computedCompilerClasspath, messageCollector, outputItemCollector,
localStateDirectories = localStateDirectories()
outputFiles = allOutputFiles()
)
compilerRunner.runMetadataCompilerAsync(sourceRoots.kotlinSourceFiles, args, environment)
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.FileTree
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Input
@@ -32,12 +33,14 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJsDceOptionsImpl
import java.io.File
@CacheableTask
open class KotlinJsDce : AbstractKotlinCompileTool<K2JSDceArguments>(), KotlinJsDce {
open class KotlinJsDce : AbstractKotlinCompileTool<K2JSDceArguments>(), KotlinJsDce {
init {
cacheOnlyIfEnabledForKotlin()
}
override fun localStateDirectories(): FileCollection = project.files()
override fun createCompilerArgs(): K2JSDceArguments = K2JSDceArguments()
override fun setupCompilerArgs(args: K2JSDceArguments, defaultsOnly: Boolean) {
@@ -26,6 +26,8 @@ import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.incremental.ChangedFiles
import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAwareWithInput
import org.jetbrains.kotlin.gradle.internal.prepareCompilerArguments
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.logging.kotlinWarn
@@ -45,7 +47,11 @@ const val KOTLIN_BUILD_DIR_NAME = "kotlin"
const val USING_JVM_INCREMENTAL_COMPILATION_MESSAGE = "Using Kotlin/JVM incremental compilation"
const val USING_JS_INCREMENTAL_COMPILATION_MESSAGE = "Using Kotlin/JS incremental compilation"
abstract class AbstractKotlinCompileTool<T : CommonToolArguments>() : AbstractCompile(), CompilerArgumentAwareWithInput<T> {
abstract class AbstractKotlinCompileTool<T : CommonToolArguments>
: AbstractCompile(),
CompilerArgumentAwareWithInput<T>,
TaskWithLocalState {
private fun useCompilerClasspathConfigurationMessage(propertyName: String) {
logger.kotlinWarn(
"'$path.$propertyName' is deprecated and will be removed soon. " +
@@ -117,6 +123,8 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
internal val taskBuildDirectory: File
get() = File(File(project.buildDir, KOTLIN_BUILD_DIR_NAME), name)
override fun localStateDirectories(): FileCollection = project.files(taskBuildDirectory)
// indicates that task should compile kotlin incrementally if possible
// it's not possible when IncrementalTaskInputs#isIncremental returns false (i.e first build)
@get:Input
@@ -260,7 +268,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
// To prevent this, we backup outputs before incremental build and restore when exception is thrown
val prevOutputs: Map<File, ByteArray>? = if (incremental && inputs.isIncremental) {
val outputFiles = HashSet<File>()
outputsCompatible.files.forEach {
allOutputFiles().forEach {
if (it.isDirectory) {
it.walk().filterTo(outputFiles, File::isFile)
} else if (it.isFile) {
@@ -272,13 +280,13 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
} else null
if (!incremental) {
clearLocalStateDirectories("IC is disabled")
clearLocalState("IC is disabled")
}
try {
executeImpl(inputs)
} catch (t: Throwable) {
outputsCompatible.files.forEach {
allOutputFiles().forEach {
if (it.isDirectory) {
it.deleteRecursively()
} else if (it.isFile) {
@@ -449,7 +457,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
val environment = GradleCompilerEnvironment(
computedCompilerClasspath, messageCollector, outputItemCollector,
localStateDirectories = localStateDirectories(),
outputFiles = allOutputFiles(),
incrementalCompilationEnvironment = icEnv
)
compilerRunner.runJvmCompilerAsync(
@@ -606,7 +614,7 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
val environment = GradleCompilerEnvironment(
computedCompilerClasspath, messageCollector, outputItemCollector,
localStateDirectories = localStateDirectories(),
outputFiles = allOutputFiles(),
incrementalCompilationEnvironment = icEnv
)
compilerRunner.runJsCompilerAsync(sourceRoots.kotlinSourceFiles, commonSourceSet.toList(), args, environment)
@@ -1,13 +1,11 @@
package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.GradleException
import org.gradle.api.Task
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.compilerRunner.KotlinLogger
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.utils.outputsCompatible
import java.io.File
fun throwGradleExceptionIfError(exitCode: ExitCode) {
when (exitCode) {
@@ -20,27 +18,26 @@ fun throwGradleExceptionIfError(exitCode: ExitCode) {
}
}
internal fun <T : Task> T.localStateDirectories(): List<File> =
outputsCompatible.files.files.filter { it.isDirectory }
internal fun TaskWithLocalState.clearLocalState(reason: String? = null) {
val log = GradleKotlinLogger(logger)
internal fun <T : Task> T.clearLocalStateDirectories(reason: String? = null) {
clearLocalStateDirectories(GradleKotlinLogger(logger), localStateDirectories(), reason)
}
internal fun clearLocalStateDirectories(log: KotlinLogger, localStateDirectories: List<File>, reason: String?) {
log.kotlinDebug {
val suffix = reason?.let { " ($it)" }.orEmpty()
"Clearing output directories$suffix:"
"Clearing output$suffix:"
}
for (dir in localStateDirectories) {
if (!dir.exists()) continue
for (file in allOutputFiles()) {
if (!file.exists()) continue
when {
dir.isDirectory -> {
dir.deleteRecursively()
dir.mkdirs()
log.kotlinDebug { " deleted $dir" }
file.isDirectory -> {
log.debug("Deleting output directory: $file")
file.deleteRecursively()
file.mkdirs()
}
file.isFile -> {
log.debug("Deleting output file: $file")
file.delete()
}
else -> log.kotlinDebug { " skipping $dir (not a directory)" }
}
}
}
}