Skip to content

Commit

Permalink
cortinico#181 - found the magic reformatAll task
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudshiftchris committed Jul 31, 2023
1 parent 7c3b3dd commit f64d8b8
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 132 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
/local.properties
.DS_Store
/build
.idea/
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ internal data class FormattingOptionsBean(
enum class Style {
FACEBOOK,
DROPBOX,
GOOGLE;
GOOGLE
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.ncorti.ktfmt.gradle
import com.ncorti.ktfmt.gradle.FormattingOptionsBean.Style.DROPBOX
import com.ncorti.ktfmt.gradle.FormattingOptionsBean.Style.FACEBOOK
import com.ncorti.ktfmt.gradle.FormattingOptionsBean.Style.GOOGLE
import javax.inject.Inject
import org.gradle.api.provider.Property

/** Gradle Extension to help you configure ktfmt-gradle */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,41 +26,50 @@ abstract class KtfmtPlugin : Plugin<Project> {
private lateinit var topLevelFormat: TaskProvider<Task>
private lateinit var topLevelCheck: TaskProvider<Task>

override fun apply(project: Project) = project.run {
ktfmtExtension =
project.extensions.create(EXTENSION_NAME, KtfmtExtension::class.java)
override fun apply(project: Project) =
project.run {
ktfmtExtension = project.extensions.create(EXTENSION_NAME, KtfmtExtension::class.java)

// setup to pull in ktfmt separately to run on an isolated classloader
val ktFmt = configurations.create("ktfmt").apply {
attributes .apply{
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME))
}
isVisible = false
isCanBeConsumed = false
}
// setup to pull in ktfmt separately to run on an isolated classloader
val ktFmt =
configurations.create("ktfmt").apply {
attributes.apply {
attribute(
Usage.USAGE_ATTRIBUTE,
project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME)
)
}
isVisible = false
isCanBeConsumed = false
}

project.dependencies.add(ktFmt.name,"com.facebook:ktfmt:0.44")
project.dependencies.add(ktFmt.name, "com.facebook:ktfmt:0.44")

project.tasks.withType(KtfmtBaseTask::class.java).configureEach {
it.ktfmtClasspath.from(ktFmt)
}
project.tasks.withType(KtfmtBaseTask::class.java).configureEach {
it.ktfmtClasspath.from(ktFmt)
}

topLevelFormat = createTopLevelFormatTask(project)
topLevelCheck = createTopLevelCheckTask(project)
topLevelFormat = createTopLevelFormatTask(project)
topLevelCheck = createTopLevelCheckTask(project)

project.plugins.withId("kotlin") { applyKtfmt(project) }
project.plugins.withId("kotlin-android") {
if (project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform")) {
project.logger.i("Skipping Android task creation, as KMP is applied")
} else {
applyKtfmtToAndroidProject(project, ktfmtExtension, topLevelFormat, topLevelCheck)
project.plugins.withId("kotlin") { applyKtfmt(project) }
project.plugins.withId("kotlin-android") {
if (project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform")) {
project.logger.i("Skipping Android task creation, as KMP is applied")
} else {
applyKtfmtToAndroidProject(
project,
ktfmtExtension,
topLevelFormat,
topLevelCheck
)
}
}
project.plugins.withId("org.jetbrains.kotlin.js") { applyKtfmt(project) }
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
applyKtfmtToMultiplatformProject(project)
}
}
project.plugins.withId("org.jetbrains.kotlin.js") { applyKtfmt(project) }
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
applyKtfmtToMultiplatformProject(project)
}
}

private fun applyKtfmt(project: Project) {
val extension = project.extensions.getByType(KotlinProjectExtension::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import java.io.File

internal object IncludedFilesParser {
fun parse(value: String, rootDir: File): Set<File> {
if(value.isBlank()) return emptySet()
return value.split(',', ':')
if (value.isBlank()) return emptySet()
return value
.split(',', ':')
.map {
val relativePath = it.removePrefix("/").removePrefix("\\")
rootDir.resolve(relativePath.replace("\\", "/")).canonicalFile
}
.toSet()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import com.ncorti.ktfmt.gradle.FormattingOptionsBean
import com.ncorti.ktfmt.gradle.KtfmtExtension
import com.ncorti.ktfmt.gradle.KtfmtPlugin
import com.ncorti.ktfmt.gradle.util.d
import java.io.File
import java.util.*
import org.gradle.api.UnknownDomainObjectException
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
Expand All @@ -15,8 +17,6 @@ import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.options.Option
import org.gradle.workers.WorkQueue
import org.gradle.workers.WorkerExecutor
import java.io.File
import java.util.*

/**
* ktfmt-gradle base Gradle tasks. Handles a coroutine scope and contains method to propertly
Expand All @@ -31,17 +31,14 @@ abstract class KtfmtBaseTask(
includeOnly.convention("")
}

@get:InputFiles
internal abstract val ktfmtClasspath: ConfigurableFileCollection
@get:InputFiles internal abstract val ktfmtClasspath: ConfigurableFileCollection

@get:Input
@get:Optional
internal var bean: FormattingOptionsBean? = null
@get:Input @get:Optional internal var bean: FormattingOptionsBean? = null

@get:Option(
option = "include-only",
description =
"A comma separate list of relative file paths to include exclusively. " +
"A comma separate list of relative file paths to include exclusively. " +
"If set the task will run the processing only on such files."
)
@get:Input
Expand All @@ -55,9 +52,8 @@ abstract class KtfmtBaseTask(

@TaskAction
internal fun taskAction() {
val workQueue = workerExecutor.classLoaderIsolation { spec ->
spec.classpath.from(ktfmtClasspath)
}
val workQueue =
workerExecutor.classLoaderIsolation { spec -> spec.classpath.from(ktfmtClasspath) }
execute(workQueue)
}

Expand Down Expand Up @@ -86,12 +82,18 @@ abstract class KtfmtBaseTask(
}
}

internal fun <T : KtfmtWorkAction> FileCollection.submitToQueue(queue: WorkQueue, action: Class<T>): List<Result> {
internal fun <T : KtfmtWorkAction> FileCollection.submitToQueue(
queue: WorkQueue,
action: Class<T>
): List<Result> {
val workingDir = temporaryDir.resolve(UUID.randomUUID().toString())
workingDir.mkdirs()
try {
val includedFiles = IncludedFilesParser.parse(includeOnly.get(), layout.projectDirectory.asFile)
logger.d("Preparing to format: includeOnly=${includeOnly.orNull}, includedFiles = $includedFiles")
val includedFiles =
IncludedFilesParser.parse(includeOnly.get(), layout.projectDirectory.asFile)
logger.d(
"Preparing to format: includeOnly=${includeOnly.orNull}, includedFiles = $includedFiles"
)
forEach {
queue.submit(action) { parameters ->
parameters.sourceFile.set(it)
Expand All @@ -104,13 +106,14 @@ abstract class KtfmtBaseTask(
queue.await()

val files = workingDir.listFiles() ?: emptyArray()
return files.asSequence().filter { it.isFile }.map {
Result.fromResultString(it.readText())
}.toList()
return files
.asSequence()
.filter { it.isFile }
.map { Result.fromResultString(it.readText()) }
.toList()
} finally {
// remove working directory and everything in it
workingDir.deleteRecursively()
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ package com.ncorti.ktfmt.gradle.tasks
import com.ncorti.ktfmt.gradle.util.KtfmtUtils
import com.ncorti.ktfmt.gradle.util.d
import com.ncorti.ktfmt.gradle.util.i
import javax.inject.Inject
import org.gradle.api.file.ProjectLayout
import org.gradle.workers.WorkQueue
import org.gradle.workers.WorkerExecutor
import javax.inject.Inject

/** ktfmt-gradle Check task. Verifies if the output of ktfmt is the same as the input */
abstract class KtfmtCheckTask @Inject constructor(
workerExecutor: WorkerExecutor,
layout: ProjectLayout
) : KtfmtBaseTask(workerExecutor, layout) {
abstract class KtfmtCheckTask
@Inject
constructor(workerExecutor: WorkerExecutor, layout: ProjectLayout) :
KtfmtBaseTask(workerExecutor, layout) {

init {
group = KtfmtUtils.GROUP_VERIFICATION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ package com.ncorti.ktfmt.gradle.tasks
import com.ncorti.ktfmt.gradle.util.KtfmtUtils
import com.ncorti.ktfmt.gradle.util.d
import com.ncorti.ktfmt.gradle.util.i
import javax.inject.Inject
import org.gradle.api.file.FileCollection
import org.gradle.api.file.ProjectLayout
import org.gradle.api.tasks.OutputFiles
import org.gradle.workers.WorkQueue
import org.gradle.workers.WorkerExecutor
import javax.inject.Inject

/** ktfmt-gradle Format task. Replaces input file content with its formatted equivalent. */
abstract class KtfmtFormatTask @Inject constructor(
workerExecutor: WorkerExecutor,
layout: ProjectLayout
) : KtfmtBaseTask(workerExecutor, layout) {
abstract class KtfmtFormatTask
@Inject
constructor(workerExecutor: WorkerExecutor, layout: ProjectLayout) :
KtfmtBaseTask(workerExecutor, layout) {

@get:OutputFiles
protected val outputFiles: FileCollection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import com.facebook.ktfmt.format.ParseError
import com.google.googlejavaformat.FormattingError
import com.ncorti.ktfmt.gradle.FormattingOptionsBean
import com.ncorti.ktfmt.gradle.util.d
import org.gradle.api.logging.Logging
import java.io.File
import java.io.IOException
import org.gradle.api.logging.Logging

// format the specific file and return the result
// this implementation is decoupled from Gradle APIs for ease of testing
Expand All @@ -26,20 +26,25 @@ internal object KtfmtFormatter {
logger.d("Formatting: $ctx")
if (ctx.includedFiles.isNotEmpty()) {
if (ctx.sourceFile.canonicalFile !in ctx.includedFiles) {
return KtfmtResult.KtfmtSkipped(ctx.sourceFile, "Not included inside --include-only")
return KtfmtResult.KtfmtSkipped(
ctx.sourceFile,
"Not included inside --include-only"
)
}
}
return try {
val originCode = ctx.sourceFile.readText()
val formattedCode = Formatter.format(ctx.formattingOptions.toFormattingOptions(), originCode)
val formattedCode =
Formatter.format(ctx.formattingOptions.toFormattingOptions(), originCode)
val isCorrectlyFormatted = originCode == formattedCode
KtfmtResult.KtfmtSuccess(ctx.sourceFile, isCorrectlyFormatted, formattedCode)
} catch (cause: Throwable) {
val message =
when (cause) {
is IOException -> "Unable to read file"
is ParseError -> "Failed to parse file"
is FormattingError -> cause.diagnostics().joinToString("\n") { "${ctx.sourceFile}:$it" }
is FormattingError ->
cause.diagnostics().joinToString("\n") { "${ctx.sourceFile}:$it" }
else -> "Generic error during file processing"
}
KtfmtResult.KtfmtFailure(ctx.sourceFile, message, cause)
Expand All @@ -62,4 +67,4 @@ internal fun FormattingOptionsBean.Style.toKtfmtStyle(): FormattingOptions.Style
FormattingOptionsBean.Style.FACEBOOK -> FormattingOptions.Style.FACEBOOK
FormattingOptionsBean.Style.DROPBOX -> FormattingOptions.Style.DROPBOX
FormattingOptionsBean.Style.GOOGLE -> FormattingOptions.Style.GOOGLE
}
}
Loading

0 comments on commit f64d8b8

Please sign in to comment.