You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

118 lines
4.3 KiB

/*
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
package org.jetbrains.compose.desktop.application.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.Directory
import org.gradle.api.internal.file.FileOperations
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.LocalState
import org.gradle.process.ExecOperations
import org.gradle.process.ExecResult
import org.jetbrains.compose.desktop.application.internal.ComposeProperties
import org.jetbrains.compose.desktop.application.internal.alsoOutputTo
import org.jetbrains.compose.desktop.application.internal.ioFile
import org.jetbrains.compose.desktop.application.internal.notNullProperty
import java.io.File
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import javax.inject.Inject
abstract class AbstractComposeDesktopTask : DefaultTask() {
@get:Inject
protected abstract val objects: ObjectFactory
@get:Inject
protected abstract val providers: ProviderFactory
@get:Inject
protected abstract val execOperations: ExecOperations
@get:Inject
protected abstract val fileOperations: FileOperations
@get:LocalState
protected val logsDir: Provider<Directory> = project.layout.buildDirectory.dir("compose/logs/$name")
@get:Internal
val verbose: Property<Boolean> = objects.notNullProperty<Boolean>().apply {
set(providers.provider {
logger.isDebugEnabled || ComposeProperties.isVerbose(providers).get()
})
}
internal fun runExternalTool(
tool: File,
args: Collection<String>,
environment: Map<String, Any> = emptyMap(),
workingDir: File? = null,
checkExitCodeIsNormal: Boolean = true,
processStdout: Function1<String, Unit>? = null,
forceLogToFile: Boolean = false
): ExecResult {
val logsDir = logsDir.ioFile
logsDir.mkdirs()
val toolName = tool.nameWithoutExtension
val logToConsole = verbose.get() && !forceLogToFile
val outFile = logsDir.resolve("${toolName}-${currentTimeStamp()}-out.txt")
val errFile = logsDir.resolve("${toolName}-${currentTimeStamp()}-err.txt")
val result = outFile.outputStream().buffered().use { outFileStream ->
errFile.outputStream().buffered().use { errFileStream ->
execOperations.exec { spec ->
spec.executable = tool.absolutePath
spec.args(*args.toTypedArray())
workingDir?.let { wd -> spec.workingDir(wd) }
spec.environment(environment)
// check exit value later
spec.isIgnoreExitValue = true
if (logToConsole) {
spec.standardOutput = spec.standardOutput.alsoOutputTo(outFileStream)
spec.errorOutput = spec.errorOutput.alsoOutputTo(errFileStream)
} else {
spec.standardOutput = outFileStream
spec.errorOutput = errFileStream
}
}
}
}
if (checkExitCodeIsNormal && result.exitValue != 0) {
val errMsg = buildString {
appendln("External tool execution failed:")
val cmd = (listOf(tool.absolutePath) + args).joinToString(", ")
appendln("* Command: [$cmd]")
appendln("* Working dir: [${workingDir?.absolutePath.orEmpty()}]")
appendln("* Exit code: ${result.exitValue}")
appendln("* Standard output log: ${outFile.absolutePath}")
appendln("* Error log: ${errFile.absolutePath}")
}
error(errMsg)
}
if (processStdout != null) {
processStdout(outFile.readText())
}
if (result.exitValue == 0) {
outFile.delete()
errFile.delete()
}
return result
}
private fun currentTimeStamp() =
LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"))
}