From b3486b5e37c503a1a9febc5a7cf6bd75c93a903b Mon Sep 17 00:00:00 2001 From: shaoying Date: Sun, 16 Jun 2019 18:31:12 +0800 Subject: [PATCH] add m.Cmdp --- bin/boot.sh | 4 +- etc/init.shy | 8 +- src/contexts/cli/cli.go | 78 ++- src/contexts/ctx/ctx.go | 21 + src/contexts/log/log.go | 4 +- src/contexts/nfs/nfs.go | 5 + src/contexts/web/web.go | 41 +- src/examples/code/code.go | 3 +- src/toolkit/kit.go | 6 + usr/librarys/code.js | 609 +---------------------- usr/librarys/context.js | 2 +- usr/wiki/自然/编程/终端工具链/context.md | 358 +++++++++---- 12 files changed, 391 insertions(+), 748 deletions(-) diff --git a/bin/boot.sh b/bin/boot.sh index 3bc33f99..a17c5760 100755 --- a/bin/boot.sh +++ b/bin/boot.sh @@ -34,8 +34,10 @@ install() { "armv7l") GOARCH=arm;; esac + target=system && [ -n "$2" ] && target=$2 + wget -O ${ctx_app} "$ctx_dev/publish/${ctx_app}?GOOS=$GOOS&GOARCH=$GOARCH" && chmod a+x ${ctx_app} \ - && ./${ctx_app} upgrade system && ${md5} ${ctx_app} \ + && ./${ctx_app} upgrade ${target} && ${md5} ${ctx_app} \ && mv ${ctx_app} bin/${ctx_app} } main() { diff --git a/etc/init.shy b/etc/init.shy index 1a2c5f9c..17ed1a32 100644 --- a/etc/init.shy +++ b/etc/init.shy @@ -1,11 +1,11 @@ ~cli - config load var/tmp/runtime.json runtime + config load tmp/runtime.json runtime ~aaa - config load var/tmp/auth.json auth + config load tmp/auth.json auth ~ssh - config load var/tmp/cert.json work flow trust + config load tmp/cert.json work flow trust ~wiki - config load var/tmp/wiki.json wiki_visit + config load tmp/wiki.json wiki_visit source etc/common.shy ~ssh remote auto diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index 46eb85c1..0d9cff43 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -130,6 +130,20 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "daemon": &ctx.Config{Name: "daemon", Value: map[string]interface{}{}, Help: "守护任务"}, "action": &ctx.Config{Name: "action", Value: map[string]interface{}{}, Help: "交互任务"}, + "project": &ctx.Config{Name: "project", Value: map[string]interface{}{ + "github": "https://github.com/shylinux/context", + "env": map[string]interface{}{ + "GOPATH": "https://github.com/shylinux/context", + }, + "import": []interface{}{ + "github.com/nsf/termbox-go", + "github.com/skip2/go-qrcode", + "github.com/go-sql-driver/mysql", + "github.com/gomarkdown/markdown", + "github.com/PuerkitoBio/goquery", + "github.com/go-cas/cas", + }, + }, Help: "运行环境"}, "compile": &ctx.Config{Name: "compile", Value: map[string]interface{}{ "bench": "src/examples/app/bench.go", "env": []interface{}{"GOPATH", "PATH"}, @@ -216,6 +230,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", if name, e := os.Getwd(); e == nil { _, file := path.Split(kit.Select(name, os.Getenv("PWD"))) m.Conf("runtime", "boot.pathname", file) + m.Conf("runtime", "boot.ctx_path", name) } return }}, @@ -501,6 +516,28 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", return }}, + "project": &ctx.Command{Name: "project", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + switch arg[0] { + case "init": + m.Cmdp(time.Second, []string{"git init"}, []string{"cli.system", "git"}, [][]string{ + []string{"git", "init"}, + []string{"git", "remote", "add", kit.Select("origin", arg, 1), kit.Select(m.Conf("project", "github"), arg, 2)}, + []string{"git", "stash"}, + []string{"git", "pull"}, + []string{"git", "checkout", "-f", "master"}, + []string{"git", "stash", "pop"}, + }) + + list := [][]string{} + m.Confm("project", "import", func(index int, value string) { + list = append(list, []string{value}) + }) + + m.Cmdp(time.Second, []string{"go init"}, []string{"cli.system", "go", "get", + "cmd_env", "GOPATH", m.Conf("runtime", "boot.ctx_path")}, list) + } + return + }}, "compile": &ctx.Command{Name: "compile [OS [ARCH]]", Help: "解析脚本, script: 脚本文件, stdio: 命令终端, snippet: 代码片段", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if len(arg) > 0 && arg[0] == "self" { if m.Cmdy("cli.system", "go", "install", m.Cmdx("nfs.path", m.Conf("compile", "bench"))); m.Result(0) == "" { @@ -510,13 +547,14 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } if len(arg) > 0 && arg[0] == "all" { - m.Cmdy("cli.compile", "linux", "386") - m.Cmdy("cli.compile", "linux", "amd64") - m.Cmdy("cli.compile", "linux", "arm") - m.Cmdy("cli.compile", "windows", "386") - m.Cmdy("cli.compile", "windows", "amd64") - m.Cmdy("cli.compile", "darwin", "amd64") - m.Set("result").Table() + m.Cmdp(time.Second, []string{"go build"}, []string{"cli.compile"}, [][]string{ + []string{"linux", "386"}, + []string{"linux", "amd64"}, + []string{"linux", "arm"}, + []string{"windows", "386"}, + []string{"windows", "amd64"}, + []string{"darwin", "amd64"}, + }) return } @@ -547,7 +585,17 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", dir := m.Conf("publish", "path") m.Assert(os.MkdirAll(dir, 0777)) - m.Confm("publish", "list", func(key string, value string) { + if len(arg) == 0 { + list := [][]string{} + m.Confm("publish", "list", func(key string, value string) { + list = append(list, []string{key}) + }) + m.Cmdp(time.Second, []string{"copy"}, []string{"cli.publish"}, list) + return + } + + for _, key := range arg { + value := m.Conf("publish", []string{"list", key}) p := m.Cmdx("nfs.path", value) if s, e := os.Stat(p); e == nil { if s.IsDir() { @@ -555,18 +603,24 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } else { m.Cmd("nfs.copy", path.Join(dir, key), p) } - return } - }) - m.Cmdy("nfs.dir", dir, "dir_sort", "time", "time_r") + } + + // m.Cmdy("nfs.dir", dir, "dir_sort", "time", "time_r") return }}, - "upgrade": &ctx.Command{Name: "upgrade bench|system|extend|plugin|portal|client|script", Help: "服务升级", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + "upgrade": &ctx.Command{Name: "upgrade bench|system|extend|plugin|portal|client|script|project", Help: "服务升级", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { if len(arg) == 0 { m.Cmdy("ctx.config", "upgrade") return } + if len(arg) > 0 && arg[0] == "project" { + m.Cmd("cli.project", "init") + m.Cmd("cli.compile", "all") + m.Cmd("cli.publish") + return + } restart := false for _, link := range kit.View([]string{arg[0]}, m.Confm("upgrade")) { diff --git a/src/contexts/ctx/ctx.go b/src/contexts/ctx/ctx.go index 04c54193..0588ee9a 100644 --- a/src/contexts/ctx/ctx.go +++ b/src/contexts/ctx/ctx.go @@ -1230,6 +1230,14 @@ func (m *Message) Log(action string, str string, arg ...interface{}) *Message { return m } +func (m *Message) Show(args ...interface{}) *Message { + if m.Option("cli.modal") == "action" { + fmt.Printf(kit.Format(args...)) + } else if kit.STDIO != nil { + kit.STDIO.Show(args...) + } + return m +} func (m *Message) Assert(e interface{}, msg ...string) bool { switch v := e.(type) { case nil: @@ -1541,6 +1549,19 @@ func (m *Message) Free(cbs ...func(msg *Message) (done bool)) *Message { return m } +func (m *Message) Cmdp(t time.Duration, head []string, prefix []string, suffix [][]string) *Message { + if head != nil && len(head) > 0 { + m.Show(strings.Join(head, " "), "...\n") + } + + for i, v := range suffix { + m.Show(fmt.Sprintf("%v/%v %v...\n", i+1, len(suffix), v)) + m.Cmd(prefix, v) + time.Sleep(t) + } + m.Show("\n") + return m +} func (m *Message) Cmdm(args ...interface{}) *Message { m.Log("info", "current: %v", m.Magic("session", "current")) diff --git a/src/contexts/log/log.go b/src/contexts/log/log.go index 5ac95044..eb556c78 100644 --- a/src/contexts/log/log.go +++ b/src/contexts/log/log.go @@ -151,7 +151,9 @@ var Index = &ctx.Context{Name: "log", Help: "日志中心", "search": map[string]interface{}{"value": []interface{}{"debug"}}, "call": map[string]interface{}{"value": []interface{}{"debug"}}, "back": map[string]interface{}{"value": []interface{}{"debug"}}, - "send": map[string]interface{}{"value": []interface{}{"debug"}}, + + "send": map[string]interface{}{"value": []interface{}{"debug"}}, + "recv": map[string]interface{}{"value": []interface{}{"debug"}}, "bench": map[string]interface{}{"value": []interface{}{"bench"}}, "begin": map[string]interface{}{"value": []interface{}{"bench", "red"}}, diff --git a/src/contexts/nfs/nfs.go b/src/contexts/nfs/nfs.go index 2b7a606a..719ba976 100644 --- a/src/contexts/nfs/nfs.go +++ b/src/contexts/nfs/nfs.go @@ -784,6 +784,10 @@ func (nfs *NFS) printf(arg ...interface{}) *NFS { } return nfs } +func (nfs *NFS) Show(arg ...interface{}) bool { + nfs.prompt(arg...) + return true +} func (nfs *NFS) Recv(line string) (field string, value string) { m := nfs.Context.Message() @@ -885,6 +889,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // 终端控制 if nfs.in = m.Optionv("in").(*os.File); m.Has("out") { if nfs.out = m.Optionv("out").(*os.File); m.Cap("goos") != "windows" && !m.Options("daemon") { + kit.STDIO = nfs nfs.Term(m, "init") defer nfs.Term(m, "exit") } diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index 2aadb53d..f6d79d99 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -768,6 +768,15 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", return }}, "brow": &ctx.Command{Name: "brow url", Help: "浏览网页", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + if len(arg) == 0 { + m.Cmd("tcp.ifconfig").Table(func(index int, value map[string]string) { + m.Append("index", index) + m.Append("site", fmt.Sprintf("%s://%s%s", m.Conf("serve", "protocol"), value["ip"], m.Conf("runtime", "boot.web_port"))) + }) + m.Table() + return + } + switch runtime.GOOS { case "windows": m.Cmd("cli.system", "explorer", arg[0]) @@ -1113,6 +1122,22 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", m.Cmdy("web.get", "which", fields[2], "method", fields[3], strings.Join(fields, "/")) return }}, + + "/publish/": &ctx.Command{Name: "/publish/", Help: "下载文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + key = strings.TrimPrefix(key, "/publish/") + if strings.HasSuffix(key, "bench") { + key = key + "." + m.Option("GOOS") + "." + m.Option("GOARCH") + } + key = strings.Replace(key, ".", "_", -1) + p := m.Cmdx("nfs.path", path.Join(m.Conf("publish", "path"), key)) + if p == "" { + p = m.Cmdx("nfs.path", m.Conf("publish", []string{"list", key})) + } + + m.Log("info", "publish %s %s", kit.Hashs(p), p) + http.ServeFile(m.Optionv("response").(http.ResponseWriter), m.Optionv("request").(*http.Request), p) + return + }}, "/shadow": &ctx.Command{Name: "/shadow", Help: "暗网", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { m.Confm("runtime", "node.port", func(index int, value string) { m.Add("append", "ports", value) @@ -1149,22 +1174,6 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", } return }}, - - "/publish/": &ctx.Command{Name: "/publish/", Help: "下载文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - key = strings.TrimPrefix(key, "/publish/") - if strings.HasSuffix(key, "bench") { - key = key + "." + m.Option("GOOS") + "." + m.Option("GOARCH") - } - key = strings.Replace(key, ".", "_", -1) - p := m.Cmdx("nfs.path", path.Join(m.Conf("publish", "path"), key)) - if p == "" { - p = m.Cmdx("nfs.path", m.Conf("publish", []string{"list", key})) - } - - m.Log("info", "publish %s %s", kit.Hashs(p), p) - http.ServeFile(m.Optionv("response").(http.ResponseWriter), m.Optionv("request").(*http.Request), p) - return - }}, }, } diff --git a/src/examples/code/code.go b/src/examples/code/code.go index 63c11dd6..cb63b93b 100644 --- a/src/examples/code/code.go +++ b/src/examples/code/code.go @@ -22,7 +22,8 @@ var Index = &ctx.Context{Name: "code", Help: "代码中心", map[string]interface{}{"name": "viewport", "content": "width=device-width, initial-scale=0.7, user-scalable=no"}, }, "favicon": "favicon.ico", "styles": []interface{}{"example.css", "code.css"}}, - map[string]interface{}{"componet_name": "login", "componet_help": "login", "componet_tmpl": "componet", + map[string]interface{}{"componet_name": "login", "componet_help": "login", + "componet_tmpl": "componet", "componet_init": "initLogin", "componet_ctx": "aaa", "componet_cmd": "auth", "componet_args": []interface{}{"@sessid", "ship", "username", "@username", "password", "@password"}, "inputs": []interface{}{ map[string]interface{}{"type": "text", "name": "username", "value": "", "label": "username"}, map[string]interface{}{"type": "password", "name": "password", "value": "", "label": "password"}, diff --git a/src/toolkit/kit.go b/src/toolkit/kit.go index 7769dadf..7f7bfb3b 100644 --- a/src/toolkit/kit.go +++ b/src/toolkit/kit.go @@ -16,6 +16,12 @@ import ( "time" ) +type TERM interface { + Show(...interface{}) bool +} + +var STDIO TERM + var DisableLog = false var EnableDebug = false diff --git a/usr/librarys/code.js b/usr/librarys/code.js index 5b56ba9a..9d9f3b1d 100644 --- a/usr/librarys/code.js +++ b/usr/librarys/code.js @@ -1,609 +1,4 @@ -var page = Page({ - initComList: function(page, field, option, append, result) { - return - }, - - initScheduleText: function(page, field, option, append, result) { - option.ondaemon = function(msg) { - page.reload() - } - }, - initScheduleList: function(page, field, option) { - ctx.Runs(page, option) - }, - - initFlashText: function(page, field, option, append, result) { - option.ondaemon = function(msg) { - page.reload() - } - }, - initFlashList: function(page, field, option) { - option.dataset.flash_index = ctx.Search("flash_index") - option.ondaemon = function(msg) { - page.showFlashList(msg, field, option) - } - ctx.Runs(page, option) - }, - showFlashList: function(msg, field, option) { - var page = this - var result = field.querySelector("div.result") - - result.innerHTML = "" - ctx.Table(msg, function(tip) { - var ui = kit.AppendChild(result, [{"list": [ - {"text": [tip.text, "div", "detail"]}, - {"code": [tip.code, "result", "result"]}, - {"view": ["action"], "list": [ - {"button": ["查看详情", function(event) { - ctx.Search("flash_index", tip.index) - }]}, - {"button": ["执行代码", function(event) { - tip.code && ctx.Run(page, option.dataset, [tip.index, "run"], function(msg) { - ui.output.innerText = msg.result - }) - }]}, - {"button": ["清空结果", function(event) { - ui.output.innerText = "" - }]}, - ]}, - {"code": [tip.output, "output", "output"]}, - ]}]) - }) - }, - - initKitList: function(page, field, option, append, result) { - var ui = kit.AppendChild(field, [ - {"styles": { - "fieldset.KitList": { - "top": conf.toolkit_view.top, "left": conf.toolkit_view.left, - }, - "fieldset.KitList:hover, fieldset.KitList.max": { - "width": conf.toolkit_view.width, "height": conf.toolkit_view.height, - }, - }}, - {"type": "ul", "list": [ - {"fork": ["粘贴板", [ - {"leaf": ["+ 保存粘贴板(Ctrl+S)", function(event) { - console.log("save_txt") - }]}, - {"leaf": ["+ 添加粘贴板(Ctrl+Y)", function(event) { - console.log("create_txt") - }]}, - {"leaf": ["+ 快捷粘贴板(Ctrl+P)", function(event) { - console.log("quick_txt") - }]}, - ]]}, - {"fork": ["命令行", [ - {"leaf": ["+ 折叠命令行(Ctrl+Z)", function(event, target) { - target.className = page.conf.show_result? "": "stick" - page.showResult(page) - }]}, - {"leaf": ["+ 添加命令行(Ctrl+M)", function(event) { - page.addCmdList("cmd", page.conf.ncommand++) - }]}, - ]]}, - {"fork": ["工作流", [ - {"leaf": ["+ 刷新工作流(Ctrl+R)", function(event) { - console.log("refresh_fly") - }]}, - {"leaf": ["+ 添加工作流(Ctrl+T)", function(event) { - console.log("create_fly") - }]}, - {"leaf": ["+ 命名工作流", function(event) { - console.log("rename_fly") - }]}, - {"leaf": ["+ 删除工作流", function(event) { - console.log("remove_fly") - }]}, - ]]}, - ]}, - ]) - /* -
  • 命令行
    - -
  • -
  • 工作流
    - -
  • - */ - return - - text = JSON.parse(bench_data.clipstack || "[]") - for (var i = 0; i < text.length; i++) { - copy_to_clipboard(text[i]) - } - bench_data.board = bench_data.board || {} - - document.querySelectorAll("div.workflow").forEach(function(workflow) { - // 移动面板 - workflow.style.left = context.Cookie("toolkit_left") - workflow.style.top = context.Cookie("toolkit_top") - var moving = false, left0 = 0, top0 = 0, x0 = 0, y0 = 0 - workflow.onclick = function(event) { - if (event.target != workflow) { - return - } - moving = !moving - if (moving) { - left0 = workflow.offsetLeft - top0 = workflow.offsetTop - x0 = event.clientX - y0 = event.clientY - } - } - workflow.onmousemove = function(event) { - if (moving) { - workflow.style.left = (left0+(event.clientX-x0))+"px" - workflow.style.top = (top0+(event.clientY-y0))+"px" - context.Cookie("toolkit_left", workflow.style.left) - context.Cookie("toolkit_top", workflow.style.top) - } - } - - // 固定面板 - if (context.Cookie("toolkit_class")) { - workflow.className = context.Cookie("toolkit_class") - } - var head = workflow.querySelector("div") - head.onclick = function(event) { - head.dataset["show"] = !right(head.dataset["show"]) - workflow.className = right(head.dataset["show"])? "workflow max": "workflow" - context.Cookie("toolkit_class", workflow.className) - } - - // 折叠目录 - var toolkit = workflow.querySelector("ul.toolkit") - toolkit.querySelectorAll("li>div").forEach(function(menu) { - menu.onclick = function(event) { - menu.dataset["hide"] = !right(menu.dataset["hide"]) - menu.nextElementSibling.style.display = right(menu.dataset["hide"])? "none": "" - } - }) - - // 事件 - toolkit.querySelectorAll("li>ul>li").forEach(function(item) { - // if (bench_data.board["key"] == item.dataset["key"]) { - // // item.className = "stick" - // } - - item.onclick = function(event) { - var target = event.target - var data = item.dataset - switch (data["action"]) { - case "quick_txt": - code.quick_txt = !code.quick_txt - target.className= code.quick_txt? "stick": "" - break - case "copy_txt": - if (event.altKey) { - target.parentElement.removeChild(target) - return - } - if (event.shiftKey) { - var cmd = document.querySelector("form.option.cmd"+code.current_cmd+" input[name=cmd]") - cmd && (cmd.value += " "+text) - return - } - copy_to_clipboard(data["text"], true) - break - case "save_txt": - save_clipboard(item) - return - case "create_txt": - var text = prompt("text") - text && copy_to_clipboard(text) - return - case "refresh_fly": - location.reload() - return - case "create_fly": - context.Command(["sess", "bench", "create"], function(msg) { - context.Search("bench", msg.result[0]) - }) - return - case "rename_fly": - context.Command(["work", context.Search("bench"), "rename", prompt("name")], function() { - location.reload() - }) - return - case "remove_fly": - var b = "" - document.querySelectorAll("div.workflow>ul.toolkit>li>ul.fly>li[data-key]").forEach(function(item){ - if (!b && item.dataset["key"] != context.Search("bench")) { - b = item.dataset["key"] - } - }) - context.Search("bench", b) - context.Command(["work", context.Search("bench"), "delete"]) - return - } - - // 切换工作流 - if (data["key"] && data["key"] != context.Search("bench")) { - context.Search("bench", data["key"]) - return - } - - // 切换命令行 - var cmd = document.querySelector("form.option.cmd"+data["cmd"]+" input[name=cmd]") - cmd && cmd.focus() - } - }) - }) - return - }, - - initDirList: function(page, field, option, append, result) { - var history = [] - function change(value) { - return page.setCurrent(page, option, "dir", value) - } - function brow(value, dir, event) { - page.setCurrent(page, option, "dir", value) - page.setCurrent(page, option, "dir", dir) - } - return { - "button": ["root", "back"], "action": function(value) { - switch (value) { - case "back": history.length > -1 && change(history.pop() || "/"); break - case "root": change("/"); break - } - }, - "table": {"filename": function(value, key, row, index, event) { - var dir = option.dir.value - var file = dir + ((dir && !dir.endsWith("/"))? "/": "") + value - file.endsWith("/")? history.push(change(file)): brow(file, dir, event) - }}, - } - }, - initPodList: function(page, field, option, append, result) { - return {"button": ["local"], "action": function(value) { - value == "local" && (value = "''") - page.setCurrent(page, option, "pod", value) - }, "table": {"key": function(value) { - page.setCurrent(page, option, "pod", value) - }}} - }, - initCtxList: function(page, field, option, append, result) { - return {"button": ["ctx", "shy", "web", "mdb"], "action": function(value) { - page.setCurrent(page, option, "ctx", value) - }, "table": {"names": function(value) { - page.setCurrent(page, option, "ctx", value) - }}} - }, - setCurrent: function(page, option, type, value) { - option[type].value = ctx.Current(type, value) - page.History.add(type, value) - ctx.Runs(page, option) - return value - }, - - initCmdList: function(page, field, option, append, result) { - option.dataset["componet_name_alias"] = "cmd" - option.dataset["componet_name_order"] = 0 - - var cmd = option.querySelector("input[name=cmd]") - cmd.onkeyup = function(event) { - page.onCmdList(event, cmd, "input", field, option, append, result) - } - - var action = conf.bench_data.action - action && action["cmd"] && page.runCmdList(page, option, cmd, action["cmd"].cmd[1]) - - var max = 0 - for (var k in action) { - var order = parseInt(action[k].order) - order > max && (max = order) - } - - for (var i = 1; i <= max; i++) { - var ui = page.addCmdList("cmd", i) - action["cmd"+i] && page.runCmdList(page, ui.option, ui.cmd, action["cmd"+i].cmd[1]) - } - page.conf.ncommand = i - return - }, - runCmdList: function(page, option, target, value) { - target.value = value - target.dataset.history_last = kit.History.add("cmd", target.value) - ctx.Runs(page, option) - }, - getCmdList: function(input, step, cmd) { - var history = kit.History.get("cmd") - var length = history.length - var last = (parseInt(input.dataset["history_last"]||length)+step+length)%length - if (0 <= last && last < length) { - input.dataset["history_last"] = last - cmd = history[last].data - } - return cmd - }, - addCmdList: function(name, order) { - var page = this - var alias = name+order - var ui = kit.AppendChild(document.body, [{"view": ["CmdList", "fieldset"], "list": [ - {"text": [alias, "legend"]}, - {"view": ["option "+alias, "form", "", "option"], - "data": {"dataset": { - "componet_group": "index", "componet_name": name, "componet_name_alias": alias, "componet_name_order": order, - }}, - "list": [ - {"type": "input", "data": {"style": {"display": "none"}}}, - {"name": "cmd", "type": "input", "data": {"name": "cmd", "className": "cmd", "onkeyup": function(event) { - page.onCmdList(event, ui.cmd, "input", ui.field, ui.option, ui.append, ui.result) - }}}, - ] - }, - {"view": ["append "+alias, "table", "", "append"]}, - {"code": ["", "result", "result "+alias]}, - ]}]) - - kit.OrderForm(page, ui.field, ui.option, ui.append, ui.result) - kit.OrderTable(ui.append) - kit.OrderCode(ui.result) - ui.cmd.focus() - return ui - }, - delCmdList: function(name, order) { - var option = document.querySelector("form.option.cmd"+order) - option && document.body.removeChild(option.parentElement) - - for (;order < page.conf.ncommand; order++) { - var input = document.querySelector("form.option.cmd"+order+" input[name=cmd]") - if (input) { - input.focus() - return - } - } - for (;order >= 0; order--) { - var input = document.querySelector("form.option.cmd"+(order? order: "")+" input[name=cmd]") - page.conf.ncommand = order+1 - if (input) { - input.focus() - return - } - } - }, - onCmdList: function(event, target, action, field, option, append, result) { - var page = this - var order = option.dataset.componet_name_order - var prev_order = (parseInt(order)-1+page.conf.ncommand)%page.conf.ncommand||"" - var next_order = (parseInt(order)+1)%page.conf.ncommand||"" - - switch (action) { - case "input": - kit.History.add("key", (event.ctrlKey? "Control+": "")+(event.shiftKey? "Shift+": "")+event.key) - - if (event.key == "Escape") { - target.blur() - - } else if (event.key == "Enter") { - page.runCmdList(page, option, target, target.value) - - } else if (event.ctrlKey) { - switch (event.key) { - case "0": - var pre_pre = document.querySelector("code.result.cmd"+(event.shiftKey? next_order: prev_order)+" pre") - pre_pre && (target.value += pre_pre.innerText) - break - case "1": - case "2": - case "3": - case "4": - case "5": - case "6": - case "7": - case "8": - case "9": - if (code.quick_txt) { - var item = document.querySelectorAll("div.workflow>ul>li>ul.txt>li[data-text]") - target.value += item[parseInt(event.key)-1].dataset["text"] - } else { - var item = document.querySelectorAll("table.append.cmd"+(event.shiftKey? next_order: prev_order)+" td") - target.value += item[parseInt(event.key)-1].innerText - } - break - case "p": - target.value = page.getCmdList(target, -1, target.value) - break - case "n": - target.value = page.getCmdList(target, 1, target.value) - break - case "g": - var value = target.value.substr(0, target.selectionStart) - var last = parseInt(target.dataset.search_last || kit.History.get("cmd").length-1) - for (var i = last; i >= 0; i--) { - var cmd = kit.History.get("cmd", i).data - if (cmd.startsWith(value)) { - target.value = cmd - target.dataset.search_last = i-1 - target.setSelectionRange(value.length, cmd.length) - break - } - } - target.dataset.search_last = "" - break - - case "y": - case "v": - case "s": - case "t": - break - - case "a": - case "e": - case "f": - case "b": - case "h": - case "d": - break - case "k": - kit.DelText(target, target.selectionStart) - break - case "u": - kit.DelText(target, 0, target.selectionEnd) - break - case "w": - var start = target.selectionStart-2 - var end = target.selectionEnd-1 - for (var i = start; i >= 0; i--) { - if (target.value[end] == " " && target.value[i] != " ") { - break - } - if (target.value[end] != " " && target.value[i] == " ") { - break - } - } - kit.DelText(target, i+1, end-i) - break - - case "c": - append.innerHTML = "" - result.innerHTML = "" - break - case "r": - append.innerHTML = "" - result.innerHTML = "" - case "j": - page.runCmdList(page, option, target, target.value) - break - case "l": - window.scrollTo(0, option.parentElement.offsetTop) - break - case "m": - page.addCmdList("cmd", page.conf.ncommand++) - break - case "i": - var input = document.querySelector("form.option.cmd"+next_order+" input[name=cmd]") - input && input.focus() - break - case "o": - var input = document.querySelector("form.option.cmd"+prev_order+" input[name=cmd]") - input && input.focus() - break - case "x": - result.style.height = result.style.height? "": page.conf.hide_height - break - case "z": - result.style.height = result.style.height? "": page.conf.show_height - break - case "q": - page.delCmdList("cmd", order) - break - default: - return - } - } else { - if (kit.HitText(target, "jk")) { - kit.DelText(target, target.selectionStart-2, 2) - target.blur() - } - } - event.stopPropagation() - } - }, - - onaction: function(event, target, action) { - var page = this - switch (action) { - case "scroll": - break - case "keymap": - if (event.key == "Escape") { - - } else if (event.key == "Enter") { - - } else if (event.ctrlKey) { - switch (event.key) { - case "m": - page.addCmdList("cmd", page.conf.ncommand++) - break - case "z": - page.showResult(page) - break - case "0": - case "1": - case "2": - case "3": - case "4": - case "5": - case "6": - case "7": - case "8": - case "9": - document.querySelector("form.option.cmd"+(event.key||"")+" input[name=cmd]").focus() - break - } - } - } - }, - showResult: function(page, type) { - page.conf.show_result = !page.conf.show_result - document.querySelectorAll("body>fieldset>code.result>pre").forEach(function(result) { - result.style.height = (page.conf.show_result || result.innerText=="")? "": page.conf.show_height - }) - }, - init: function(exp) { - var page = this - var body = document.body - body.onkeyup = function(event) { - page.onaction(event, body, "keymap") - } - - document.querySelectorAll("body>fieldset").forEach(function(field) { - var option = field.querySelector("form.option") - var append = field.querySelector("table.append") - var result = field.querySelector("code.result pre") - kit.OrderForm(page, field, option, append, result) - append && kit.OrderTable(append) - result && kit.OrderCode(result) - - var init = page[field.dataset.init] - if (typeof init == "function") { - var conf = init(page, field, option, append, result) - if (conf && conf["button"]) { - var buttons = [] - conf.button.forEach(function(value, index) { - buttons.push({"button": [value, function(event) { - typeof conf["action"] == "function" && conf["action"](value, event) - }]}) - }) - kit.InsertChild(field, append, "div", buttons) - } - if (conf && conf["table"]) { - option.daemon_action = conf["table"] - ctx.Runs(page, option) - } - } - }) - }, - conf: { - scroll_x: 50, - scroll_y: 50, - - ncommand: 1, - show_result: true, - show_height: "30px", - hide_height: "14px", - - quick_txt: false, +page({ + init: function() { }, }) diff --git a/usr/librarys/context.js b/usr/librarys/context.js index b94e377e..a1c42771 100644 --- a/usr/librarys/context.js +++ b/usr/librarys/context.js @@ -5,7 +5,7 @@ ctx = context = { option[k] = dataset[k].split(",") } this.GET("", option, function(msg) { - msg = msg && msg[0] + msg[0] && (msg = msg[0]) // msg && (msg.__proto__ = (page || {})) msg.Result = msg.result? msg.result.join(""): "" msg.Results = function() { diff --git a/usr/wiki/自然/编程/终端工具链/context.md b/usr/wiki/自然/编程/终端工具链/context.md index 8d4608ec..248539fa 100644 --- a/usr/wiki/自然/编程/终端工具链/context.md +++ b/usr/wiki/自然/编程/终端工具链/context.md @@ -2,26 +2,271 @@ context是一种新的应用框架,通过模块化、集群化、自动化,实现软件的快速开发,快速共享,快速使用。 -### 下载安装 -在Linux或Mac上,可以直接用脚本下载,在Windows上,可以先安装[GitBash](https://www.git-scm.com/download/),然后下载。 +## 下载安装 +在Linux或Mac上,可以直接用脚本下载, +在Windows上,可以先安装[GitBash](https://www.git-scm.com/download/),然后在GitBash中执行命令下载。 ``` -$ mkdir context && cd context -$ curl https://shylinux.com/publish/boot.sh | bash -s install +$ curl https://shylinux.com/publish/boot.sh | bash -s install context ``` -### 使用方式 +install后面的参数context,就是指定的下载目录, +进入下载目录,可以看到的有六个文件。 + +在bin目录下,就是各种执行文件 + +- bin/bench,context的执行程序 +- bin/boot.sh,context的启动脚本 +- bin/node.sh,简化版的启动脚本 + +context内部实现了语法解析,通过自定义的脚本语言,实现功能的灵活控制。 + +在etc目录下,就是context执行过程中用到的脚本。 + +- etc/init.shy,启动时加载的脚本 +- etc/exit.shy,结束时运行的脚本 +- etc/common.shy,init.shy调用到的脚本 + +## 使用方式 context内部实现了很多功能模块,每个模块下有很多命令,每条命令就是一种应用。 -#### 命令模式 +context的使用方式有很多种, + +- 可以直接调用,像Shell一样,去解析一条命令 +- 可以启动cli服务,像MySQL一样,交互式使用格式化命令 +- 可以启动web服务,像LabView一样,可以自定义各种图形界面 +- 可以自动组网,将任意台设备组合在一起,实现分布式应用 +- 可以自动建群,在群聊场景中,实现多用户、多会话、多任务、多设备的使用 + +### 命令模式 +如果只是使用一条命令,或是写在脚本文件中,可以使用这种方式。 + +例如,dir命令就是查看目录, ``` $ bin/bench dir +time size line filename +2019-06-16 10:35:18 324 11 common.shy +2019-06-16 10:35:18 201 9 exit.shy +2019-06-16 10:35:18 261 13 init.shy +``` + +还可以加更多参数,dir_deep递归查询目录,dir_type文件类型过滤,dir_sort输出表排序。 +``` +$ bin/bench dir ../ dir_deep dir_type file dir_sort line int_r +time size line filename +2019-06-16 10:22:52 13256968 91314 bench +2019-06-16 11:10:16 1535 66 boot.sh +2019-06-16 11:10:16 613 31 node.sh +2019-06-16 11:10:16 261 13 init.shy +2019-06-16 11:10:16 324 11 common.shy +2019-06-16 11:10:16 201 9 exit.shy ``` -#### 交互模式 +### 交互模式 + +启动服务,可以提供更丰富的命令与环境。 +``` +$ bin/bench +0[11:35:46]ssh> dir +time size line filename +2019-06-16 11:35:06 160 3 log/ +2019-06-16 11:35:06 96 1 run/ +2019-06-16 11:35:44 192 4 tmp/ +1[11:35:46]ssh> +``` + +如果集中管理,命令越多,系统只会越复杂,学习成本越高,使用越低效,开发越困难。 + +所以通过模块化,分而治之,更高效的管理丰富的命令。 + +context命令就是用来管理模块,没有参数时,直接查看当前模块的信息。 + +如下,第二行是当前模块,第一行是当前模块的父模块,其它行都是当前模块的子模块。 + +``` +1[11:39:01]ssh> context +names ctx msg status stream helps +ctx 0 start shy 模块中心 +ssh ctx 10 begin ctx.nfs.file3 集群中心 +``` + +context第一个参数,可以指定当前模块, +如下,切换到nfs模块,然后查看各种IO模块, +切换到ctx根模块,查看所有模块。 +``` +2[11:43:57]ssh> context nfs + +3[11:43:58]nfs> context +names ctx msg status stream helps +ctx 0 start shy 模块中心 +nfs ctx 9 begin 存储中心 +stdio nfs 1174 start stdio scan stdio + +4[11:44:22]ssh> context ctx + +5[11:45:17]ctx> context +names ctx msg status stream helps +ctx 0 start shy 模块中心 +aaa ctx 3 begin 认证中心 +cli ctx 4 begin 管理中心 +gdb ctx 232 start 调试中心 +lex ctx 6 begin 词法中心 +log ctx 31 start bench 日志中心 +mdb ctx 8 begin 数据中心 +nfs ctx 9 begin 存储中心 +ssh ctx 10 begin 集群中心 +tcp ctx 11 begin 网络中心 +web ctx 1094 start :9094 应用中心 +yac ctx 13 begin 35,14,23 语法中心 +shy cli 1171 start engine shell +matrix1 lex 34 start 76,28,2 matrix +stdio nfs 1174 start stdio scan stdio +chat web 14 begin 会议中心 +code web 15 begin 代码中心 +wiki web 16 begin 文档中心 +engine yac 1173 start stdio parse + +``` + +command命令,就是用来管理当前模块的命令, +``` +17[11:52:02]nfs> context nfs + +17[11:52:02]nfs> command +key name +_init _init +action action cmd +copy copy to from +dir dir [path [fields...]] +export export filename +git git sum +hash hash filename +import import filename [index] +json json str +load load file [buf_size [pos]] +open open file +path path filename +printf printf arg +prompt prompt arg +pwd pwd [all] | [[index] path] +read read [buf_size [pos]] +remote remote listen|dial args... +save save file string... +scan scan file name +send send [file] args... +temp temp data +term term action args... +trash trash file +write write string [pos] + +``` + +help子命令,查看命令帮助信息。 +``` +18[11:59:19]nfs> command help dir +dir: dir [path [fields...]] + 查看目录, path: 路径, fields...: 查询字段, time|type|full|path|tree|filename|size|line|hash + dir_deep: 递归查询 + dir_type both|file|dir|all: 文件类型 + dir_reg reg: 正则表达式 + dir_sort field order: 排序 +``` + + +### 集群模式 + +context提供自动化集群的功能,可以自动组网、自动认证。从而快速实现多台设备的协同工作。 + +#### 启动服务节点 +``` +$ bin/boot.sh +0[11:35:12]ssh> +``` + +#### 启动工作节点 + +新打开一个终端,启动工作节点,执行remote命令,查看上级节点, +``` +$ bin/boot.sh create app/demo +0[15:15:30]ssh> remote +key type module create_time +mac master ctx.nfs.file3 2019-06-16 15:15:23 +``` + +回到服务节点终端,执行remote命令,可以查看到所有远程节点。 +``` +2[15:15:31]ssh> remote +key type module create_time +com master ctx.nfs.file4 2019-06-16 14:25:10 +demo worker ctx.nfs.file7 2019-06-16 15:15:23 +``` + +默认配置中,子节点信任父,所以父节点可以调用子节点的命令。还有更复杂的认证机制,可以灵活配置。 + +远程命令和本地命令一样,没有任何区别。如下调用demo节点的pwd命令。还支持更复杂的多节点命令,可以更快速的同时管理多台设备。 +``` +2[15:15:31]ssh> remote demo pwd +/Users/shaoying/context/app/demo/var +``` + +#### 启动分机节点 + +在服务节点的终端,查看服务地址 +``` +3[15:49:00]ssh> web.brow +index site +0 http://192.168.199.139:9094 +``` + +同样,在另一台设备上下载context,然后启动服务节点。 +通过环境变量ctx_dev指定上级节点。 +``` +$ ctx_dev="http://192.168.199.139:9094" bin/boot.sh +0[15:49:00]ssh> remote +key type module create_time +mac master ctx.nfs.file3 2019-06-16 15:15:23 +``` + +回到服务节点终端,执行remote命令,可以查看到新添加了一个服务子节点。 +``` +2[15:15:31]ssh> remote +key type module create_time +com master ctx.nfs.file4 2019-06-16 14:25:10 +demo worker ctx.nfs.file7 2019-06-16 15:15:23 +sub server ctx.nfs.file8 2019-06-16 16:15:23 +``` + +同样可以远程调用命令。 +``` +2[15:15:31]ssh> remote sub pwd +/Users/shaoying/context/app/sub/var +``` + +### 开源模式 + +context是一种通用的应用框架,可以快速开发出各种工具。 +``` +2[15:15:31]ssh> project init +done +2[15:15:31]ssh> project init +``` + +### 网页模式 +### 工具链 +### 知识库 +### 信息流 +``` +$ bin/bench +19[11:59:19]nfs> upgrade portal +hash file +ef1998b38af0888cb56dd5e1448a68ad usr/template.tar.gz +6_043a93fa03273744be42c7ab898b2 usr/librarys.tar.gz + +19[11:59:19]nfs> upgrade portal + +``` -#### 集群模式 #### 完整版 如果对源码有兴趣,使用更丰富的功能,可以直接下载源码, @@ -109,103 +354,6 @@ index name ip mask hard 5 en0 192.168.0.106 24 c4:b3:01:cf:0b:51 ``` -### 组建集群 - -context不仅只是一个shell,还可以用来组建集群。 - -#### 启动服务节点 - -启动服务节点,使用脚本boot.sh, -与node.sh不同的是,boot.sh启动的context, -会启动web模块监听9094端口,会启动ssh模块监听9090端口。 -``` -$ cd context -$ bin/boot.sh -0[11:23:03]ssh> -``` - -#### 启动工作节点 -启动工作节点,使用脚本node.sh, -它启动的context,会主动连接本地9090端口,向服务节点注册自己。 - -如下,新打开一个终端,调用boot.sh,创建并启动服务节点demo。 -``` -$ cd context -$ bin/node.sh create app/demo -0[11:23:03]ssh> -``` - -如下,再打开一个终端,调用boot.sh,创建并启动服务节点led。 -``` -$ cd context -$ bin/node.sh create app/led -0[11:23:03]ssh> -``` - -#### 调用远程命令 -如下回到服务节点终端,执行remote命令,可以查看到所有远程节点。 -``` -22[11:35:12]ssh> remote -key create_time module name type -com 2019-05-09 20:57:21 ctx.nfs.file4 com master -led 2019-05-09 20:59:28 ctx.nfs.file5 led worker -demo 2019-05-09 20:59:28 ctx.nfs.file5 demo worker -``` - -远程命令只需要在命令前加上节点名与冒号即可。 - -如下,远程调用led节点的命令。 -``` -24[11:41:15]ssh> led:pwd -/Users/shaoying/context/app/led/var -``` - -如下,远程调用demo节点的命令。 -``` -24[11:41:15]ssh> demo:pwd -/Users/shaoying/context/app/demo/var -``` - -如下,远程调用所有子节点的命令。 -``` -29[11:44:09]ssh> *:pwd -/Users/shaoying/context/app/led/var - -/Users/shaoying/context/app/demo/var -``` - -#### 启动分机服务 - -boot.sh不仅可以用来启动本地服务,还可以将不同的主机组建在一起。 - -在另外一台计算机上,重新下载安装一下context,然后启动服务节点。 - -其中环境变量ctx_dev,用来指定上级服务节点。 - -``` -$ cd context -$ ctx_dev=http://192.168.0.106:9094 boot.sh -0[11:53:11]ssh> -``` - -回到原主机的服务节点终端, -使用remote命令,可以查看到新加的从机节点。 -``` -30[11:55:38]ssh> remote -key create_time module name type -com 2019-05-09 20:57:21 ctx.nfs.file4 com master -mac 2019-05-10 10:53:00 ctx.nfs.file13 mac server -led 2019-05-09 20:59:28 ctx.nfs.file5 led worker -demo 2019-05-09 20:59:28 ctx.nfs.file5 demo worker -``` - -当然,也可以在本地启动多个服务节点,根据ctx_dev指定不同的上级节点,可以级联,也可以并联。 -``` -$ cd context -$ ctx_dev=http://localhost:9094 boot.sh create app/sub -``` -***注意,不指定ctx_dev时,默认连接 https://shylinux.com ,如果不信任此主机,记得设置ctx_dev*** - ### 网页服务 下载完整版的context,启动的服务节点,就会带有前端网页服务。