From 25f4c1f3807e687af3bc9e9dc5ee7cf43d148b9e Mon Sep 17 00:00:00 2001 From: shaoying Date: Fri, 5 Jan 2018 00:22:50 +0800 Subject: [PATCH] =?UTF-8?q?vps=20add=20else=20=E6=B7=BB=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E8=84=9A=E6=9C=AC=E8=AF=AD=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 51 ++++++----- etc/init.sh | 33 +++---- src/context/aaa/aaa.go | 19 ++-- src/context/cli/cli.go | 191 +++++++++++++++++++++++++++-------------- src/context/ctx.go | 78 ++++++++++++----- src/context/ssh/ssh.go | 3 + 6 files changed, 244 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index 9aba2412..2bd4be33 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # context context: 通过提供自由的模块,简洁的接口,动态的结构,让编程变得更简单,让世界变得更美好。 -## 设计理念 -* 让用户轻松学会编程 -* 让系统轻松学会编程 -* 让自己轻松学会编程 +## 数据结构 +* ARM: 寻址与指令 +* Linux: 文件与进程 +* HTTP: 表示与会话 -## 设计规范 -* 协议与流程 -* 框架与接口 -* 语句与表达式 +## 开发流程 +* 设计: 协议与流程 +* 编程: 接口与框架 +* 测试: 语句与表达式 ## 接口设计CCC(command, config, cache) * 服务管理server @@ -19,27 +19,38 @@ context: 通过提供自由的模块,简洁的接口,动态的结构,让 * 配置管理config * 缓存管理cache +### Context * Cap() Conf() Cmd() * Spawn() Begin() Start() Close() +### Message * Request[] History[] Session[] * detail[] option[] result[] append[] +### Conbine * Context Master Owner * Search() Choice() Assert() Figure() -## 结构设计 -* 功能树 -* 权限树 -* 消息树 +## 模块设计 +* ctx cli aaa web +* nfs tcp mdb ssh +* lex yac log gdb -## 分支管理 -* 0.1 ctx cli aaa ssh -* 0.2 nfs tcp mdb web -* 0.3 lex yac log gdb +### Core +* ctx: 模块中心 +* cli: 管理中心 +* aaa: 认证中心 +* web: 应用中心 -## 终端管理 -* 寻址 指令 事件 函数 资源 -* 文件 进程 配置 框架 模块 -* 表示 会话 认证 搜索 交互 +### Base +* nfs: 存储中心 +* tcp: 网络中心 +* mdb: 数据中心 +* ssh: 集群中心 + +### Draw +* lex: 词法解析 +* yac: 语法解析 +* log: 日志中心 +* gdb: 调试中心 diff --git a/etc/init.sh b/etc/init.sh index 80468fcf..538fcc54 100644 --- a/etc/init.sh +++ b/etc/init.sh @@ -2,26 +2,27 @@ ~cli @lex lex ~aaa login root root -~web serve -return -~ssh dial chat.shylinux.com:9090 true -sleep 1 + ~ssh dial chat.shylinux.com:9090 true + sleep 1 ~host1 + ~aaa login root root + ~web serve ~nfs load usr/sess.txt - var a = $result - return - $a = $result - if $a != "" - remote context mpa register $a + var sessid = $result + if -n $sessid + ~host1 remote context mpa register $sessid + else + ~host1 remote context mpa register terminal shhylinux term term term 1 + let sessid $result end - if $a == "" - remote context mpa register terminal shhylinux term term term 1 - $sessid $result - remote cache sessid $sessid - ~nfs save usr/sess.txt "terminal: " $sessid - ~nfs genqr usr/sess.png "terminal: " $sessid - end + ~host1 cache sessid $sessid + ~host1 remote cache sessid $sessid + ~nfs save usr/sess.txt $sessid + ~nfs genqr usr/sess.png "terminal: " $sessid +return + + return return # ~cli # remote slaver listen ":9393" tcp diff --git a/src/context/aaa/aaa.go b/src/context/aaa/aaa.go index 26aff6c7..9aa9b684 100644 --- a/src/context/aaa/aaa.go +++ b/src/context/aaa/aaa.go @@ -128,25 +128,26 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心", username, password = arg[1], arg[2] } + msg := m if username == Pulse.Conf("rootname") { - m.Set("detail", group, username).Target().Start(m) - } else if msg := m.Find(username, false); msg == nil { + msg = Pulse.Spawn(Pulse.Target()) + msg.Set("detail", group, username).Target().Start(msg) + } else if msg = Pulse.Find(username, false); msg == nil { m.Start(username, "认证用户", group, username) + msg = m } else { m.Target(msg.Target()) } - m.Cap("password", password) - m.Source().Group, m.Source().Owner = m.Cap("group"), m.Target() - aaa.sessions[m.Cap("sessid")] = m.Target() - m.Echo(m.Cap("sessid")) + msg.Cap("password", password) + m.Source().Group, m.Source().Owner = msg.Cap("group"), msg.Target() + aaa.sessions[m.Cap("sessid")] = msg.Target() + m.Echo(msg.Cap("sessid")) } }}, }, Index: map[string]*ctx.Context{ - "void": &ctx.Context{Name: "void", - Commands: map[string]*ctx.Command{"login": &ctx.Command{}}, - }, + "void": &ctx.Context{Name: "void", Commands: map[string]*ctx.Command{"login": &ctx.Command{}}}, }, } diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index a527e1bd..c99af471 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -8,6 +8,7 @@ import ( "io" "os" "os/exec" + "regexp" "strconv" "strings" "time" @@ -51,7 +52,7 @@ func (cli *CLI) parse(m *ctx.Message) bool { if cli.which == len(cli.lines) { cli.exit = true cli.which = 0 - m.Spawn(cli.target).Set("detail", "end").Post(cli.Context) + m.Spawn(cli.Context).Set("detail", "end").Post(cli.Context) return false } line = cli.lines[cli.which] @@ -60,7 +61,7 @@ func (cli *CLI) parse(m *ctx.Message) bool { l, e := cli.bio.ReadString('\n') if e == io.EOF { cli.exit = true - m.Spawn(cli.target).Set("detail", "end").Post(cli.Context) + m.Spawn(cli.Context).Set("detail", "end").Post(cli.Context) return false } m.Assert(e) @@ -98,17 +99,28 @@ func (cli *CLI) parse(m *ctx.Message) bool { } } - if r := rune(ls[i][0]); r == '$' || r == '_' || (!unicode.IsNumber(r) && !unicode.IsLetter(r)) { - if c, ok := cli.alias[string(r)]; ok { - if i == 0 { - if msg.Add("detail", c); len(ls[i]) == 1 { - continue + if len(ls[i]) > 0 && !cli.test { + if r := rune(ls[i][0]); r == '$' || r == '_' || (!unicode.IsNumber(r) && !unicode.IsLetter(r)) { + if c, ok := cli.alias[string(r)]; ok { + if i == 0 { + if msg.Add("detail", c); len(ls[i]) == 1 { + continue + } + ls[i] = ls[i][1:] + } else if len(ls[i]) > 1 && !cli.test { + key := ls[i][1:] + switch c { + case "config", "cache": + if cli.Context.Has(key, c) { + ls[i] = m.Cap(key) + break + } + + msg := m.Spawn(cli.target) + m.Assert(msg.Exec(c, key)) + ls[i] = msg.Get("result") + } } - ls[i] = ls[i][1:] - } else if len(ls[i]) > 1 { - msg := m.Spawn(cli.target) - m.Assert(msg.Exec(c, ls[i][1:])) - ls[i] = msg.Get("result") } } } @@ -272,10 +284,9 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { } cli.Sessions["aaa"] = msg } - } else if len(arg) > 0 { + } else if len(arg) > 0 && arg[0] == "stdout" { m.Cap("stream", "stdout") m.Cap("next", "source "+m.Conf("init.sh")) - cli.Context.Master(cli.Context) cli.bio = bufio.NewReader(os.Stdin) cli.out = os.Stdout cli.Caches["level"] = &ctx.Cache{Name: "操作目标", Value: "0", Help: "操作目标"} @@ -287,9 +298,6 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { m.Cap("stream", "file") cli.bio = bufio.NewReader(stream.(io.ReadWriteCloser)) } - m.Capi("level", 1) - defer m.Capi("level", -1) - cli.test = m.Has("test") cli.save = m.Has("save") } @@ -340,7 +348,6 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { return cli.exit == false }) - m.Cap("status", "close") return !cli.save } @@ -353,7 +360,6 @@ func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { case m.Source(): if m.Name == "aaa" { msg := m.Spawn(cli.Context) - msg.Master(cli.Context) if !cli.Context.Close(msg, arg...) { return false } @@ -381,8 +387,9 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "source": &ctx.Command{Name: "source file", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { f, e := os.Open(arg[0]) // {{{ m.Assert(e) - m.Put("option", "file", f).Start(key, "脚本文件") + m.Put("option", "file", f).Start(fmt.Sprintf("%s(%d)", key, Pulse.Capi("level", 1)), "脚本文件") <-m.Target().Exit + Pulse.Capi("level", -1) // }}} }}, "return": &ctx.Command{Name: "return result...", Help: "结束脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { @@ -394,18 +401,55 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } // }}} }}, - "if": &ctx.Command{Name: "if a [ == | != ] b", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + "if": &ctx.Command{Name: "if a [ == | != ] b", Help: "条件语句", + Formats: map[string]int{"~": 0, "!~": 0, "==": 0, "!=": 0, "-z": 0, "-n": 0, "-e": 0, "-f": 0, "-d": 0}, + Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Source().Server.(*CLI) // {{{ + m.Assert(ok) + + run := false + switch { + case m.Has("-e"): + _, e := os.Stat(arg[0]) + run = e == nil + case m.Has("-f"): + info, e := os.Stat(arg[0]) + run = e == nil && !info.IsDir() + case m.Has("-d"): + info, e := os.Stat(arg[0]) + run = e == nil && info.IsDir() + + case m.Has("-z"): + run = len(arg) == 0 || len(arg[0]) == 0 + case m.Has("-n"): + run = len(arg) > 0 && len(arg[0]) > 0 + + case m.Has("=="): + run = arg[0] == arg[1] + case m.Has("!="): + run = arg[0] != arg[1] + + case m.Has("~"): + m, e := regexp.MatchString(arg[1], arg[0]) + run = m && e == nil + case m.Has("!~"): + m, e := regexp.MatchString(arg[1], arg[0]) + run = !m || e != nil + } + + if !run { + m.Add("option", "test") + } + + m.Target(m.Source()) + m.Put("option", "file", cli.bio).Start(key, "条件语句") + <-m.Target().Exit + // }}} + }}, + "else": &ctx.Command{Name: "else", Help: "条件切换", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { cli, ok := m.Source().Server.(*CLI) // {{{ m.Assert(ok) - - if arg[1] == "==" && arg[0] != arg[2] { - m.Add("option", "test") - } - if arg[1] == "!=" && arg[0] == arg[2] { - m.Add("option", "test") - } - m.Put("option", "file", cli.bio).Start(key, "条件语句") - <-m.Target().Exit + cli.test = !cli.test // }}} }}, "for": &ctx.Command{Name: "for var in list", Help: "循环语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { @@ -429,11 +473,30 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", // }}} }}, "var": &ctx.Command{Name: "var a [= b]", Help: "定义变量", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Source().Server.(*CLI) + if m.Assert(ok); cli.test { + return + } + val := "" if len(arg) > 2 { val = arg[2] } - m.Cap(arg[0], arg[0], val, "临时变量") + m.Assert(!m.Source().Has(arg[0], "cache")) + m.Spawn(m.Source()).Cap(arg[0], arg[0], val, "临时变量") + }}, + "let": &ctx.Command{Name: "let a [=] b", Help: "设置变量", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Source().Server.(*CLI) + if m.Assert(ok); cli.test { + return + } + + val := arg[1] + if len(arg) > 2 { + val = arg[2] + } + + m.Spawn(m.Source()).Cap(arg[0], val) }}, "function": &ctx.Command{Name: "function name", Help: "定义函数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { cli, ok := m.Source().Server.(*CLI) // {{{ @@ -465,39 +528,39 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } // }}} }}, - "remote": &ctx.Command{Name: "remote [send args...]|[[master|slaver] listen|dial address protocol]", Help: "建立远程连接", - Formats: map[string]int{"send": -1, "master": 0, "slaver": 0, "listen": 1, "dial": 1}, - Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - action := "dial" // {{{ - if m.Has("listen") { - action = "listen" - } - - msg := m.Find(m.Get("args"), true) - - if m.Has("master") { - msg.Template = msg.Spawn(msg.Source()).Add("option", "master") - } - msg.Cmd(action, m.Get(action)) - - }}, // }}} - "open": &ctx.Command{Name: "open [master|slaver] [script [log]]", Help: "建立远程连接", - Options: map[string]string{"master": "主控终端", "slaver": "被控终端", "args": "启动参数", "io": "读写流"}, - Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - m.Start(fmt.Sprintf("PTS%d", m.Capi("nterm")), "管理终端", "void.sh") // {{{ - // }}} - }}, - "master": &ctx.Command{Name: "open [master|slaver] [script [log]]", Help: "建立远程连接", - Options: map[string]string{"master": "主控终端", "slaver": "被控终端", "args": "启动参数", "io": "读写流"}, - Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - _, ok := c.Server.(*CLI) // {{{ - m.Assert(ok, "模块类型错误") - m.Assert(m.Target() != c, "模块是主控模块") - - msg := m.Spawn(c) - msg.Start(fmt.Sprintf("PTS%d", Pulse.Capi("nterm")), arg[0], arg[1:]...) - // }}} - }}, + // "remote": &ctx.Command{Name: "remote [send args...]|[[master|slaver] listen|dial address protocol]", Help: "建立远程连接", + // Formats: map[string]int{"send": -1, "master": 0, "slaver": 0, "listen": 1, "dial": 1}, + // Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + // action := "dial" // {{{ + // if m.Has("listen") { + // action = "listen" + // } + // + // msg := m.Find(m.Get("args"), true) + // + // if m.Has("master") { + // msg.Template = msg.Spawn(msg.Source()).Add("option", "master") + // } + // msg.Cmd(action, m.Get(action)) + // + // }}, // }}} + // "open": &ctx.Command{Name: "open [master|slaver] [script [log]]", Help: "建立远程连接", + // Options: map[string]string{"master": "主控终端", "slaver": "被控终端", "args": "启动参数", "io": "读写流"}, + // Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + // m.Start(fmt.Sprintf("PTS%d", m.Capi("nterm")), "管理终端", "void.sh") // {{{ + // // }}} + // }}, + // "master": &ctx.Command{Name: "open [master|slaver] [script [log]]", Help: "建立远程连接", + // Options: map[string]string{"master": "主控终端", "slaver": "被控终端", "args": "启动参数", "io": "读写流"}, + // Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + // _, ok := c.Server.(*CLI) // {{{ + // m.Assert(ok, "模块类型错误") + // m.Assert(m.Target() != c, "模块是主控模块") + // + // msg := m.Spawn(c) + // msg.Start(fmt.Sprintf("PTS%d", Pulse.Capi("nterm")), arg[0], arg[1:]...) + // // }}} + // }}, }, Index: map[string]*ctx.Context{ "void": &ctx.Context{Name: "void", diff --git a/src/context/ctx.go b/src/context/ctx.go index 01d28231..afe7334b 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -149,6 +149,7 @@ func (c *Context) Begin(m *Message) *Context { // {{{ // }}} func (c *Context) Start(m *Message) bool { // {{{ + if m != c.Requests[0] { c.Requests, m.Index = append(c.Requests, m), len(c.Requests)+1 } @@ -169,7 +170,7 @@ func (c *Context) Start(m *Message) bool { // {{{ // }}} func (c *Context) Close(m *Message, arg ...string) bool { // {{{ - m.Log("close", c, "%v", arg) + m.Log("close", c, "%d:%d %v", len(m.source.Sessions), len(m.target.Historys), arg) if m.target == c { if m.Index == 0 { @@ -240,12 +241,25 @@ func (c *Context) Master(s ...*Context) *Context { // {{{ } // }}} -func (c *Context) Has(key string) bool { // {{{ - if _, ok := c.Caches[key]; ok { - return true - } - if _, ok := c.Configs[key]; ok { - return true +func (c *Context) Has(key ...string) bool { // {{{ + switch len(key) { + case 1: + if _, ok := c.Caches[key[0]]; ok { + return true + } + if _, ok := c.Configs[key[0]]; ok { + return true + } + case 2: + if _, ok := c.Caches[key[0]]; ok && key[1] == "cache" { + return true + } + if _, ok := c.Configs[key[0]]; ok && key[1] == "config" { + return true + } + if _, ok := c.Commands[key[0]]; ok && key[1] == "command" { + return true + } } return false } @@ -494,8 +508,7 @@ func (m *Message) Log(action string, ctx *Context, str string, arg ...interface{ } info := fmt.Sprintf("%s", ctx.Name) - // name := fmt.Sprintf("%s->%s", m.source.Name, m.target.Name) - name := fmt.Sprintf("%s:%s->%s.%d", m.source.Name, m.Name, m.target.Name, m.Index) + name := fmt.Sprintf("%s->%s", m.source.Name, m.target.Name) if m.Name != "" { name = fmt.Sprintf("%s:%s->%s.%d", m.source.Name, m.Name, m.target.Name, m.Index) } @@ -912,7 +925,7 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{ m.master = m.source if x, ok := s.Commands[key]; ok && x.Hand != nil && m.Check(c, "commands", key) { m.AssertOne(m, true, func(m *Message) { - m.Log("cmd", s, "%s %v %v", key, arg, m.Meta["option"]) + m.Log("cmd", s, "%d %s %v %v", len(m.target.Historys), key, arg, m.Meta["option"]) if x.Options != nil { for _, v := range m.Meta["option"] { @@ -922,6 +935,9 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{ } } + if m.Has("args") { + m.Meta["args"] = nil + } if x.Formats != nil { for i := 0; i < len(arg); i++ { n, ok := x.Formats[arg[i]] @@ -955,10 +971,10 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{ } } - if c.Historys == nil { - c.Historys = make([]*Message, 0, 10) + if m.target.Historys == nil { + m.target.Historys = make([]*Message, 0, 10) } - c.Historys = append(c.Historys, m) + m.target.Historys = append(m.target.Historys, m) }) return m.Get("result") @@ -1082,7 +1098,7 @@ func (m *Message) Conf(key string, arg ...string) string { // {{{ return m.Conf(key, arg[1]) } - m.Log("error", nil, "配置项不存在") + m.Log("error", nil, "%s 配置项不存在", key) return "" } @@ -1120,8 +1136,10 @@ func (m *Message) Cap(key string, arg ...string) string { // {{{ } else { x.Value = arg[0] } + m.Log("debug", s, "%s %s", x.Name, x.Value) return x.Value case 0: + m.Log("debug", s, "%s %s", x.Name, x.Value) if x.Hand != nil { return x.Hand(m, x) } @@ -1141,7 +1159,7 @@ func (m *Message) Cap(key string, arg ...string) string { // {{{ return m.Cap(key, arg[1]) } - m.Log("error", nil, "缓存项不存在") + m.Log("error", nil, "%s 缓存项不存在", key) return "" } @@ -1328,10 +1346,14 @@ var Index = &Context{Name: "ctx", Help: "模块中心", // }}} }}, - "context": &Command{Name: "context [home] [[find|search] name] [info|list|show|spawn|start|switch|close][args]", Help: "查找并操作模块,\n查找起点root:根模块、back:父模块、home:本模块,\n查找方法find:路径匹配、search:模糊匹配,\n查找对象name:支持点分和正则,\n操作类型show:显示信息、switch:切换为当前、start:启动模块、spawn:分裂子模块,args:启动参数", + "context": &Command{Name: "context back|[[home] [find|search] name] [info|list|show|spawn|start|switch|close][args]", Help: "查找并操作模块,\n查找起点root:根模块、back:父模块、home:本模块,\n查找方法find:路径匹配、search:模糊匹配,\n查找对象name:支持点分和正则,\n操作类型show:显示信息、switch:切换为当前、start:启动模块、spawn:分裂子模块,args:启动参数", Formats: map[string]int{"back": 0, "home": 0, "find": 1, "search": 1, "info": 1, "list": 0, "show": 0, "close": 0, "switch": 0, "start": 0, "spawn": 0}, Hand: func(m *Message, c *Context, key string, arg ...string) { - root := !m.Has("home") // {{{ + if m.Has("back") { // {{{ + m.target = m.source + return + } + root := !m.Has("home") ms := []*Message{} switch { @@ -1355,10 +1377,10 @@ var Index = &Context{Name: "ctx", Help: "模块中心", } for _, v := range ms { - v.Meta = m.Meta - v.Data = m.Data + // v.Meta = m.Meta + // v.Data = m.Data switch { - case m.Has("switch"): + case m.Has("switch"), m.Has("back"): m.target = v.target case m.Has("spawn"): v.Set("detail", arg[2:]...).target.Spawn(v, arg[0], arg[1]).Begin(v) @@ -1428,9 +1450,9 @@ var Index = &Context{Name: "ctx", Help: "模块中心", return true }) case len(arg) > 0 && v != m: + v.Meta = m.Meta v.Cmd(arg...) - // m.Meta = v.Meta - // m.target = target + m.Meta = v.Meta default: m.target = v.target } @@ -1610,12 +1632,24 @@ var Index = &Context{Name: "ctx", Help: "模块中心", m.Cap(arg[0], "") } + if m.source == m.source.master { + m.source, m.target = m.target, m.source + } m.Echo("%s", m.Cap(arg[0])) case 2: + if m.source == m.source.master { + m.source, m.target = m.target, m.source + } m.Cap(arg[0], arg[1]) case 3: + if m.source == m.source.master { + m.source, m.target = m.target, m.source + } m.Cap(arg[0], arg[2]) case 4: + if m.source == m.source.master { + m.source, m.target = m.target, m.source + } m.Cap(arg[0], arg[1:]...) } // }}} diff --git a/src/context/ssh/ssh.go b/src/context/ssh/ssh.go index 65c9a121..d2690d35 100644 --- a/src/context/ssh/ssh.go +++ b/src/context/ssh/ssh.go @@ -133,6 +133,9 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心", fmt.Fprintf(ssh.Writer, "detail: %v\n", v) } for _, k := range m.Meta["option"] { + if k == "args" { + continue + } for _, v := range m.Meta[k] { fmt.Fprintf(ssh.Writer, "%s: %s\n", k, v) }