Skip to content

Commit

Permalink
Builder to run Diktat
Browse files Browse the repository at this point in the history
### What's done:
- added a builder to run Diktat
- reused it in maven plugin

It's part of #1561
  • Loading branch information
nulls committed Nov 15, 2022
1 parent 341ef78 commit 98fb63d
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 47 deletions.
2 changes: 1 addition & 1 deletion diktat-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
</dependency>
<dependency>
<groupId>org.cqfn.diktat</groupId>
<artifactId>diktat-rules</artifactId>
<artifactId>diktat</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

package org.cqfn.diktat.plugin.maven

import org.cqfn.diktat.ruleset.rules.DiktatRuleSetProvider
import org.cqfn.diktat.DiktatProcessCommand
import org.cqfn.diktat.api.DiktatError
import org.cqfn.diktat.ktlint.unwrap

import com.pinterest.ktlint.core.KtLint
import com.pinterest.ktlint.core.LintError
import com.pinterest.ktlint.core.Reporter
import com.pinterest.ktlint.core.RuleExecutionException
import com.pinterest.ktlint.core.RuleSet
import com.pinterest.ktlint.core.api.Baseline
import com.pinterest.ktlint.core.api.Baseline.Status.VALID
import com.pinterest.ktlint.core.api.containsLintError
Expand Down Expand Up @@ -98,9 +98,9 @@ abstract class DiktatBaseMojo : AbstractMojo() {
private lateinit var mavenSession: MavenSession

/**
* @param params instance of [KtLint.ExperimentalParams] used in analysis
* @param command instance of [DiktatProcessCommand] used in analysis
*/
abstract fun runAction(params: KtLint.ExperimentalParams)
abstract fun runAction(command: DiktatProcessCommand)

/**
* Perform code check using diktat ruleset
Expand All @@ -117,9 +117,6 @@ abstract class DiktatBaseMojo : AbstractMojo() {
if (excludes.isNotEmpty()) " and excluding $excludes" else ""
)

val ruleSets by lazy {
listOf(DiktatRuleSetProvider(configFile).get())
}
val baselineResults = baseline?.let { loadBaseline(it.absolutePath) }
?: Baseline(status = VALID)
reporterImpl = resolveReporter(baselineResults)
Expand All @@ -129,7 +126,7 @@ abstract class DiktatBaseMojo : AbstractMojo() {
inputs
.map(::File)
.forEach {
checkDirectory(it, lintErrors, baselineResults.lintErrorsPerFile, ruleSets)
checkDirectory(it, lintErrors, baselineResults.lintErrorsPerFile)
}

reporterImpl.afterAll()
Expand Down Expand Up @@ -201,8 +198,7 @@ abstract class DiktatBaseMojo : AbstractMojo() {
private fun checkDirectory(
directory: File,
lintErrors: MutableList<LintError>,
baselineRules: Map<String, List<LintError>>,
ruleSets: Iterable<RuleSet>
baselineRules: Map<String, List<LintError>>
) {
val (excludedDirs, excludedFiles) = excludes.map(::File).partition { it.isDirectory }
directory
Expand All @@ -222,8 +218,7 @@ abstract class DiktatBaseMojo : AbstractMojo() {
baselineRules.getOrDefault(
file.relativeTo(mavenProject.basedir.parentFile).invariantSeparatorsPath,
emptyList()
),
ruleSets
)
)
reporterImpl.after(file.absolutePath)
} catch (e: RuleExecutionException) {
Expand All @@ -233,26 +228,23 @@ abstract class DiktatBaseMojo : AbstractMojo() {
}
}

private fun checkFile(file: File,
lintErrors: MutableList<LintError>,
baselineErrors: List<LintError>,
ruleSets: Iterable<RuleSet>
private fun checkFile(
file: File,
lintErrors: MutableList<LintError>,
baselineErrors: List<LintError>
) {
val text = file.readText()
val params =
KtLint.ExperimentalParams(
fileName = file.absolutePath,
text = text,
ruleSets = ruleSets,
script = file.extension.equals("kts", ignoreCase = true),
cb = { lintError, isCorrected ->
if (!baselineErrors.containsLintError(lintError)) {
reporterImpl.onLintError(file.absolutePath, lintError, isCorrected)
lintErrors.add(lintError)
}
},
debug = debug
)
runAction(params)
val command = DiktatProcessCommand.Builder()
.file(file)
.fileContent(file.readText(Charsets.UTF_8))
.isScript(file.extension.equals("kts", ignoreCase = true))
.callback { error: DiktatError, isCorrected: Boolean ->
val ktlintError = error.unwrap()
if (!baselineErrors.containsLintError(ktlintError)) {
reporterImpl.onLintError(file.absolutePath, ktlintError, isCorrected)
lintErrors.add(ktlintError)
}
}
.build()
runAction(command)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,22 @@

package org.cqfn.diktat.plugin.maven

import org.cqfn.diktat.DiktatProcessCommand
import org.cqfn.diktat.ruleset.rules.DiktatRuleSetProvider
import org.cqfn.diktat.ruleset.utils.ignoreCorrectedErrors

import com.pinterest.ktlint.core.KtLint
import org.apache.maven.plugins.annotations.Mojo

import java.io.File

/**
* Main [Mojo] that call [DiktatRuleSetProvider]'s rules on [inputs] files
*/
@Mojo(name = "check")
@Suppress("unused")
class DiktatCheckMojo : DiktatBaseMojo() {
/**
* @param params instance of [KtLint.ExperimentalParams] used in analysis
* @param command instance of [DiktatProcessCommand] used in analysis
*/
override fun runAction(params: KtLint.ExperimentalParams) {
KtLint.lint(params)
override fun runAction(command: DiktatProcessCommand) {
command.check()
}
}

Expand All @@ -34,15 +31,15 @@ class DiktatCheckMojo : DiktatBaseMojo() {
@Suppress("unused")
class DiktatFixMojo : DiktatBaseMojo() {
/**
* @param params instance of [KtLint.Params] used in analysis
* @param command instance of [DiktatProcessCommand] used in analysis
*/
override fun runAction(params: KtLint.ExperimentalParams) {
val fileName = params.fileName
val fileContent = File(fileName).readText(charset("UTF-8"))
val formattedText = KtLint.format(params.ignoreCorrectedErrors())
override fun runAction(command: DiktatProcessCommand) {
val fileName = command.file.name
val fileContent = command.fileContent
val formattedText = command.fix()
if (fileContent != formattedText) {
log.info("Original and formatted content differ, writing to $fileName...")
File(fileName).writeText(formattedText, charset("UTF-8"))
command.file.writeText(formattedText, Charsets.UTF_8)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.cqfn.diktat

import org.cqfn.diktat.api.DiktatCallback
import org.cqfn.diktat.ktlint.wrap
import org.cqfn.diktat.ruleset.rules.DiktatRuleSetProvider
import com.pinterest.ktlint.core.KtLint
import com.pinterest.ktlint.core.api.EditorConfigDefaults
import com.pinterest.ktlint.core.api.EditorConfigOverride
import java.io.File

/**
* Command to run `diktat`
*/
class DiktatProcessCommand private constructor(
val file: File,
val fileContent: String,
private val callback: DiktatCallback,
private val isScript: Boolean,
) {
/**
* Run `diktat fix` using parameters from current command
*
* @return result of `diktat fix`
*/
fun fix(): String {
return KtLint.format(ktLintParams())
}

/**
* Run `diktat check` using parameters from current command
*/
fun check() {
KtLint.lint(ktLintParams())
}

private fun ktLintParams(): KtLint.ExperimentalParams = KtLint.ExperimentalParams(
fileName = file.absolutePath,
text = fileContent,
ruleSets = setOf(DiktatRuleSetProvider().get()),
ruleProviders = emptySet(),
userData = emptyMap(),
cb = { e, corrected ->
callback.accept(e.wrap(), corrected)
},
script = isScript,
editorConfigPath = null,
debug = false,
editorConfigDefaults = EditorConfigDefaults.emptyEditorConfigDefaults,
editorConfigOverride = EditorConfigOverride.emptyEditorConfigOverride,
isInvokedFromCli = false
)

/**
* Builder for [DiktatProcessCommand]
*
* @property file
* @property fileContent
* @property callback
* @property isScript
*/
data class Builder(
var file: File? = null,
var fileContent: String? = null,
var callback: DiktatCallback? = null,
var isScript: Boolean? = null,
) {
fun file(file: File) = apply { this.file = file }
fun fileContent(fileContent: String) = apply { this.fileContent = fileContent }
fun callback(callback: DiktatCallback) = apply { this.callback = callback }
fun isScript(isScript: Boolean) = apply { this.isScript = isScript }

fun build() = DiktatProcessCommand(
requireNotNull(file),
requireNotNull(fileContent),
requireNotNull(callback),
requireNotNull(isScript),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.cqfn.diktat.api

import java.util.function.BiConsumer

/**
* Callback for diktat process
*/
@FunctionalInterface
fun interface DiktatCallback : BiConsumer<DiktatError, Boolean>
31 changes: 31 additions & 0 deletions diktat-ruleset/src/main/kotlin/org/cqfn/diktat/api/DiktatError.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.cqfn.diktat.api

/**
* Error found by `diktat`
*/
interface DiktatError {
/**
* @return line number (one-based)
*/
fun getLine(): Int

/**
* @return column number (one-based)
*/
fun getCol(): Int

/**
* @return rule id
*/
fun getRuleId(): String

/**
* error message
*/
fun getDetail(): String

/**
* @return true if the found error can be fixed
*/
fun canBeAutoCorrected(): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.cqfn.diktat.ktlint

import org.cqfn.diktat.api.DiktatError
import com.pinterest.ktlint.core.LintError

/**
* Wrapper for KtLint error
*
* @property lintError
*/
data class LintErrorWrapper(
val lintError: LintError
) : DiktatError {
override fun getLine(): Int = lintError.line

override fun getCol(): Int = lintError.col

override fun getRuleId(): String = lintError.ruleId

override fun getDetail(): String = lintError.detail

override fun canBeAutoCorrected(): Boolean = lintError.canBeAutoCorrected
}

/**
* @return [DiktatError] from KtLint [LintError]
*/
fun LintError.wrap(): DiktatError = LintErrorWrapper(this)

/**
* @return KtLint [LintError] from [DiktatError] or exception
*/
fun DiktatError.unwrap(): LintError = (this as? LintErrorWrapper)?.lintError ?: error("Unsupported wrapper for ${DiktatError::class.java.simpleName}")

0 comments on commit 98fb63d

Please sign in to comment.