diff --git a/etc/cert.pem b/etc/cert.pem new file mode 100644 index 00000000..98139d4c --- /dev/null +++ b/etc/cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC9TCCAl4CCQCHSqshz+HyLTANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +R0IxHzAdBgNVBAgTFlRlc3QgU3RhdGUgb3IgUHJvdmluY2UxFjAUBgNVBAcTDVRl +c3QgTG9jYWxpdHkxGjAYBgNVBAoTEU9yZ2FuaXphdGlvbiBOYW1lMSEwHwYDVQQL +ExhPcmdhbml6YXRpb25hbCBVbml0IE5hbWUxFDASBgNVBAMTC0NvbW1vbiBOYW1l +MSEwHwYJKoZIhvcNAQkBFhJ0ZXN0QGVtYWlsLmFkZHJlc3MwHhcNMTcxMDMxMTYw +NDM5WhcNMTcxMTMwMTYwNDM5WjCBvjELMAkGA1UEBhMCR0IxHzAdBgNVBAgTFlRl +c3QgU3RhdGUgb3IgUHJvdmluY2UxFjAUBgNVBAcTDVRlc3QgTG9jYWxpdHkxGjAY +BgNVBAoTEU9yZ2FuaXphdGlvbiBOYW1lMSEwHwYDVQQLExhPcmdhbml6YXRpb25h +bCBVbml0IE5hbWUxFDASBgNVBAMTC0NvbW1vbiBOYW1lMSEwHwYJKoZIhvcNAQkB +FhJ0ZXN0QGVtYWlsLmFkZHJlc3MwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB +AOw3gvdtfKWkSEl2l30V7irBhkrD6IVd6AzxaAYL97giDglPvu7ng2PXYlF5pjjf +mxDYtjAGuq1itnN0LKRe6CjUOuGtC2KMlZ8121fQCNw8M6TLPSpDjVuzysaUb2ds ++OClb0uC8SmSy3bOCGsicI77yXvEuKFkm43ikyVounmRAgMBAAEwDQYJKoZIhvcN +AQELBQADgYEAkOk7DVR/XgJdMSXXGd/OtWmTfVp2sIyyy37zSoc4uRFWwPqbzLPf +NgUKGNHEYvJY7/bWQ3p2D+u1U2PUfv/t6SQcAu3Nkw7sd7PoeeDZcRau84NevgoR +HfQKirJQgZd0hKFwiBnDspYbi8IL2mHEJOlzw1priY9v8MVIscyFVbE= +-----END CERTIFICATE----- diff --git a/etc/init.sh b/etc/init.shy similarity index 100% rename from etc/init.sh rename to etc/init.shy diff --git a/etc/key.pem b/etc/key.pem new file mode 100644 index 00000000..ae38b53e --- /dev/null +++ b/etc/key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXwIBAAKBgQDsN4L3bXylpEhJdpd9Fe4qwYZKw+iFXegM8WgGC/e4Ig4JT77u +54Nj12JReaY435sQ2LYwBrqtYrZzdCykXugo1DrhrQtijJWfNdtX0AjcPDOkyz0q +Q41bs8rGlG9nbPjgpW9LgvEpkst2zghrInCO+8l7xLihZJuN4pMlaLp5kQIDAQAB +AoGBAOasYwG68pFTN6A95jupsdYg/EKAw82RYa1aBUp6X2N6JhjjvkHQ5ZcXWxTT +ZgZ+HhC6gFewCpaNIjzmwz2UzMJJ4empijEbJFuwZCq4M/Adca2BhduV2YIwqvi8 +MHGmHMB81zYKA0E4j+vahJnn8aAqSoPnaM9MBw5vhggU5YodAkEA/IwRTVNOHmIm +1XCfvPoSpDBpSJh6V1mPyBuPs/2Fr52j+L+6qOhNML0O063az44/dR8RZytcaGYQ +7EByYbeCZwJBAO9ySW4TbDLRejSmFWHmflrnjV7s4DqE6OBbCRJF3aIleELYaTPC +Q0kOKRZTCr1PwopIdAOOOgaSWgsX75zU2UcCQQDMCwb3qLTXC4pArMwCzTE+gvat +drRx2qS2kr4aOF1ItF8E3TOcwIONO1K9aBv/0fgnUsCm0HvKxZwqpS9FEBVFAkEA +ntgeRlu0J3I3s72J6cxSflOlwRc7GRcatdsuhWS7xtk8knumLqPspwYx05F7SmMj +F0FBVSqA6+MiwME8P7oj+QJBAJFv2HKAaGElXkaJJzmQPHGJdGLUMb9oHXPtzcpz +HLtT2kHK1LlQqsOEacivPCKtnnLkX6Xsl8pMpe8EV43t718= +-----END RSA PRIVATE KEY----- diff --git a/etc/shy.vim b/etc/shy.vim new file mode 100644 index 00000000..fa38d1fc --- /dev/null +++ b/etc/shy.vim @@ -0,0 +1,85 @@ +syn keyword shStatement break cd chdir continue eval exec exit kill newgrp pwd read readonly return shift test trap ulimit umask wait + +syn keyword shStatement source return function +syn keyword shStatement if else elif end for +syn keyword shStatement let var + +syn match shOperator "\~[-_a-zA-Z0-9]\+\>" +syn match shShellVariables "\$[-_a-zA-Z0-9]\+\>" +syn match shShellVariables "@[-_a-zA-Z0-9]\+\>" + +hi def link shArithRegion shShellVariables +hi def link shBeginHere shRedir +hi def link shCaseBar shConditional +hi def link shCaseCommandSub shCommandSub +hi def link shCaseDoubleQuote shDoubleQuote +hi def link shCaseIn shConditional +hi def link shQuote shOperator +hi def link shCaseSingleQuote shSingleQuote +hi def link shCaseStart shConditional +hi def link shCmdSubRegion shShellVariables +hi def link shColon shComment +hi def link shDerefOp shOperator +hi def link shDerefPOL shDerefOp +hi def link shDerefPPS shDerefOp +hi def link shDeref shShellVariables +hi def link shDerefDelim shOperator +hi def link shDerefSimple shDeref +hi def link shDerefSpecial shDeref +hi def link shDerefString shDoubleQuote +hi def link shDerefVar shDeref +hi def link shDoubleQuote shString +hi def link shEcho shString +hi def link shEchoDelim shOperator +hi def link shEchoQuote shString +hi def link shEmbeddedEcho shString +hi def link shEscape shCommandSub +hi def link shExDoubleQuote shDoubleQuote +hi def link shExSingleQuote shSingleQuote +hi def link shFunction Function +hi def link shHereDoc shString +hi def link shHerePayload shHereDoc +hi def link shLoop shStatement +hi def link shMoreSpecial shSpecial +hi def link shOption shCommandSub +hi def link shPattern shString +hi def link shParen shArithmetic +hi def link shPosnParm shShellVariables +hi def link shQuickComment shComment +hi def link shRange shOperator +hi def link shRedir shOperator +hi def link shSetListDelim shOperator +hi def link shSetOption shOption +hi def link shSingleQuote shString +hi def link shSource shOperator +hi def link shStringSpecial shSpecial +hi def link shSubShRegion shOperator +hi def link shTestOpr shConditional +hi def link shTestPattern shString +hi def link shTestDoubleQuote shString +hi def link shTestSingleQuote shString +hi def link shVariable shSetList +hi def link shWrapLineOperator shOperator + +hi def link shArithmetic Special +hi def link shCharClass Identifier +hi def link shSnglCase Statement +hi def link shCommandSub Special +hi def link shComment Comment +hi def link shConditional Conditional +hi def link shCtrlSeq Special +hi def link shExprRegion Delimiter +hi def link shFunctionKey Function +hi def link shFunctionName Function +hi def link shNumber Number +hi def link shOperator Operator +hi def link shRepeat Repeat +hi def link shSet Statement +hi def link shSetList Identifier +hi def link shShellVariables PreProc +hi def link shSpecial Special +hi def link shStatement Statement +hi def link shString String +hi def link shTodo Todo +hi def link shAlias Identifier + diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index c99af471..d718f123 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -1,40 +1,38 @@ -package cli - -import ( +package cli // {{{ +// }}} +import ( // {{{ "context" "bufio" - "fmt" "io" - "os" - "os/exec" - "regexp" + + "fmt" "strconv" "strings" - "time" "unicode" + + "os" + "os/exec" + "time" + + "regexp" ) +// }}} + type CLI struct { - bio *bufio.Reader - out io.WriteCloser - - which int + bio *bufio.Reader + out io.WriteCloser lines []string + pos int - alias map[string]string - lex *ctx.Message - + lex *ctx.Message + alias map[string][]string target *ctx.Context - wait *ctx.Context - exit bool - test bool - save bool - *ctx.Context } -func (cli *CLI) echo(str string, arg ...interface{}) bool { +func (cli *CLI) print(str string, arg ...interface{}) bool { // {{{ if cli.out != nil { fmt.Fprintf(cli.out, str, arg...) return true @@ -42,127 +40,267 @@ func (cli *CLI) echo(str string, arg ...interface{}) bool { return false } -func (cli *CLI) parse(m *ctx.Message) bool { +// }}} +func (cli *CLI) parse(m *ctx.Message) (cmd []string) { // {{{ + line := m.Cap("next") - if line == "" { - if m.Cap("level") == "0" { - cli.echo(m.Conf("PS1")) - } + if m.Cap("next", ""); line == "" { + if cli.bio == nil { - if cli.which == len(cli.lines) { - cli.exit = true - cli.which = 0 - m.Spawn(cli.Context).Set("detail", "end").Post(cli.Context) - return false - } - line = cli.lines[cli.which] - cli.which++ + line = cli.lines[cli.pos] + cli.pos++ } else { + cli.print(m.Conf("PS1")) l, e := cli.bio.ReadString('\n') - if e == io.EOF { - cli.exit = true - m.Spawn(cli.Context).Set("detail", "end").Post(cli.Context) - return false - } m.Assert(e) line = l } } - m.Cap("next", "") - if line = strings.TrimSpace(line); len(line) == 0 && m.Cap("stream") == "stdout" { + if line = strings.TrimSpace(line); len(line) == 0 && cli.out != nil { line = m.Cap("back") m.Cap("back", "") } if len(line) == 0 || line[0] == '#' { - return true + return nil } ls := []string{} if cli.lex == nil { ls = strings.Split(line, " ") - } else { - lex := m.Spawn(cli.lex.Target()) - m.Assert(lex.Cmd("split", line, "void")) - ls = lex.Meta["result"] - } - - msg := m.Spawn(cli.target) - - for i := 0; i < len(ls); i++ { - if cli.lex == nil { + cs := []string{} + for i := 0; i < len(ls); i++ { if ls[i] = strings.TrimSpace(ls[i]); ls[i] == "" { continue } if ls[i][0] == '#' { break } + cs = append(cs, ls[i]) } - - 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") - } - } - } - } - } - - msg.Add("detail", ls[i]) + ls = cs + } else { + lex := m.Spawn(cli.lex.Target()) + m.Assert(lex.Cmd("split", line, "void")) + ls = lex.Meta["result"] } - msg.Wait = make(chan bool) - msg.Post(cli.Context) - - if msg.Target().Context() != nil || msg.Target() == ctx.Index { - cli.target = msg.Target() - } - m.Cap("target", cli.target.Name) - - result := strings.TrimRight(strings.Join(msg.Meta["result"], ""), "\n") - if m.Cap("result", result); len(result) > 0 { - cli.echo(result + "\n") + if !cli.Has("skip") || !cli.Pulse.Caps("skip") { + ls = cli.expand(ls) } if m.Cap("back", line); cli.bio != nil { cli.lines = append(cli.lines, line) + m.Capi("nline", 1) } - return !cli.exit + + return ls } -func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { +// }}} +func (cli *CLI) expand(ls []string) []string { // {{{ + + cs := []string{} + for i := 0; i < len(ls); i++ { + if len(ls[i]) > 0 { + 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 { + ns := []string{} + ns = append(ns, c...) + if ls[0] = ls[i][1:]; len(ls[0]) > 0 { + ns = append(ns, ls...) + } else { + ns = append(ns, ls[1:]...) + } + ls = ns + } else if len(ls[i]) > 1 { + key := ls[i][1:] + + if r == rune(key[0]) { + ls[i] = key + } else { + if cli.Context.Has(key, c[0]) { + switch c[0] { + case "config": + ls[i] = cli.Pulse.Conf(key) + case "cache": + ls[i] = cli.Pulse.Cap(key) + } + } else { + msg := cli.Pulse.Spawn(cli.target) + if msg.Exec(c[0], key) != "error: " { + ls[i] = msg.Get("result") + } + } + } + } + } + } + + if c, ok := cli.alias[ls[i]]; ok && i == 0 { + ns := []string{} + ns = append(ns, c...) + ns = append(ns, ls[1:]...) + } + } + + cs = append(cs, ls[i]) + } + + return cs +} + +// }}} +func (cli *CLI) express(arg []string) string { // {{{ + + result := "false" + + switch len(arg) { + case 0: + result = "" + case 1: + result = arg[0] + case 2: + switch arg[0] { + case "-z": + if arg[1] == "" { + result = "true" + } + case "-n": + result = arg[1] + + case "-e": + if _, e := os.Stat(arg[1]); e == nil { + result = "true" + } + case "-f": + if info, e := os.Stat(arg[1]); e == nil && !info.IsDir() { + result = "true" + } + case "-d": + if info, e := os.Stat(arg[1]); e == nil && info.IsDir() { + result = "true" + } + } + case 3: + v1, e1 := strconv.Atoi(arg[0]) + v2, e2 := strconv.Atoi(arg[2]) + switch arg[1] { + case "+": + result = arg[0] + arg[2] + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%d", v1+v2) + } + case "-": + result = arg[0] + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%d", v1-v2) + } + case "*": + result = arg[0] + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%d", v1*v2) + } + case "/": + result = arg[0] + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%d", v1/v2) + } + case "%": + result = arg[0] + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%d", v1%v2) + } + + case "<": + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%t", v1 < v2) + } else { + result = fmt.Sprintf("%t", arg[0] < arg[2]) + } + + case "<=": + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%t", v1 <= v2) + } else { + result = fmt.Sprintf("%t", arg[0] <= arg[2]) + } + + case ">": + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%t", v1 > v2) + } else { + result = fmt.Sprintf("%t", arg[0] > arg[2]) + } + + case ">=": + if e1 == nil && e2 == nil { + result = fmt.Sprintf("%t", v1 >= v2) + } else { + result = fmt.Sprintf("%t", arg[0] >= arg[2]) + } + + case "==": + if arg[0] == arg[2] { + result = "true" + } + case "!=": + if arg[0] != arg[2] { + result = "true" + } + case "~": + if m, e := regexp.MatchString(arg[1], arg[0]); m && e == nil { + result = "true" + } + case "!~": + if m, e := regexp.MatchString(arg[1], arg[0]); !m || e != nil { + result = "true" + } + + } + } + + cli.Pulse.Log("info", nil, "result: %v", result) + return result +} + +// }}} +func (cli *CLI) check(arg []string) bool { // {{{ + switch cli.express(arg) { + case "", "0", "false": + return false + } + return true +} + +// }}} + +func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{ c.Caches = map[string]*ctx.Cache{} c.Configs = map[string]*ctx.Config{} + c.Caches["skip"] = &ctx.Cache{Name: "下一条指令", Value: "0", Help: "下一条指令"} + if cli.Has("skip") { + m.Cap("skip", cli.Pulse.Cap("skip")) + } s := new(CLI) s.Context = c s.lex = cli.lex s.alias = cli.alias + s.lines = cli.lines[cli.pos:] return s } -func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { +// }}} +func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ cli.Caches["target"] = &ctx.Cache{Name: "操作目标", Value: "", Help: "操作目标"} cli.Caches["result"] = &ctx.Cache{Name: "前一条指令执行结果", Value: "", Help: "前一条指令执行结果"} cli.Caches["back"] = &ctx.Cache{Name: "前一条指令", Value: "", Help: "前一条指令"} cli.Caches["next"] = &ctx.Cache{Name: "下一条指令", Value: "", Help: "下一条指令"} + cli.Caches["exit"] = &ctx.Cache{Name: "下一条指令", Value: "0", Help: "下一条指令"} + cli.Caches["else"] = &ctx.Cache{Name: "下一条指令", Value: "0", Help: "下一条指令"} + cli.Caches["nline"] = &ctx.Cache{Name: "下一条指令", Value: "0", Help: "下一条指令"} cli.Configs["PS1"] = &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { if len(arg) > 0 { // {{{ @@ -228,7 +366,7 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { }} if len(arg) > 0 { - cli.Configs["init.sh"] = &ctx.Config{Name: "启动脚本", Value: arg[0], Help: "模块启动时自动运行的脚本"} + cli.Configs["init.shy"] = &ctx.Config{Name: "启动脚本", Value: arg[0], Help: "模块启动时自动运行的脚本"} } if cli.Context == Index { @@ -236,57 +374,44 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { } cli.target = cli.Context - cli.alias = map[string]string{ - "~": "context", - "!": "message", - "@": "config", - "$": "cache", - "&": "server", - ":": "command", + cli.alias = map[string][]string{ + "~": []string{"context"}, + "!": []string{"message"}, + "@": []string{"config"}, + "$": []string{"cache"}, + "&": []string{"server"}, + ":": []string{"command"}, } return cli } -func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { - cli.Context.Exit = make(chan bool) +// }}} +func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ + cli.pos = 0 cli.bio = nil - cli.exit = false - cli.test = false + cli.Context.Exit = make(chan bool) - if stream, ok := m.Data["io"]; ok { - cli.Context.Master(cli.Context) - io := stream.(io.ReadWriteCloser) - cli.bio = bufio.NewReader(io) - cli.out = io + cli.Caches["#"] = &ctx.Cache{Name: "前一条指令", Value: fmt.Sprintf("%d", len(arg)), Help: "前一条指令"} + for i, v := range arg { + cli.Caches[fmt.Sprintf("%d", i)] = &ctx.Cache{Name: "前一条指令", Value: v, Help: "前一条指令"} + } - if msg := m.Find("aaa", true); msg != nil { - cli.echo("username>") - username, e := cli.bio.ReadString('\n') - msg.Assert(e) - username = strings.TrimSpace(username) - - cli.echo("password>") - password, e := cli.bio.ReadString('\n') - msg.Assert(e) - password = strings.TrimSpace(password) - - msg.Name = "aaa" - msg.Wait = make(chan bool) - if msg.Cmd("login", username, password) == "" { - cli.echo("登录失败") - io.Close() - return true + m.Caps("exit", false) + m.Caps("else", false) + if m.Has("skip") { + if m.Capi("skip", 1) == 1 { + if !m.Has("save") { + m.Caps("else", true) } - - if cli.Sessions == nil { - cli.Sessions = make(map[string]*ctx.Message) - } - cli.Sessions["aaa"] = msg } - } else if len(arg) > 0 && arg[0] == "stdout" { + } else { + m.Caps("skip", false) + } + + if m.Has("stdio") { m.Cap("stream", "stdout") - m.Cap("next", "source "+m.Conf("init.sh")) + m.Cap("next", "source "+m.Conf("init.shy")) cli.bio = bufio.NewReader(os.Stdin) cli.out = os.Stdout cli.Caches["level"] = &ctx.Cache{Name: "操作目标", Value: "0", Help: "操作目标"} @@ -298,64 +423,90 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { m.Cap("stream", "file") cli.bio = bufio.NewReader(stream.(io.ReadWriteCloser)) } - cli.test = m.Has("test") - cli.save = m.Has("save") + } + + if cli.bio != nil { + cli.lines = []string{m.Get("for")} } go m.AssertOne(m, true, func(m *ctx.Message) { - for cli.parse(m) { + for !m.Caps("exit") { + if cmd := cli.parse(m); cmd != nil { + m.Spawn(cli.target).Set("detail", cmd...).Post(cli.Context) + } } + }, func(m *ctx.Message) { + m.Caps("exit", true) + m.Spawn(cli.Context).Set("detail", "end").Post(cli.Context) }) m.Capi("nterm", 1) defer m.Capi("nterm", -1) m.Deal(func(msg *ctx.Message, arg ...string) bool { - if cli.test { - if _, ok := Index.Commands[msg.Get("detail")]; ok { - msg.Exec(msg.Meta["detail"][0], msg.Meta["detail"][1:]...) - } - return false - } - return true + return !cli.Has("skip") || !m.Caps("skip") || Index.Has(msg.Get("detail"), "command") + }, func(msg *ctx.Message, arg ...string) bool { - if msg.Get("result") == "error: " { - if msg.Get("detail") != "login" { - msg.Log("system", nil, "%v", msg.Meta["detail"]) + if cli.Has("skip") && m.Caps("skip") { + return !m.Caps("exit") + } - msg.Set("result") - msg.Set("append") - c := exec.Command(msg.Meta["detail"][0], msg.Meta["detail"][1:]...) + if !msg.Has("result") && cli.Owner == ctx.Index.Owner { + msg.Log("system", nil, "%v", msg.Meta["detail"]) - if cli.out == os.Stdout { - c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr - msg.Assert(c.Start()) - msg.Assert(c.Wait()) + msg.Set("result").Set("append") + c := exec.Command(msg.Meta["detail"][0], msg.Meta["detail"][1:]...) + + if cli.out == os.Stdout { + c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr + if e := c.Start(); e != nil { + msg.Echo("error: ") + msg.Echo("%s\n", e) + } else if e := c.Wait(); e != nil { + msg.Echo("error: ") + msg.Echo("%s\n", e) + } + } else { + if out, e := c.CombinedOutput(); e == nil { + msg.Echo(string(out)) } else { - if out, e := c.CombinedOutput(); e == nil { - msg.Echo(string(out)) - } else { - msg.Echo("error: ") - msg.Echo("%s\n", e) - } + msg.Echo("error: ") + msg.Echo("%s\n", e) } } } + result := strings.TrimRight(strings.Join(msg.Meta["result"], ""), "\n") + if m.Cap("result", result); len(result) > 0 { + cli.print(result + "\n") + } + if msg.Target().Context() != nil || msg.Target() == ctx.Index { cli.target = msg.Target() } - return cli.exit == false + m.Cap("target", cli.target.Name) + + return !m.Caps("exit") }) - return !cli.save + if cli.Pulse.Has("save") { + m.Cap("status", "stop") + cli.Exit <- true + } + + return !cli.Pulse.Has("save") } -func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { +// }}} +func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{ switch cli.Context { case m.Target(): - if m.Target() == Index && m.Capi("nserver") > 1 { - return false + if p, ok := cli.Context.Context().Server.(*CLI); ok { + if p.bio != nil { + p.lines = append(p.lines, cli.lines...) + } else { + p.pos += cli.pos + } } case m.Source(): if m.Name == "aaa" { @@ -369,205 +520,177 @@ func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { return true } +// }}} + var Pulse *ctx.Message var Index = &ctx.Context{Name: "cli", Help: "管理中心", Caches: map[string]*ctx.Cache{ - "nterm": &ctx.Cache{Name: "终端数量", Value: "0", Help: "已经运行的终端数量"}, + "nterm": &ctx.Cache{Name: "终端数量", Value: "0", Help: "正在运行的终端数量"}, }, Configs: map[string]*ctx.Config{}, Commands: map[string]*ctx.Command{ - "sleep": &ctx.Command{Name: "sleep time", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - t, e := strconv.Atoi(arg[0]) // {{{ - m.Assert(e) - m.Log("info", nil, "sleep %ds", t) - time.Sleep(time.Second * time.Duration(t)) - m.Log("info", nil, "sleep %ds done", t) - // }}} - }}, - "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(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) { - cli, ok := m.Source().Server.(*CLI) // {{{ - m.Assert(ok) - cli.exit = true - for _, v := range arg { - cli.Pulse.Echo(v) - } - // }}} - }}, - "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) + "alias": &ctx.Command{Name: "alias [short [long]]|[delete short]", Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Target().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) - 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) { - 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 - // }}} - }}, - "end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - cli, ok := m.Source().Server.(*CLI) // {{{ - m.Assert(ok) - cli.exit = true - // }}} - }}, - "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.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) // {{{ - m.Target(m.Source().Context()) - m.Assert(ok) - m.Add("option", "test") - m.Add("option", "save") - m.Put("option", "file", cli.bio).Start(arg[0], "定义函数") - // }}} - }}, - "alias": &ctx.Command{Name: "alias [short [long]]", Help: "定义别名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - cli := c.Server.(*CLI) // {{{ switch len(arg) { case 0: for k, v := range cli.alias { - m.Echo("%s: %s\n", k, v) - } - case 2: - switch arg[0] { - case "delete": - delete(cli.alias, arg[1]) - default: - cli.alias[arg[0]] = arg[1] - m.Echo("%s: %s\n", arg[0], cli.alias[arg[0]]) + m.Echo("%s: %v\n", k, v) } + case 1: + m.Echo("%s: %v\n", arg[0], cli.alias[arg[0]]) default: - cli.alias[arg[0]] = strings.Join(arg[1:], " ") - m.Echo("%s: %s\n", arg[0], cli.alias[arg[0]]) + if arg[0] == "delete" { + m.Echo("delete: %s %v\n", arg[1], cli.alias[arg[1]]) + delete(cli.alias, arg[1]) + } else { + cli.alias[arg[0]] = arg[1:] + m.Echo("%s: %v\n", arg[0], cli.alias[arg[0]]) + } } // }}} }}, - // "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", - Commands: map[string]*ctx.Command{ - "open": &ctx.Command{}, - }, - }, + "sleep": &ctx.Command{Name: "sleep time", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ + if d, e := time.ParseDuration(arg[0]); m.Assert(e) { + m.Log("info", nil, "sleep %v", d) + time.Sleep(d) + m.Log("info", nil, "sleep %v done", d) + } + } + // }}} + }}, + "var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ + val := "" + if len(arg) > 2 { + val = cli.express(arg[2:]) + } + cli.Pulse.Cap(arg[0], arg[0], val, "临时变量") + } + // }}} + }}, + "let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式(a {+|-|*|/|%} b)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ + m.Echo(cli.Pulse.Cap(arg[0], cli.express(arg[2:]))) + } + // }}} + }}, + "source": &ctx.Command{Name: "source file", Help: "运行脚本, file: 脚本文件名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ + if f, e := os.Open(arg[0]); m.Assert(e) { + 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: "结束脚本, rusult: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{ + call := cli.Requests[len(cli.Requests)-1] + call.Log("fuck", nil, "return") + for _, v := range arg { + call.Echo(v) + } + cli.Pulse.Caps("exit", true) + } + // }}} + }}, + "if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ + if m.Target(m.Source()); (cli.Has("skip") && cli.Pulse.Caps("skip")) || !cli.check(arg) { + m.Add("option", "skip") + } + + m.Put("option", "file", cli.bio).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "条件语句") + <-m.Target().Exit + Pulse.Capi("level", -1) + } + // }}} + }}, + "elif": &ctx.Command{Name: "elif exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ + if !cli.Pulse.Caps("else") { + cli.Pulse.Capi("skip", 1) + return + } + + cli.Pulse.Caps("else", cli.Pulse.Caps("skip", !cli.check(arg))) + } + // }}} + }}, + "else": &ctx.Command{Name: "else", Help: "条件切换", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ + if cli.Pulse.Caps("else") { + cli.Pulse.Capi("skip", -1) + } else { + cli.Pulse.Capi("skip", 1) + } + } + // }}} + }}, + "end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ + cli.Pulse.Caps("exit", true) + if cli.Pulse.Has("for") && !cli.Pulse.Caps("skip") { + cli.Pulse.Caps("exit", false) + cli.pos = 0 + } + cli.bio = nil + } + // }}} + }}, + "for": &ctx.Command{Name: "for exp", Help: "循环语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ + if cli.Pulse.Has("for") && cli.pos > 0 { + if m.Target(m.Source()); (cli.Has("skip") && cli.Pulse.Caps("skip")) || !cli.check(arg) { + m.Capi("skip", 1) + } + + return + } + + m.Log("fuck", nil, "%d %d %v", cli.pos, len(cli.lines), cli.lines) + if m.Target(m.Source()); (cli.Has("skip") && cli.Pulse.Caps("skip")) || !cli.check(arg) { + m.Add("option", "skip") + } + m.Add("option", "for", cli.Pulse.Cap("back")) + m.Put("option", "file", cli.bio).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "循环语句") + <-m.Target().Exit + Pulse.Capi("level", -1) + } + // }}} + }}, + "function": &ctx.Command{Name: "function name", Help: "定义函数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{ + if _, ok := cli.Context.Context().Server.(*CLI); ok { + m.Target(m.Source().Context()) + } else { + m.Target(m.Source()) + } + + m.Add("option", "skip") + m.Add("option", "save") + m.Put("option", "file", cli.bio).Start(arg[0], "定义函数") + <-m.Target().Exit + } + // }}} + }}, + "call": &ctx.Command{Name: "call name arg...", Help: "定义函数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + m.Target(m.Source()) // {{{ + m.BackTrace(func(msg *ctx.Message) bool { + if fun := msg.Find(arg[0], false); fun != nil { + fun.Add("detail", arg[0], arg[1:]...).Target().Start(fun) + <-fun.Target().Exit + m.Set("result", fun.Meta["result"]...) + return false + } + return true + }) + // }}} + }}, }, } diff --git a/src/context/ctx.go b/src/context/ctx.go index afe7334b..a27d7ad1 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -608,7 +608,13 @@ func (m *Message) Assert(e interface{}, msg ...string) bool { // {{{ return true } - if len(msg) > 0 { + if len(msg) > 1 { + arg := make([]interface{}, 0, len(msg)-1) + for _, m := range msg[1:] { + arg = append(arg, m) + } + e = errors.New(fmt.Sprintf(msg[0], arg...)) + } else if len(msg) > 0 { e = errors.New(msg[0]) } if _, ok := e.(error); !ok { @@ -635,9 +641,7 @@ func (m *Message) AssertOne(msg *Message, safe bool, hand ...func(msg *Message)) fmt.Printf("\033[31m%s error: %v\033[0m\n\n", msg.target.Name, e) } - if e == io.EOF { - return - } else if len(hand) > 1 { + if len(hand) > 1 { m.AssertOne(msg, safe, hand[1:]...) } else if !safe { msg.Assert(e) @@ -809,14 +813,22 @@ func (m *Message) Add(meta string, key string, value ...string) *Message { // {{ case "detail", "result": m.Meta[meta] = append(m.Meta[meta], key) m.Meta[meta] = append(m.Meta[meta], value...) + case "option", "append": if _, ok := m.Meta[key]; !ok { m.Meta[key] = make([]string, 0, 3) - m.Meta[meta] = append(m.Meta[meta], key) } m.Meta[key] = append(m.Meta[key], value...) + + for _, v := range m.Meta[meta] { + if v == key { + return m + } + } + m.Meta[meta] = append(m.Meta[meta], key) + default: - m.Assert(false, "消息参数错误") + m.Log("error", nil, "%s 消息参数错误", meta) } return m @@ -824,20 +836,12 @@ func (m *Message) Add(meta string, key string, value ...string) *Message { // {{ // }}} func (m *Message) Set(meta string, arg ...string) *Message { // {{{ - if m.Meta == nil { - m.Meta = make(map[string][]string) - } - if _, ok := m.Meta[meta]; !ok { - m.Meta[meta] = make([]string, 0, 3) - } - switch meta { case "detail", "result": - m.Meta[meta] = arg + delete(m.Meta, meta) case "option", "append": if len(arg) > 0 { - m.Meta[meta] = []string{arg[0]} - m.Meta[arg[0]] = arg[1:] + delete(m.Meta, arg[0]) } else { for _, k := range m.Meta[meta] { delete(m.Meta, k) @@ -846,7 +850,11 @@ func (m *Message) Set(meta string, arg ...string) *Message { // {{{ delete(m.Meta, meta) } default: - m.Assert(false, "消息参数错误") + m.Log("error", nil, "%s 消息参数错误", meta) + } + + if len(arg) > 0 { + m.Add(meta, arg[0], arg[1:]...) } return m @@ -863,15 +871,20 @@ func (m *Message) Put(meta string, key string, value interface{}) *Message { // if m.Data == nil { m.Data = make(map[string]interface{}) } + m.Data[key] = value + if _, ok := m.Meta[meta]; !ok { m.Meta[meta] = make([]string, 0, 3) } - if _, ok := m.Data[key]; !ok { - m.Meta[meta] = append(m.Meta[meta], key) + for _, v := range m.Meta[meta] { + if v == key { + return m + } } - m.Data[key] = value + m.Meta[meta] = append(m.Meta[meta], key) + default: - m.Assert(false, "消息参数错误") + m.Log("error", nil, "%s 消息参数错误", meta) } return m @@ -904,15 +917,14 @@ func (m *Message) Geti(key string) int { // {{{ } // }}} -func (m *Message) Echo(str string, arg ...interface{}) *Message { // {{{ - return m.Add("result", fmt.Sprintf(str, arg...)) +func (m *Message) Gets(key string) bool { // {{{ + b := m.Get(key) + return b != "" && b != "0" } // }}} -func (m *Message) End(s bool) { // {{{ - if m.Wait != nil { - m.Wait <- s - } +func (m *Message) Echo(str string, arg ...interface{}) *Message { // {{{ + return m.Add("result", fmt.Sprintf(str, arg...)) } // }}} @@ -962,6 +974,9 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{ } x.Hand(m.Set("result").Set("append"), s, key, arg...) + if !m.Has("result") { + m.Meta["result"] = nil + } if x.Appends != nil { for _, v := range m.Meta["append"] { @@ -981,8 +996,6 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{ } } } - - m.Set("result", "error: ", "命令不存在") return "" } @@ -994,7 +1007,11 @@ func (m *Message) Deal(pre func(msg *Message, arg ...string) bool, post func(msg for run := true; run; { m.AssertOne(<-m.target.messages, true, func(msg *Message) { - defer msg.End(true) + defer func() { + if msg.Wait != nil { + msg.Wait <- true + } + }() if len(msg.Meta["detail"]) == 0 { return @@ -1013,22 +1030,26 @@ func (m *Message) Deal(pre func(msg *Message, arg ...string) bool, post func(msg } // }}} -func (m *Message) Post(s *Context) string { // {{{ +func (m *Message) Post(s *Context, async ...bool) string { // {{{ if s == nil { s = m.target.master } - m.Assert(s.messages != nil, s.Name+" 没有开启消息处理") + if s != nil && s.messages != nil { + if len(async) == 0 || async[0] == false { + m.Wait = make(chan bool) + } - if s.messages <- m; m.Wait != nil { - <-m.Wait + if s.messages <- m; m.Wait != nil { + <-m.Wait + } + return m.Get("result") } - return m.Get("result") + return m.Exec(m.Meta["detail"][0], m.Meta["detail"][1:]...) } // }}} - func (m *Message) Cmd(arg ...string) string { // {{{ if len(arg) > 0 { m.Set("detail", arg...) @@ -1041,6 +1062,21 @@ func (m *Message) Cmd(arg ...string) string { // {{{ return m.Exec(m.Meta["detail"][0], m.Meta["detail"][1:]...) } +// }}} + +func (m *Message) Confs(key string, arg ...bool) bool { // {{{ + if len(arg) > 0 { + if arg[0] { + m.Conf(key, "1") + } else { + m.Conf(key, "0") + } + } + + b := m.Conf(key) + return b != "" && b != "0" +} + // }}} func (m *Message) Confi(key string, arg ...int) int { // {{{ n, e := strconv.Atoi(m.Conf(key)) @@ -1057,6 +1093,7 @@ func (m *Message) Confi(key string, arg ...int) int { // {{{ // }}} func (m *Message) Conf(key string, arg ...string) string { // {{{ var hand func(m *Message, x *Config, arg ...string) string + for _, c := range []*Context{m.target, m.target.master, m.target.Owner, m.source, m.source.master, m.source.Owner} { for s := c; s != nil; s = s.context { if x, ok := s.Configs[key]; ok { @@ -1070,13 +1107,12 @@ func (m *Message) Conf(key string, arg ...string) string { // {{{ hand = x.Hand } case 1: - m.Log("conf", s, "%s %v", key, arg) - if x.Hand != nil { x.Value = x.Hand(m, x, arg[0]) } else { x.Value = arg[0] } + m.Log("conf", s, "%s %v", x.Name, x.Value) return x.Value case 0: if x.Hand != nil { @@ -1102,13 +1138,30 @@ func (m *Message) Conf(key string, arg ...string) string { // {{{ return "" } +// }}} +func (m *Message) Caps(key string, arg ...bool) bool { // {{{ + if len(arg) > 0 { + if arg[0] { + m.Cap(key, "1") + } else { + m.Cap(key, "0") + } + } + + b := m.Cap(key) + return b != "" && b != "0" +} + // }}} func (m *Message) Capi(key string, arg ...int) int { // {{{ n, e := strconv.Atoi(m.Cap(key)) m.Assert(e) - if len(arg) > 0 { - n, e = strconv.Atoi(m.Cap(key, fmt.Sprintf("%d", arg[0]+n))) + for _, i := range arg { + if i == 0 { + i = -n + } + n, e = strconv.Atoi(m.Cap(key, fmt.Sprintf("%d", n+i))) m.Assert(e) } @@ -1118,6 +1171,7 @@ func (m *Message) Capi(key string, arg ...int) int { // {{{ // }}} func (m *Message) Cap(key string, arg ...string) string { // {{{ var hand func(m *Message, x *Cache, arg ...string) string + for _, c := range []*Context{m.target, m.target.master, m.target.Owner, m.source, m.source.master, m.source.Owner} { for s := c; s != nil; s = s.context { if x, ok := s.Caches[key]; ok { @@ -1175,8 +1229,8 @@ var Index = &Context{Name: "ctx", Help: "模块中心", Configs: map[string]*Config{ "default": &Config{Name: "默认的搜索起点(root/back/home)", Value: "root", Help: "模块搜索的默认起点,root:从根模块,back:从父模块,home:从当前模块"}, - "start": &Config{Name: "启动模块", Value: "cli", Help: "启动时自动运行的模块"}, - "init.sh": &Config{Name: "启动脚本", Value: "etc/init.sh", Help: "模块启动时自动运行的脚本"}, + "start": &Config{Name: "启动模块", Value: "cli", Help: "启动时自动运行的模块"}, + "init.shy": &Config{Name: "启动脚本", Value: "etc/init.shy", Help: "模块启动时自动运行的脚本"}, "bench.log": &Config{Name: "日志文件", Value: "var/bench.log", Help: "模块日志输出的文件", Hand: func(m *Message, x *Config, arg ...string) string { if len(arg) > 0 { // {{{ if e := os.MkdirAll(path.Dir(arg[0]), os.ModePerm); e == nil { @@ -1510,6 +1564,7 @@ var Index = &Context{Name: "ctx", Help: "模块中心", } return all }) + m.Assert(m.Has("result"), "%s 命令不存在", arg[0]) case 3: cmd := &Command{} m.BackTrace(func(m *Message) bool { @@ -1686,7 +1741,7 @@ func Start(args ...string) { Pulse.Conf("start", args[0]) } if len(args) > 1 { - Pulse.Conf("init.sh", args[1]) + Pulse.Conf("init.shy", args[1]) } if len(args) > 2 { Pulse.Conf("bench.log", args[2]) @@ -1705,13 +1760,11 @@ func Start(args ...string) { m.target.root = Index m.target.Begin(m) } - Index.Requests = append(Index.Requests, Pulse) log.Println() for _, m := range Pulse.Search(Pulse.Conf("start")) { - m.Set("detail", "stdout").target.Start(m) + m.Set("option", "stdio").target.Start(m) } - for <-Pulse.Wait; Pulse.Capi("nserver") > 0; <-Pulse.Wait { - } + <-Index.master.Exit }