forked from pinterest/ktlint
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add "installGitPreCommitHook" sub command. (pinterest#487)
Move old one (`--install-git-pre-commit-hook`) option to be a ktlint subcommand - new syntax: `ktlint installGitPreCommitHook`. Old one `--install-git-pre-commit-hook` is still working, but deprecated. Signed-off-by: Yahor Berdnikau <[email protected]>
- Loading branch information
1 parent
fd43a86
commit fc33148
Showing
5 changed files
with
138 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
ktlint/src/main/kotlin/com/pinterest/ktlint/internal/ByteArrayExt.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.pinterest.ktlint.internal | ||
|
||
import java.math.BigInteger | ||
import java.security.MessageDigest | ||
|
||
/** | ||
* Generate hex string for given [ByteArray] content. | ||
*/ | ||
internal val ByteArray.hex get() = BigInteger(MessageDigest.getInstance("SHA-256").digest(this)).toString(16) |
20 changes: 20 additions & 0 deletions
20
ktlint/src/main/kotlin/com/pinterest/ktlint/internal/CommandLineExt.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.pinterest.ktlint.internal | ||
|
||
import kotlin.system.exitProcess | ||
import picocli.CommandLine | ||
|
||
/** | ||
* Check if user requested either help or version options, if yes - print it | ||
* and exit process with [exitCode] exit code. | ||
*/ | ||
internal fun CommandLine.printHelpOrVersionUsage( | ||
exitCode: Int = 0 | ||
) { | ||
if (isUsageHelpRequested) { | ||
usage(System.out, CommandLine.Help.Ansi.OFF) | ||
exitProcess(exitCode) | ||
} else if (isVersionHelpRequested) { | ||
printVersionHelp(System.out, CommandLine.Help.Ansi.OFF) | ||
exitProcess(exitCode) | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GitPreCommitHookSubCommand.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package com.pinterest.ktlint.internal | ||
|
||
import com.pinterest.ktlint.KtlintCommandLine | ||
import java.io.File | ||
import kotlin.system.exitProcess | ||
import picocli.CommandLine | ||
|
||
@CommandLine.Command( | ||
description = [ | ||
"Install git hook to automatically check files for style violations on commit", | ||
"Usage of \"--install-git-pre-commit-hook\" command line option is deprecated!" | ||
], | ||
aliases = ["--install-git-pre-commit-hook"], | ||
mixinStandardHelpOptions = true, | ||
versionProvider = KtlintVersionProvider::class | ||
) | ||
class GitPreCommitHookSubCommand : Runnable { | ||
@CommandLine.ParentCommand | ||
private lateinit var ktlintCommand: KtlintCommandLine | ||
|
||
@CommandLine.Spec | ||
private lateinit var commandSpec: CommandLine.Model.CommandSpec | ||
|
||
override fun run() { | ||
commandSpec.commandLine().printHelpOrVersionUsage() | ||
|
||
val gitHooksDir = resolveGitHooksDir() | ||
val preCommitHookFile = gitHooksDir.resolve("pre-commit") | ||
val preCommitHook = loadGitPreCommitHookTemplate() | ||
|
||
if (preCommitHookFile.exists()) { | ||
backupExistingPreCommitHook(gitHooksDir, preCommitHookFile, preCommitHook) | ||
} | ||
|
||
// > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit | ||
preCommitHookFile.writeBytes(preCommitHook) | ||
preCommitHookFile.setExecutable(true) | ||
println(".git/hooks/pre-commit installed") | ||
} | ||
|
||
private fun resolveGitHooksDir(): File { | ||
val gitDir = File(".git") | ||
if (!gitDir.isDirectory) { | ||
System.err.println( | ||
".git directory not found. Are you sure you are inside project root directory?" | ||
) | ||
exitProcess(1) | ||
} | ||
|
||
val hooksDir = gitDir.resolve("hooks") | ||
if (!hooksDir.exists() && !hooksDir.mkdir()) { | ||
System.err.println("Failed to create .git/hooks folder") | ||
exitProcess(1) | ||
} | ||
|
||
return hooksDir | ||
} | ||
|
||
private fun loadGitPreCommitHookTemplate(): ByteArray = ClassLoader | ||
.getSystemClassLoader() | ||
.getResourceAsStream( | ||
"ktlint-git-pre-commit-hook${if (ktlintCommand.android) "-android" else ""}.sh" | ||
).use { it.readBytes() } | ||
|
||
private fun backupExistingPreCommitHook( | ||
hooksDir: File, | ||
preCommitHookFile: File, | ||
expectedPreCommitHook: ByteArray | ||
) { | ||
// backup existing hook (if any) | ||
val actualPreCommitHook = preCommitHookFile.readBytes() | ||
if (actualPreCommitHook.isNotEmpty() && | ||
!actualPreCommitHook.contentEquals(expectedPreCommitHook) | ||
) { | ||
val backupFile = hooksDir.resolve("pre-commit.ktlint-backup.${actualPreCommitHook.hex}") | ||
println(".git/hooks/pre-commit -> $backupFile") | ||
preCommitHookFile.copyTo(backupFile, overwrite = true) | ||
} | ||
} | ||
|
||
companion object { | ||
const val COMMAND_NAME = "installGitPreCommitHook" | ||
} | ||
} |