市面上有不少交互式命令行工具
picocli\jline\kotlin-REPL\jshell
有些直接可以使用,有些需要部分改造,我使用Picocli-shell-jline项目的基础上实现了一款交互式命令行的LicenseGenerator工具
引入maven依赖
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli-shell-jline3</artifactId>
<version>4.7.4</version>
</dependency>
启动
try {
val workDir = Supplier { Paths.get(System.getProperty("user.dir")) }
// set up JLine built-in commands
val builtins = Builtins(workDir, ConfigurationPath(Path.of(""), Path.of("")), null)
builtins.rename(Builtins.Command.TTOP, "top")
// set up picocli commands
val commands = App()
val factory = PicocliCommands.PicocliCommandsFactory()
// Or, if you have your own factory, you can chain them like this:
// MyCustomFactory customFactory = createCustomFactory(); // your application custom factory
// PicocliCommandsFactory factory = new PicocliCommandsFactory(customFactory); // chain the factories
val cmd = CommandLine(commands, factory)
val picocliCommands = PicocliCommands(cmd)
val parser: Parser = DefaultParser()
TerminalBuilder.builder().build().use { terminal ->
val systemRegistry: SystemRegistry = SystemRegistryImpl(parser, terminal, workDir, null)
systemRegistry.setCommandRegistries(builtins, picocliCommands)
systemRegistry.register("help", picocliCommands)
val reader = LineReaderBuilder.builder()
.terminal(terminal)
.completer(systemRegistry.completer())
.parser(parser)
.variable(LineReader.LIST_MAX, 50) // max tab completion candidates
.build()
builtins.setLineReader(reader)
commands.setReader(reader)
factory.setTerminal(terminal)
val widgets =
TailTipWidgets(reader, systemRegistry::commandDescription, 5, TailTipWidgets.TipType.COMPLETER)
widgets.enable()
val keyMap: KeyMap<Binding> = reader.keyMaps["main"]!!
keyMap.bind(Reference("tailtip-toggle"), KeyMap.alt("s"))
val prompt = "License> "
val rightPrompt: String? = null
// start the shell and process input until the user quits with Ctrl-D
var line: String?
while (true) {
try {
systemRegistry.cleanUp()
line = reader.readLine(prompt, rightPrompt, null as MaskingCallback?, null)
systemRegistry.execute(line)
Thread.sleep(1000)
} catch (e: UserInterruptException) {
// Ignore
} catch (e: EndOfFileException) {
return
} catch (e: Exception) {
systemRegistry.trace(e)
}
}
}
} catch (t: Throwable) {
t.printStackTrace()
}
Command
@Command(name = "", version = ["v1.1.2"],
description = [
"Example interactive shell with completion and autosuggestions. " +
"Hit @|magenta <TAB>|@ to see available commands.",
"Hit @|magenta ALT-S|@ to toggle tailtips.",
""],
footer = ["", "Press Ctrl-D to exit."],
subcommands = [Generate::class, Checksum::class, Sign::class, Verify::class, PicocliCommands.ClearScreen::class, CommandLine.HelpCommand::class])
class App : Runnable {
var out: PrintWriter? = null
override fun run() {
out?.println(CommandLine(this).usageMessage);
}
fun setReader(reader: LineReader) {
out = reader.terminal.writer()
}
}
生成公私钥
@CommandLine.Command(name = "generate", version = ["v1.1.2"],
description = ["Generate Public and Private Keys"])
class Generate : Runnable {
@Option(names = ["algorithm", "-a"], defaultValue = "RSA", description = ["Algorithm with RSA DECB PKCS5Padding"])
var algorithm = "RSA"
@Option(names = ["size", "-s"], defaultValue = "2048", description = ["Size default with 2048"])
var size = 2048
@Option(names = ["public", "-p"], defaultValue = "./pub.cert", description = ["Public Key locate"])
lateinit var public: File
@Option(names = ["private", "-r"], defaultValue = "./pri.cert", description = ["Private Key locate"])
lateinit var private: File
@OptIn(ExperimentalEncodingApi::class)
override fun run() {
val generator = KeyPairGenerator.getInstance(algorithm)
generator.initialize(size)
val pair = generator.genKeyPair()
val albyte = algorithm.toByteArray(Charsets.UTF_8)
val pubBytes = pair.public.encoded
val priBytes = pair.private.encoded
FileOutputStream(public).write(Base64.encodeToByteArray(pubBytes))
FileOutputStream(private).write(Base64.encodeToByteArray(priBytes))
}
}
总结
总体来说picocli-shell-jline3项目好像还没有开发完,也好像没人维护了,启动非常繁琐,而且有bug,得自己改动,一些逻辑本身不太清楚,而且用了反射的方式调用java基础库的一些不让调用的功能,需要设置jvm启动参数避免警告,总体来说框架本身功能还是非常快速上手,文档也非常全
--illegal-access=deny --add-opens java.base/java.lang=ALL-UNNAMED
标签:交互式,val,terminal,命令行,reader,systemRegistry,class,description
From: https://www.cnblogs.com/terrency/p/17478311.html