refactor: use worker API for KtfmtFormatTask
This commit is contained in:
parent
3a694c7255
commit
3e56fa2e12
4 changed files with 104 additions and 52 deletions
|
@ -2,6 +2,7 @@ package app.passwordstore.gradle
|
|||
|
||||
import app.passwordstore.gradle.ktfmt.KtfmtCheckTask
|
||||
import app.passwordstore.gradle.ktfmt.KtfmtFormatTask
|
||||
import java.util.concurrent.Callable
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.register
|
||||
|
@ -9,23 +10,14 @@ import org.gradle.kotlin.dsl.register
|
|||
class KtfmtPlugin : Plugin<Project> {
|
||||
|
||||
override fun apply(target: Project) {
|
||||
target.tasks.register<KtfmtFormatTask>("ktfmtFormat") {
|
||||
source =
|
||||
project.layout.projectDirectory.asFileTree
|
||||
.filter { file ->
|
||||
file.extension == "kt" ||
|
||||
file.extension == "kts" && !file.canonicalPath.contains("build")
|
||||
val input = Callable {
|
||||
target.layout.projectDirectory.asFileTree.filter { file ->
|
||||
file.extension == "kt" || file.extension == "kts" && !file.canonicalPath.contains("build")
|
||||
}
|
||||
.asFileTree
|
||||
}
|
||||
target.tasks.register<KtfmtFormatTask>("ktfmtFormat") { source(input) }
|
||||
target.tasks.register<KtfmtCheckTask>("ktfmtCheck") {
|
||||
source =
|
||||
project.layout.projectDirectory.asFileTree
|
||||
.filter { file ->
|
||||
file.extension == "kt" ||
|
||||
file.extension == "kts" && !file.canonicalPath.contains("build")
|
||||
}
|
||||
.asFileTree
|
||||
source(input)
|
||||
projectDirectory.set(target.layout.projectDirectory)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,52 +1,53 @@
|
|||
package app.passwordstore.gradle.ktfmt
|
||||
|
||||
import com.facebook.ktfmt.format.Formatter
|
||||
import com.facebook.ktfmt.format.FormattingOptions
|
||||
import java.io.File
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.tasks.IgnoreEmptyDirectories
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.tasks.SourceTask
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.internal.exceptions.MultiCauseException
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
abstract class KtfmtFormatTask : SourceTask() {
|
||||
abstract class KtfmtFormatTask
|
||||
@Inject
|
||||
constructor(
|
||||
private val workerExecutor: WorkerExecutor,
|
||||
private val projectLayout: ProjectLayout,
|
||||
) : SourceTask() {
|
||||
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
@get:InputFiles
|
||||
@get:IgnoreEmptyDirectories
|
||||
protected val inputFiles: FileCollection
|
||||
get() = super.getSource()
|
||||
init {
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun execute() {
|
||||
runBlocking(Dispatchers.IO.limitedParallelism(PARALLEL_TASK_LIMIT)) {
|
||||
coroutineScope { inputFiles.map { async { formatFile(it) } }.awaitAll() }
|
||||
val result =
|
||||
with(workerExecutor.noIsolation()) {
|
||||
submit(KtfmtWorkerAction::class.java) {
|
||||
name.set("foofoo")
|
||||
files.from(source)
|
||||
projectDirectory.set(projectLayout.projectDirectory.asFile)
|
||||
}
|
||||
runCatching { await() }
|
||||
}
|
||||
|
||||
result.exceptionOrNull()?.workErrorCauses<Exception>()?.ifNotEmpty {
|
||||
forEach { logger.error(it.message, it.cause) }
|
||||
throw GradleException("error formatting sources for $name")
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatFile(input: File) {
|
||||
val originCode = input.readText()
|
||||
val formattedCode =
|
||||
Formatter.format(
|
||||
FormattingOptions(
|
||||
style = FormattingOptions.Style.GOOGLE,
|
||||
maxWidth = 100,
|
||||
continuationIndent = 2,
|
||||
),
|
||||
originCode
|
||||
)
|
||||
if (originCode != formattedCode) {
|
||||
input.writeText(formattedCode)
|
||||
private inline fun <reified T : Throwable> Throwable.workErrorCauses(): List<Throwable> {
|
||||
return when (this) {
|
||||
is MultiCauseException -> this.causes.map { it.cause }
|
||||
else -> listOf(this.cause)
|
||||
}
|
||||
.filter {
|
||||
// class instance comparison doesn't work due to different classloaders
|
||||
it?.javaClass?.canonicalName == T::class.java.canonicalName
|
||||
}
|
||||
.filterNotNull()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package app.passwordstore.gradle.ktfmt
|
||||
|
||||
import com.facebook.ktfmt.format.Formatter
|
||||
import com.facebook.ktfmt.format.FormattingOptions
|
||||
import java.io.File
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.internal.logging.slf4j.DefaultContextAwareTaskLogger
|
||||
import org.gradle.workers.WorkAction
|
||||
|
||||
abstract class KtfmtWorkerAction : WorkAction<KtfmtWorkerParameters> {
|
||||
private val logger: Logger =
|
||||
DefaultContextAwareTaskLogger(Logging.getLogger(KtfmtFormatTask::class.java))
|
||||
private val files: List<File> = parameters.files.toList()
|
||||
private val projectDirectory: File = parameters.projectDirectory.asFile.get()
|
||||
private val name: String = parameters.name.get()
|
||||
|
||||
override fun execute() {
|
||||
try {
|
||||
files.forEach { file ->
|
||||
val sourceText = file.readText()
|
||||
val relativePath = file.toRelativeString(projectDirectory)
|
||||
|
||||
logger.log(LogLevel.DEBUG, "$name checking format: $relativePath")
|
||||
|
||||
val formattedText =
|
||||
Formatter.format(
|
||||
FormattingOptions(
|
||||
style = FormattingOptions.Style.GOOGLE,
|
||||
maxWidth = 100,
|
||||
continuationIndent = 2,
|
||||
),
|
||||
sourceText
|
||||
)
|
||||
|
||||
if (!formattedText.contentEquals(sourceText)) {
|
||||
logger.log(LogLevel.QUIET, "${file.toRelativeString(projectDirectory)}: Format fixed")
|
||||
file.writeText(formattedText)
|
||||
}
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
throw Exception("format worker execution error", t)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package app.passwordstore.gradle.ktfmt
|
||||
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.workers.WorkParameters
|
||||
|
||||
interface KtfmtWorkerParameters : WorkParameters {
|
||||
val name: Property<String>
|
||||
val files: ConfigurableFileCollection
|
||||
val projectDirectory: RegularFileProperty
|
||||
val output: RegularFileProperty
|
||||
}
|
Loading…
Reference in a new issue