跳转到内容

基于TrantorCli开发本地命令

TrantorCli支持第三方命令的接入,下边介绍如何基于TrantorCli开发本地命令。

本教程提供demo可以一起使用,下文所涉及源码都在demo内。

demo下载地址:https://erda.cloud/terminus/dop/T-Project/trantor-cli-plugin-demo

sdk

提供trantor-cli-client-sdk用于本地的开发

<dependency>
<groupId>io.terminus.trantor</groupId>
<artifactId>trantor-cli-client-sdk</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>

定义命令

TrantorCommand的抽象

image-20211105150134436

定义一个Trantor命令必须要继承自 AbstractTrantorCommand 。

添加类注解

AnnotationDescriptionRequiredProperty
@Name定义命令的名称。truevalue
@Summary对当前命令做一个简短的说明,可以展示在使用帮助中。falsevalue
@Description加长版说明,可以写该命令的使用示例,也可以展示在使用帮助中。falsevalue

添加方法注解

AnnotationDescriptionRequiredProperty
@Argument添加在成员变量的set方法上,用于参数的描述。true
@Option添加在成员变量的set方法上,用于选项的描述true

定义一个基础命令

基础命令继承 AbstractTrantorSimpleCommand 抽象类。

该类命令是最基础的命令执行逻辑。

示例:

@Name("basic")
@Summary("this is a basic command")
@Description("EXAMPLES:\n" +
"trantor basic [arg]" +
"trantor basic -s true hhh")
public class BasicCommand extends AbstractTrantorSimpleCommand {
/**
* 命令选项
*/
private Boolean status;
/**
* 命令参数
*/
private String arg;
/**
* 定义该变量接收命令中的--status / -s选项对应的值
* 更多属性建议查看Option源码
*/
@Option(shortName = "s", longName = "status")
@DefaultValue("true")
@Description("default type is true")
public void setStatus(Boolean status) {
this.status = status;
}
/**
* 定义该变量接收命令中的第一个参数
* argName 定义变量名称
* index 定义该变量在命令中参数的下标
* 更多属性建议查看Argument源码
*/
@Argument(argName = "arg", index = 0)
@Description("arg for basic command")
public void setArg(String arg) {
this.arg = arg;
}
/**
* 返回当前命令的版本 自定义
*
* @return 当前命令的版本
*/
@Override
public String getVersion() {
return TrantorCliVersion.VERSION;
}
/**
* 获取当前命令的父命令 当没有父命令时允许返回null
*
* @return 父命令名
*/
@Override
public Class<? extends TrantorCommand> getParent() {
return null;
}
/**
* 命令的逻辑部分
*
* @return 命令的执行状态
*/
@Override
public int process() throws Throwable {
AnsiLog.info("这是一个基础命令,参数为{},选项为{}", arg, status);
if (status) {
AnsiLog.info("666");
}
return TerminalStatus.EXIT_NORMALITY;
}
}

图例:

image-20211103174347570

定义一个复杂命令

复杂命令需要继承 AbstractTrantorComplexCommand 抽象类。

该类命令主要应用场景在多级命令,生命周期与简单命令一致,process() 方法执行完即结束。

逻辑上来说存在子命令的父命令只会存在选项,所以该抽象类的实现类不可以再有 Argument (命令参数) 的元信息描述。

一般场景下只会有二级命令,所以该抽象类默认实现了TrantorCommand接口的getParent() 方法并返回 null 表示没有父级命令。

如遇特殊情况,需要用到三级命令,请重写 TrantorCommand的getParent() 方法,返回值为二级命令的类信息。

示例:

ParentCommand命令为父级命令,由于有子命令,所以find命令需要继承自AbstractTrantorComplexCommand抽象类,可以拿到子命令以及子命令下的参数。实际最终命令的执行逻辑应该定义在SonCommandprocess() 方法中。

@Name("parent")
@Summary("this is a complex command,it have a secondary command")
public class ParentCommand extends AbstractTrantorComplexCommand {
/**
* 没有子命令输入时执行该方法
*
* @return
* @throws Throwable
*/
@Override
protected int execute() throws Throwable {
AnsiLog.info(this.usage());
return TerminalStatus.EXIT_NORMALITY;
}
/**
* 返回当前命令的版本 自定义
*
* @return 当前命令的版本
*/
@Override
public String getVersion() {
return TrantorCliVersion.VERSION;
}
/**
* 当需要个性化使用帮助时可重写该方法
*
* @return 使用帮助内容
*/
@Override
public String usage() {
StringBuilder usageStringBuilder = new StringBuilder();
UsageMessageFormatter usageMessageFormatter = new UsageMessageFormatter();
usageMessageFormatter.setOptionComparator(null);
this.getCli().usage(usageStringBuilder, usageMessageFormatter);
return usageStringBuilder.toString();
}
}

子命令SonCommand继承 AbstractTrantorSimpleCommand 抽象类,定义参数/选项,重写方法。

@Name("son")
@Summary("this is a secondary command")
@Description("EXAMPLES:\n" +
"trantor parent son")
public class SonCommand extends AbstractTrantorSimpleCommand {
private String arg;
@Argument(argName = "arg", index = 0)
@Description("arg for son command")
public void setArg(String arg) {
this.arg = arg;
}
@Override
public String getVersion() {
return TrantorCliVersion.VERSION;
}
@Override
public Class<? extends TrantorCommand> getParent() {
return ParentCommand.class;
}
@Override
public int process() throws Throwable {
AnsiLog.info("这里是一个子命令 参数是{}", arg);
if (!"hahaha".equals(arg)) {
throw new TrantorCommandProcessException(TerminalStatus.EXIT_ABNORMALLY, "参数不匹配");
}
return TerminalStatus.EXIT_NORMALITY;
}
}

图例:

image-20211104100751293

定义一个会话级别的命令

会话级别的交互式命令需要继承AbstractTrantorSessionCommand抽象类。

该类命令主要用于多次交互的场景 例如 连接服务端进行远程命令操作,或者部署、数据迁移等需要多次交互的场景。 生命周期为进入会话,直到用户通过 exit 命令/CTRL+ D快捷键 主动退出。 该抽象类默认实现了TrantorCommand 的 getParent() 方法并返回 null 表示没有父级命令。

当我们需要定义一个会话级别的命令时可以继承AbstractTrantorLocalSessionCommand抽象类,该类是AbstractTrantorSessionCommand的进一步抽象,实现了process方法,可以帮助我们路由到会话中的命令。

示例:

实现一个会话级别命令

@Name("room")
@Summary("this is a session command")
@Description("EXAMPLES:\n" +
"trantor room")
public class RoomCommand extends AbstractTrantorLocalSessionCommand {
/**
* 开始会话模式命令前的处理逻辑
* <p>
* 返回的Map中,如果有ServiceName的key存在,value会成为命令行的Prompt
*
* @return 可以展示给用户的信息 Map k->label; v->value;
*/
@Override
protected TrantorSessionCommandPrepareInformation prepareHook() throws Throwable {
TrantorSessionCommandPrepareInformation information = new TrantorSessionCommandPrepareInformation();
//定义命令行提示符
information.setPrompt("trantor-cli-test");
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("hello","这是一个会话级别的命令");
//定义进入会话后的展示信息
information.setDisplayMessage(map);
return information;
}
/**
* 结束会话模式命令后的处理逻辑
*/
@Override
protected void quitHook() throws Throwable {
AnsiLog.info("会话结束啦");
}
@Override
public String getVersion() {
return TrantorCliVersion.VERSION;
}
}

实现一个会话中的命令

@Name("chart")
@Summary("this is a session command")
@Description("EXAMPLES:\n" +
"chart [arg]"
)
public class ChartCommand extends AbstractTrantorSimpleCommand {
/**
* 命令参数
*/
private String arg;
/**
* 定义该变量接收命令中的第一个参数
* argName 定义变量名称
* index 定义该变量在命令中参数的下标
* 更多属性建议查看Argument源码
*/
@Argument(argName = "arg", index = 0)
@Description("arg for basic command")
public void setArg(String arg) {
this.arg = arg;
}
@Override
public String getVersion() {
return TrantorCliVersion.VERSION;
}
@Override
public Class<? extends TrantorCommand> getParent() {
return RoomCommand.class;
}
@Override
public int process() throws Throwable {
if ("hello".equals(arg)){
AnsiLog.info("hi");
}else{
AnsiLog.info("你好");
}
return TerminalStatus.EXIT_NORMALITY;
}
}

图例:

image-20211104150830642

命令的返回状态 (TerminalStatus)

KeyDescriptionValue
EXIT_NORMALITY命令执行完成,正常退出0
EXIT_ABNORMALLY命令执行失败,异常退出1
EXIT_PARSE_EXCEPTION命令数据解析失败,异常退出2
EXIT_COMMAND_NOT_EXECUTABLE命令不可执行126
EXIT_COMMAND_NOT_FOUND没找到命令127

命令行日志工具 (AnsiLog)

MethodDescription
level设置日志级别
system设置日志级别 (ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF)
trace打印trace级别日志
debug打印debug级别日志
info打印info级别日志
warn打印warn级别日志
error打印error级别日志

部署

trantor-cli-plugin-client-demo工程下执行mvn命令打成.jar包。

Terminal window
mvn clean package

打好的jar包放在 ../trantor-cli/lib/ext 目录下。

image-20211130142027241

执行安装命令后即可使用。

Terminal window
trantor install [jarPath]

jarPath 参数表示需要安装的jar包路径。

图例:

image-20211130141909540

单测

Trantor Cli提供了单测工具类TrantorBasicCommandTest,引入依赖后即可使用。

<dependency>
<groupId>io.terminus.trantor</groupId>
<artifactId>trantor-cli-test</artifactId>
<version>1.0.0.RELEASE</version>
<scope>test</scope>
</dependency>

示例:

public class CommandTest extends TrantorBasicCommandTest {
@Test
public void testBasicCommand() throws Throwable {
String inputCommand ="test";
int status = runCommand(inputCommand, BasicCommand.class);
Assert.assertEquals(TerminalStatus.EXIT_NORMALITY, status);
}
}