Clikt: Мощный CLI фреймворк для Kotlin
Clikt — это современный, легковесный фреймворк для создания консольных (CLI) приложений на языке Kotlin. В отличие от многих других библиотек, Clikt использует декларативный подход, позволяя описывать структуру команд и их параметры с помощью простых аннотаций и лямбда-выражений. Это делает код чистым, читаемым и легко поддерживаемым. Библиотека идеально подходит как для небольших утилит, так и для сложных многоуровневых интерфейсов командной строки.
Ключевые возможности Clikt
- Декларативный синтаксис: Определение команд, опций и аргументов через DSL (Domain Specific Language) или аннотации.
- Автоматическая генерация справки: Clikt автоматически создает красивое и структурированное сообщение
--helpна основе ваших определений. - Поддержка вложенных команд: Создавайте иерархии команд (например,
git commit,git push) с помощью простого механизма подкоманд. - Валидация значений: Встроенные механизмы для проверки типов, диапазонов, форматов и пользовательских условий.
- Автодополнение: Нативная поддержка генерации скриптов автодополнения для Bash, Zsh и Fish.
- Тестируемость: Удобные инструменты для тестирования CLI-приложений без реального запуска в терминале.
Установка и подключение
Для начала работы добавьте зависимость в ваш build.gradle.kts:
repositories {
mavenCentral()
}
dependencies {
implementation("com.github.ajalt.clikt:clikt:4.4.0")
}
Для Maven используйте:
<dependency>
<groupId>com.github.ajalt.clikt</groupId>
<artifactId>clikt</artifactId>
<version>4.4.0</version>
</dependency>
Базовый пример: приветствие
Создадим простую команду, которая принимает имя пользователя и опциональный флаг для приветствия на разных языках.
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.option
class Greet : CliktCommand() {
val name: String by argument(help = "Имя пользователя")
val formal: Boolean by option("--formal", "-f", help = "Формальное приветствие").flag()
override fun run() {
val greeting = if (formal) "Здравствуйте" else "Привет"
echo("$greeting, $name!")
}
}
fun main(args: Array<String>) = Greet().main(args)
Запуск из командной строки:
$ kotlin greet.kts Иван
Привет, Иван!
$ kotlin greet.kts --formal Иван
Здравствуйте, Иван!
$ kotlin greet.kts --help
Usage: greet [<options>] <name>
Имя пользователя
Options:
-f, --formal Формальное приветствие
-h, --help Show this message and exit
Продвинутый пример: работа с файлами и подкомандами
Рассмотрим более сложный сценарий — утилиту для работы с текстовыми файлами с поддержкой подкоманд count и search.
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.option
import java.io.File
class FileTool : CliktCommand() {
override fun run() = Unit // Корневая команда ничего не делает
}
class Count : CliktCommand(help = "Подсчитать строки в файле") {
val file: File by argument(help = "Путь к файлу")
.validate { require(it.exists()) { "Файл не найден: $it" } }
override fun run() {
val lines = file.readLines().size
echo("Количество строк: $lines")
}
}
class Search : CliktCommand(help = "Поиск подстроки в файле") {
val file: File by argument(help = "Путь к файлу")
val pattern: String by option("--pattern", "-p", help = "Искомая строка").default("")
override fun run() {
val found = file.readLines().filter { it.contains(pattern) }
if (found.isEmpty()) {
echo("Совпадений не найдено.")
} else {
found.forEach {