[K/N] Add clangFormat task for automatic patch formatting ^KT-53776

Merge-request: KT-MR-7880
Merged-by: Alexander Shabalin <Alexander.Shabalin@jetbrains.com>
This commit is contained in:
Alexander Shabalin
2022-12-07 14:46:55 +00:00
committed by Space Team
parent 5c9aa88617
commit 314edd7066
6 changed files with 128 additions and 9 deletions
@@ -12,13 +12,11 @@ import org.gradle.process.ExecOperations
import org.gradle.process.ExecResult
import org.gradle.process.ExecSpec
import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.konan.util.DependencyProcessor
fun execLlvmUtility(project: Project, utility: String, action: Action<in ExecSpec>): ExecResult {
val llvmBinDirectory = "${project.platformManager.hostPlatform.absoluteLlvmHome}/bin"
return project.exec(Action<ExecSpec> {
action.execute(this)
executable = "$llvmBinDirectory/$utility"
executable = project.platformManager.resolveLlvmUtility(utility)
})
}
@@ -26,10 +24,11 @@ fun execLlvmUtility(project: Project, utility: String, closure: Closure<in ExecS
return execLlvmUtility(project, utility) { project.configure(this, closure) }
}
fun PlatformManager.resolveLlvmUtility(utility: String) = "${hostPlatform.absoluteLlvmHome}/bin/$utility"
fun ExecOperations.execLlvmUtility(platformManager: PlatformManager, utility: String, action: Action<in ExecSpec>): ExecResult {
val llvmBinDirectory = "${platformManager.hostPlatform.absoluteLlvmHome}/bin"
return exec {
action.execute(this)
executable = "$llvmBinDirectory/$utility"
executable = platformManager.resolveLlvmUtility(utility)
}
}
@@ -16,10 +16,7 @@ import org.gradle.api.services.BuildServiceParameters
import org.gradle.kotlin.dsl.*
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.ExecClang
import org.jetbrains.kotlin.cpp.CompilationDatabaseExtension
import org.jetbrains.kotlin.cpp.CompilationDatabasePlugin
import org.jetbrains.kotlin.cpp.CompileToExecutable
import org.jetbrains.kotlin.cpp.RunGTest
import org.jetbrains.kotlin.cpp.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.konan.target.SanitizerKind
@@ -68,6 +65,7 @@ private abstract class CompileTestsSemaphore : BuildService<BuildServiceParamete
open class CompileToBitcodePlugin : Plugin<Project> {
override fun apply(target: Project) {
target.apply<CompilationDatabasePlugin>()
target.apply<GitClangFormatPlugin>()
target.extensions.create<CompileToBitcodeExtension>(EXTENSION_NAME, target)
}
@@ -0,0 +1,84 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.cpp
import org.gradle.api.DefaultTask
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.UntrackedTask
import org.gradle.api.tasks.options.Option
import org.gradle.kotlin.dsl.getByType
import org.gradle.process.ExecOperations
import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.resolveLlvmUtility
import java.io.ByteArrayOutputStream
import javax.inject.Inject
/**
* A task that formats changed code with clang-format.
*
* Will run <git-clang-format> --binary <clang-format> --force $(git merge-base [parent] HEAD) [directory]
*/
@UntrackedTask(because = "Formatter should always run when asked")
abstract class GitClangFormat : DefaultTask() {
private val platformManager = project.extensions.getByType<PlatformManager>()
/**
* Parent branch for the current branch.
*/
@get:Option(option = "parent", description = "base parent of the branch; by default origin/master")
@get:Input
abstract val parent: Property<String>
/**
* Directory in which to format sources.
*/
@get:Option(option = "directory", description = "directory in which to format sources; by default project's source directory")
@get:Input
abstract val directory: Property<String>
/**
* Whether to run the tool in interactive mode.
*/
@get:Option(option = "interactive", description = "interactively ask about each change before applying; by default false")
@get:Input
abstract val interactive: Property<Boolean>
@get:Inject
protected abstract val execOperations: ExecOperations
@TaskAction
fun run() {
val gitClangFormat = platformManager.resolveLlvmUtility("git-clang-format")
val clangFormat = platformManager.resolveLlvmUtility("clang-format")
val parent = this.parent.get()
val directory = this.directory.get()
val interactive = this.interactive.get()
val commit = ByteArrayOutputStream().let {
execOperations.exec {
executable = "git"
args("merge-base", parent, "HEAD")
standardOutput = it
}
it.toString().trim()
}
execOperations.exec {
executable = gitClangFormat
args("--binary", clangFormat)
args("--force")
if (interactive) {
args("--patch")
// Not a nice experience, but it works.
standardInput = System.`in`
}
args(commit)
args("--")
args(directory)
}
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.cpp
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.*
/**
* Plugin for [GitClangFormat] that creates a task `clangFormat` that will format project sources in the current branch.
*/
open class GitClangFormatPlugin : Plugin<Project> {
override fun apply(target: Project) {
val directory = target.layout.projectDirectory.toString()
target.tasks.register<GitClangFormat>("clangFormat") {
description = "Run clang-format in $directory"
group = TASK_GROUP
parent.convention("origin/master")
this.directory.convention(directory)
interactive.convention(false)
// Needs LLVM toolchain.
// TODO: It does not need every dependency ever, only LLVM toolchain for the host.
dependsOn(":kotlin-native:dependencies:update")
}
}
companion object {
@JvmStatic
val TASK_GROUP = "development support"
}
}
+2
View File
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.CopyCommonSources
import org.jetbrains.kotlin.PlatformInfo
import org.jetbrains.kotlin.KotlinBuildPusher
import org.jetbrains.kotlin.cpp.CompilationDatabasePlugin
import org.jetbrains.kotlin.cpp.GitClangFormatPlugin
import org.jetbrains.kotlin.CompareDistributionSignatures
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.apache.tools.ant.filters.ReplaceTokens
@@ -159,6 +160,7 @@ dependencies {
}
apply plugin: CompilationDatabasePlugin
apply plugin: GitClangFormatPlugin
apply plugin: 'maven-publish'
apply plugin: BasePlugin
+2
View File
@@ -46,6 +46,8 @@ to follow stdlib naming conventions.
## Formatting
For automated formatting you can use [config for CLion](codestyle/cpp/CLionFormat.xml) or `clang-format` (see [config](.clang-format) at the repo's root). Note, that CLion uses `clang-format` by default; this can be turned off if you prefer to use rules from `CLionFormat.xml`.
Since 1.8.20 there's also a `:kotlin-native:clangFormat` task that will effectively run `git-clang-format -f $(git merge-base origin/master HEAD) -- kotlin-native/`.
The task accepts optional arguments `--parent` to specify base branch other than `origin/master`, and `--interactive` to run the tool with `-p` flag and interactively accept or reject formatted patches.
Formatting rules are designed to closely mirror [Kotlin rules](https://kotlinlang.org/docs/reference/coding-conventions.html).