模仿、改写程序包
设计思路
myCobra用于处理简单的子命令系统(简单的,不能带很多参数的)。其中有一个命令树,每个节点的子节点就是子命令,每个节点存储自己的命令。
type Command struct设计:
type Command struct{
cmds string;
father *Command;
sons [](*Command);
}
就是一棵树。
AddCommand函数:
func (c Command) AddCommand(newCom *Command){
if (len(newCom.sons)!=0 || (newCom.father)!=nil){
fmt.Printf("AddCommand Error\n");
return;
}
newCom.father=&c;
c.sons=append(c.sons,newCom)
}
在当前的叶子节点加入子命令,子命令是一个新节点。由于sons是用切片定义的,只用append函数就能插入。
CommandPath函数
func (C Command) CommandPath() string{
if (C.father==nil){
ret:="No Command : "+C.cmds;
return ret;
}
var now Command;
var path []string;
now=C;
path=append(path,now.cmds);
for ;(now.father)!=&root;{
if (now.father==nil){
ret:="No Command : "+now.cmds;
return ret;
}
now=*now.father;
path=append(path,now.cmds);
}
ret:="";
for i:=len(path)-1;i>=0;i=i-1{
ret=ret+path[i];
if i!=0{
ret=ret+" -> "
}
}
return ret;
}
返回当前节点的命令路径,路径通常用Root -> cmd1 -->cmd2 -->… -> current cmd 的形式列出。查找原理就是不断地访问父命令,迭代,直到访问到根,根的father就是自己。并且将一路上路过的节点的命令记录下来,再倒叙输出。
ExcuteC函数
func (c Command) ExcuteC(){
cmd := exec.Command(c.cmds)
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(err)
}
fmt.Println(string(out))
}
执行当前命令。
exec.Command会在Path系统变量中寻找指定的二进制文件,并且执行,这里将输出指向了cmd.CombineOutput,然后再一起输出它,这样我们就能看到输出了。
NewCommand函数
func NewCommand(cmds string) Command{
var ret Command;
ret.cmds=cmds;
return ret;
}
创建一个新的command,可以添加在树中
此外还有:
Init函数:初始化一个树,在每次调用mycobra函数前需要先使用。
GetRoot函数:获得这棵树的根节点。
测试函数
mycobra_test可以这样写:
package mycobra;
import (
"testing"
)
func TestInit(t *testing.T){
Init();
var c1=NewCommand("hello");
mroot:=GetRoot();
mroot.AddCommand(&c1);
if (c1.CommandPath()!="Root -> hello"){
t.Errorf("%s\n",c1.CommandPath());
}
var c2=NewCommand("hello2");
c1.AddCommand(&c2);
if (c2.CommandPath()!="Root -> hello -> hello2"){
t.Errorf("%s\n",c2.CommandPath());
}
var c3=NewCommand("hello3");
mroot.AddCommand(&c3);
if (c3.CommandPath()!="Root -> hello3"){
t.Errorf("%s\n",c3.CommandPath());
}
c1.ExcuteC();
c2.ExcuteC();
c3.ExcuteC();
}
创建了一个有四个节点的树,root,c1,c2,c3,对应不同的helloworld输出。
将c1,c2,c3三个命令Command加入到树中的不同位置,并且判断它们的CommandPath是否等于预期的值。
结果:
使用一下
在main函数中这样写(和test函数中的案例一样)
package main
import (
"mycobra"
"fmt"
//"os/exec"
//"os"
)
func main(){
mycobra.Init();
var c1=mycobra.NewCommand("hello");
var root=mycobra.GetRoot();
root.AddCommand(&c1);
fmt.Printf("%s\n",c1.CommandPath());
var c2=mycobra.NewCommand("hello2");
c1.AddCommand(&c2);
fmt.Printf("%s\n",c2.CommandPath());
var c3=mycobra.NewCommand("hello3");
root.AddCommand(&c3);
fmt.Printf("%s\n",c3.CommandPath());
c1.ExcuteC();
c2.ExcuteC();
c3.ExcuteC();
}
运行结果:
完全符合预期,路径是对的,输出也是对的。