diff --git a/bin/boot.sh b/bin/boot.sh
index eb5d3fb0..a62d17e9 100755
--- a/bin/boot.sh
+++ b/bin/boot.sh
@@ -48,12 +48,13 @@ install() {
echo
echo
- curl -o ${ctx_app} "$ctx_dev/publish/${ctx_app}?GOOS=$GOOS&GOARCH=$GOARCH" && chmod a+x ${ctx_app} || return
+ wget -O ${ctx_app} "$ctx_dev/publish/bench?GOOS=$GOOS&GOARCH=$GOARCH" && chmod a+x ${ctx_app} || return
target=install && [ -n "$1" ] && target=$1
${md5} ${ctx_app} && ./${ctx_app} upgrade ${target} || return
- mv ${ctx_app} bin/${ctx_app} && bin/boot.sh
+ mv ${ctx_app} bin/${ctx_app}
+ # && bin/boot.sh
}
main() {
trap HUP hup
diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go
index 3a4d465d..74056345 100644
--- a/src/contexts/cli/cli.go
+++ b/src/contexts/cli/cli.go
@@ -69,18 +69,38 @@ func format(m *ctx.Message, out *bytes.Buffer) {
}
m.Table()
case "cut":
- c := byte(kit.Select(" ", m.Optionv("cmd_parse"), 2)[0])
+ c := byte(kit.Select(" ", m.Optionv("cmd_parse"), 1)[0])
bio := bufio.NewScanner(out)
+ pos := []int{}
heads := []string{}
if h := kit.Select("", m.Optionv("cmd_parse"), 3); h != "" {
heads = strings.Split(h, " ")
} else if bio.Scan() {
- heads = kit.Split(bio.Text(), c, kit.Int(kit.Select("-1", m.Optionv("cmd_parse"), 1)))
+ h := bio.Text()
+ v := kit.Trans(m.Optionv("cmd_headers"))
+ for i := 0; i < len(v)-1; i += 2 {
+ h = strings.Replace(h, v[i], v[i+1], 1)
+ }
+
+ heads = kit.Split(h, c, kit.Int(kit.Select("-1", m.Optionv("cmd_parse"), 2)))
+ for _, v := range heads {
+ pos = append(pos, strings.Index(h, v))
+ }
}
for bio.Scan() {
+ if len(pos) > 0 {
+ for i, v := range pos {
+ if i == len(pos)-1 {
+ m.Add("append", heads[i], bio.Text()[v:])
+ } else {
+ m.Add("append", heads[i], bio.Text()[v:pos[i+1]])
+ }
+ }
+ continue
+ }
for i, v := range kit.Split(bio.Text(), c, len(heads)) {
m.Add("append", heads[i], v)
}
@@ -306,12 +326,13 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
"cmd_timeout: 命令超时",
"cmd_active(true/false): 是否交互",
"cmd_daemon(true/false): 是否守护",
- "cmd_dir: 工作目录",
"cmd_env key value: 环境变量",
+ "cmd_dir: 工作目录",
"cmd_log: 输出日志",
- "cmd_temp arg...: 缓存结果",
- "cmd_parse format|json|csv|cli|cut [count sep]: 解析结果",
"cmd_error: 输出错误",
+ "cmd_temp arg...: 缓存结果",
+ "cmd_parse format|json|csv|cli|cut [count sep headers]: 解析结果",
+ "cmd_headers",
}, Form: map[string]int{
"cmd_timeout": 1,
"cmd_active": 1,
@@ -323,6 +344,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
"cmd_parse": 4,
"cmd_error": 0,
"cmd_select": -1,
+ "cmd_headers": 2,
"app_log": 1,
}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
// 管道参数
@@ -865,7 +887,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
if len(arg) == 1 {
m.Cmdy("nfs.git", "sum", "-n", 20)
} else {
- m.Cmdy("nfs.git", "sum", "-n", arg[1:])
+ m.Cmdy("nfs.git", "sum", "--reverse", "--since", arg[1:])
}
case "trends":
@@ -920,7 +942,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
// 编译项目
if m.Cmdy("cli.compile", ""); m.Has("bin") {
- target := path.Join(kit.Select(os.Getenv("GOBIN"), ""), m.Conf("compile", "name"))
+ target := path.Join(kit.Select(os.Getenv("GOBIN"), ""), m.Conf("runtime", "boot.ctx_app"))
os.Remove(target)
m.Append("bin", m.Cmdx("nfs.copy", target, m.Append("bin")))
os.Chmod(target, 0777)
diff --git a/src/contexts/cli/version.go b/src/contexts/cli/version.go
index e58fba82..b9074099 100644
--- a/src/contexts/cli/version.go
+++ b/src/contexts/cli/version.go
@@ -7,5 +7,5 @@ var version = struct {
self int
}{
[]string{"2017-11-01 01:02:03", "2019-07-13 18:02:21"},
- `2019-11-01 14:34:16`, `mac`, 657,
+ `2019-11-03 00:13:51`, `mac`, 659,
}
diff --git a/src/contexts/ctx/cgi.go b/src/contexts/ctx/cgi.go
index ee5ddb60..96e79a98 100644
--- a/src/contexts/ctx/cgi.go
+++ b/src/contexts/ctx/cgi.go
@@ -109,3 +109,8 @@ func ExecuteFile(m *Message, w io.Writer, p string) error {
tmpl.ParseGlob(p)
return tmpl.ExecuteTemplate(w, path.Base(p), m)
}
+func ExecuteStr(m *Message, w io.Writer, p string) error {
+ tmpl := template.New("render").Funcs(CGI)
+ tmpl, _ = tmpl.Parse(p)
+ return tmpl.Execute(w, m)
+}
diff --git a/src/contexts/ctx/type.go b/src/contexts/ctx/type.go
index 78f4cb82..790dc7df 100644
--- a/src/contexts/ctx/type.go
+++ b/src/contexts/ctx/type.go
@@ -250,8 +250,15 @@ func (m *Message) Push(str string, arg ...interface{}) *Message {
}
func (m *Message) Sort(key string, arg ...string) *Message {
cmp := "str"
- if len(arg) > 0 {
+ if len(arg) > 0 && arg[0] != "" {
cmp = arg[0]
+ } else {
+ cmp = "int"
+ for _, v := range m.Meta[key] {
+ if _, e := strconv.Atoi(v); e != nil {
+ cmp = "str"
+ }
+ }
}
number := map[int]int{}
@@ -274,7 +281,7 @@ func (m *Message) Sort(key string, arg ...string) *Message {
for j := i + 1; j < len(table); j++ {
result := false
switch cmp {
- case "str":
+ case "", "str":
if table[i][key] > table[j][key] {
result = true
}
@@ -306,6 +313,106 @@ func (m *Message) Sort(key string, arg ...string) *Message {
}
return m
}
+func (m *Message) Limit(offset, limit int) *Message {
+ l := len(m.Meta[m.Meta["append"][0]])
+ if offset < 0 {
+ offset = 0
+ }
+ if offset > l {
+ offset = l
+ }
+ if offset+limit > l {
+ limit = l - offset
+ }
+ for _, k := range m.Meta["append"] {
+ m.Meta[k] = m.Meta[k][offset : offset+limit]
+ }
+ return m
+}
+func (m *Message) Filter(value string) *Message {
+
+ return m
+}
+func (m *Message) Group(method string, args ...string) *Message {
+
+ nrow := len(m.Meta[m.Meta["append"][0]])
+
+ keys := map[string]bool{}
+ for _, v := range args {
+ keys[v] = true
+ }
+
+ counts := []int{}
+ mis := map[int]bool{}
+ for i := 0; i < nrow; i++ {
+ counts = append(counts, 1)
+ if mis[i] {
+ continue
+ }
+ next:
+ for j := i + 1; j < nrow; j++ {
+ if mis[j] {
+ continue
+ }
+ for key := range keys {
+ if m.Meta[key][i] != m.Meta[key][j] {
+ continue next
+ }
+ }
+ for _, k := range m.Meta["append"] {
+ if !keys[k] {
+ switch method {
+ case "sum", "avg":
+ v1, e1 := strconv.Atoi(m.Meta[k][i])
+ v2, e2 := strconv.Atoi(m.Meta[k][j])
+ if e1 == nil && e2 == nil {
+ m.Meta[k][i] = fmt.Sprintf("%d", v1+v2)
+ }
+ }
+ }
+ }
+ mis[j] = true
+ counts[i]++
+ }
+ }
+
+ for i := 0; i < nrow; i++ {
+ for _, k := range m.Meta["append"] {
+ if !keys[k] {
+ switch method {
+ case "avg":
+ if v1, e1 := strconv.Atoi(m.Meta[k][i]); e1 == nil {
+ m.Meta[k][i] = strconv.Itoa(v1 / counts[i])
+ }
+ }
+ }
+ }
+ }
+ for i := 0; i < nrow; i++ {
+ m.Push("_counts", counts[i])
+ }
+
+ for i := 0; i < nrow; i++ {
+ if mis[i] {
+ for j := i + 1; j < nrow; j++ {
+ if !mis[j] {
+ for _, k := range m.Meta["append"] {
+ m.Meta[k][i] = m.Meta[k][j]
+ }
+ mis[i], mis[j] = false, true
+ break
+ }
+ }
+ }
+ if mis[i] {
+ for _, k := range m.Meta["append"] {
+ m.Meta[k] = m.Meta[k][0:i]
+ }
+ break
+ }
+ }
+ return m
+}
func (m *Message) Table(cbs ...interface{}) *Message {
if len(m.Meta["append"]) == 0 {
return m
diff --git a/src/contexts/yac/yac.go b/src/contexts/yac/yac.go
index 2f60f17c..b527f852 100644
--- a/src/contexts/yac/yac.go
+++ b/src/contexts/yac/yac.go
@@ -1135,7 +1135,9 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
}
args := arg[i : j+1]
if arg[i] == "feature" {
- feature[arg[i+1]] = arg[i+2]
+ for k := 2; k < len(args); k++ {
+ feature[args[1]] = kit.Merge(feature[args[1]], args[k])
+ }
} else if arg[i] == "exports" {
for k := 1; k < len(args); k += 1 {
@@ -1147,14 +1149,7 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
"value": kit.Select("", args, 1),
}
for k := 2; k < len(args)-1; k += 2 {
- switch val := input[args[k]].(type) {
- case nil:
- input[args[k]] = args[k+1]
- case string:
- input[args[k]] = []interface{}{input[args[k]], args[k+1]}
- case []interface{}:
- input[args[k]] = append(val, args[k+1])
- }
+ input[args[k]] = kit.Merge(input[args[k]], args[k+1])
}
inputs = append(inputs, input)
}
@@ -1170,6 +1165,13 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
}
}
+ ctx := m.Cap("module")
+ if strings.Contains(cmd, ".") {
+ cs := strings.Split(cmd, ".")
+ ctx = strings.Join(cs[:len(cs)-1], ".")
+ cmd = cs[len(cs)-1]
+ }
+
m.Confv("_index", []interface{}{-2}, map[string]interface{}{
"name": kit.Select("", arg, 1),
"help": kit.Select("", arg, 2),
@@ -1177,7 +1179,7 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
"init": init,
"type": right,
- "ctx": m.Cap("module"),
+ "ctx": ctx,
"cmd": cmd,
"args": args,
"inputs": inputs,
diff --git a/src/examples/code/code.go b/src/examples/code/code.go
index ab973cdf..c5e7e421 100644
--- a/src/examples/code/code.go
+++ b/src/examples/code/code.go
@@ -3,29 +3,302 @@ package code
import (
"contexts/ctx"
"contexts/web"
+ "path"
+ "regexp"
+ "strings"
+ "time"
+ "toolkit"
)
var Index = &ctx.Context{Name: "code", Help: "代码中心",
- Caches: map[string]*ctx.Cache{},
- Configs: map[string]*ctx.Config{},
+ Caches: map[string]*ctx.Cache{},
+ Configs: map[string]*ctx.Config{
+ "docker": {Name: "docker", Help: "容器", Value: map[string]interface{}{
+ "shy": `
+FROM {{options . "base"}}
+
+WORKDIR /home/{{options . "user"}}/context
+Env ctx_dev {{options . "host"}}
+
+RUN wget -q -O - $ctx_dev/publish/boot.sh | sh -s install
+
+CMD sh bin/boot.sh
+
+`,
+ }},
+ },
Commands: map[string]*ctx.Command{
- "zsh": &ctx.Command{Name: "zsh", Help: "终端", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
- m.Echo("zsh")
+ "zsh": {Name: "zsh dir grep key [split reg fields] [filter reg fields] [order key method] [group keys method] [sort keys method]",
+ Form: map[string]int{"split": 2, "filter": 2, "order": 2, "group": 2, "sort": 2},
+ Help: "终端", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
+ p, arg := kit.Select(".", arg[0]), arg[1:]
+ switch arg[0] {
+ case "install":
+ m.Cmd("cli.system", "apk", "add", arg[1])
+
+ case "list":
+ m.Cmdy("nfs.dir", p, "time", "size", "path")
+
+ case "find":
+ m.Cmdy("cli.system", "find", p, "-name", arg[1])
+
+ case "grep":
+ if m.Options("split") {
+ re, _ := regexp.Compile(kit.Select("", m.Optionv("split"), 0))
+ fields := map[string]bool{}
+ for _, v := range strings.Split(kit.Select("", m.Optionv("split"), 1), " ") {
+ if v != "" {
+ fields[v] = true
+ }
+ }
+
+ m.Cmd("cli.system", "grep", "-rn", arg[1], p, "cmd_parse", "cut", ":", "3", "path line text").Table(func(index int, line map[string]string) {
+ if ls := re.FindAllStringSubmatch(line["text"], -1); len(ls) > 0 {
+ m.Push("path", line["path"])
+ m.Push("line", line["line"])
+ for _, v := range ls {
+ if len(fields) == 0 || fields[v[1]] {
+ m.Push(v[1], v[2])
+ }
+ }
+ }
+ })
+ m.Table()
+ } else {
+ m.Cmdy("cli.system", "grep", "-rn", arg[1], p, "cmd_parse", "cut", ":", "3", "path line text")
+ }
+
+ if m.Has("filter") {
+ m.Filter(m.Option("filter"))
+ }
+ if m.Has("order") {
+ m.Sort(kit.Select("", m.Optionv("order"), 0), kit.Select("", m.Optionv("order"), 1))
+ }
+ if m.Has("group") {
+ m.Group(kit.Select("sum", m.Optionv("group"), 1), strings.Split(kit.Select("", m.Option("group"), 0), " ")...)
+ }
+ if m.Has("sort") {
+ m.Sort(kit.Select("", m.Optionv("sort"), 0), kit.Select("", m.Optionv("sort"), 1))
+ }
+
+ case "tail":
+ m.Cmdy("cli.system", "tail", path.Join(p, arg[1]))
+
+ }
+ return
+ }},
+ "tmux": {Name: "tmux [session [window [pane cmd]]]", Help: "窗口", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
+ prefix := []string{"cli.system", "tmux"}
+ if len(arg) > 1 {
+ switch arg[1] {
+ case "modify":
+ switch arg[2] {
+ case "session":
+ m.Cmdy(prefix, "rename-session", "-t", arg[0], arg[3])
+ case "window":
+ m.Cmdy(prefix, "rename-window", "-t", arg[0], arg[3])
+ }
+ return
+ }
+ }
+ // 查看会话
+ if m.Cmdy(prefix, "list-session", "-F", "#{session_id},#{session_name},#{session_windows},#{session_height},#{session_width}",
+ "cmd_parse", "cut", ",", "5", "id session windows height width"); len(arg) == 0 {
+ return
+ }
+
+ // 创建会话
+ if arg[0] != "" && !kit.Contains(m.Meta["session"], arg[0]) {
+ m.Cmdy(prefix, "new-session", "-ds", arg[0])
+ }
+ m.Set("append").Set("result")
+
+ // 查看窗口
+ if m.Cmdy(prefix, "list-windows", "-t", arg[0], "-F", "#{window_id},#{window_name},#{window_panes},#{window_height},#{window_width}",
+ "cmd_parse", "cut", ",", "5", "id window panes height width"); len(arg) == 1 {
+ return
+ }
+
+ // 创建窗口
+ if arg[1] != "" && !kit.Contains(m.Meta["window"], arg[1]) {
+ m.Cmdy(prefix, "new-window", "-dt", arg[0], "-n", arg[1])
+ }
+ m.Set("append").Set("result")
+
+ // 查看面板
+ if len(arg) == 2 {
+ m.Cmdy(prefix, "list-panes", "-t", arg[0]+":"+arg[1], "-F", "#{pane_id},#{pane_index},#{pane_tty},#{pane_height},#{pane_width}",
+ "cmd_parse", "cut", ",", "5", "id pane tty height width")
+ return
+ }
+
+ // 执行命令
+ target := arg[0] + ":" + arg[1] + "." + arg[2]
+ if len(arg) > 3 {
+ if len(arg) > 5 {
+ switch arg[5] {
+ case "modify":
+ switch arg[6] {
+ case "text":
+ m.Cmdy(prefix, "set-buffer", "-b", arg[4], arg[7])
+ }
+ return
+ }
+ }
+ switch arg[3] {
+ case "buffer":
+ if len(arg) > 5 {
+ m.Cmdy(prefix, "set-buffer", "-b", arg[4], arg[5])
+ }
+ if len(arg) > 4 {
+ m.Cmdy(prefix, "show-buffer", "-b", arg[4])
+ return
+ }
+ m.Cmdy(prefix, "list-buffers", "cmd_parse", "cut", ": ", "3", "buffer size text")
+ for i, v := range m.Meta["text"] {
+ if i < 3 {
+ m.Meta["text"][i] = m.Cmdx(prefix, "show-buffer", "-b", m.Meta["buffer"][i])
+ } else {
+ m.Meta["text"][i] = v[2 : len(v)-1]
+ }
+ }
+ return
+ case "layout":
+ default:
+ m.Cmdy(prefix, "send-keys", "-t", target, strings.Join(arg[3:], " "), "Enter")
+ time.Sleep(1 * time.Second)
+ }
+ }
+
+ // 查看终端
+ m.Echo(strings.TrimSpace(m.Cmdx(prefix, "capture-pane", "-pt", target)))
return
}},
- "tmux": &ctx.Command{Name: "tmux", Help: "窗口", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
+ "docker": {Name: "docker", Help: "容器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
+ prefix := []string{"cli.system", "docker"}
+ switch arg[0] {
+ case "image":
+ prefix = append(prefix, "image")
+ pos := kit.Select("shy", arg, 1)
+ tag := kit.Select("2.1", arg, 2)
+
+ // 查看镜像
+ if m.Cmdy(prefix, "ls", "cmd_parse", "cut", "cmd_headers", "IMAGE ID", "IMAGE_ID"); len(arg) == 1 {
+ return
+ } else if i := kit.IndexOf(m.Meta["IMAGE_ID"], arg[1]); i > -1 {
+ arg, pos, tag = arg[2:], strings.TrimSpace(m.Meta["REPOSITORY"][i]), strings.TrimSpace(m.Meta["TAG"][i])
+ } else {
+ arg = arg[3:]
+ }
+
+ // 拉取镜像
+ if len(arg) == 0 {
+ m.Cmdy(prefix, "pull", pos+":"+tag)
+ return
+ }
+
+ switch arg[0] {
+ // 启动容器
+ case "运行":
+ m.Set("append").Set("result")
+ m.Cmdy("cli.system", "docker", "run", "-dt", pos+":"+tag)
+ return
+ // 清理镜像
+ case "清理":
+ m.Cmd(prefix, "prune", "-f")
+
+ // 删除镜像
+ case "delete":
+ m.Cmd(prefix, "rm", pos+":"+tag)
+
+ // 创建镜像
+ default:
+ m.Option("base", pos+":"+tag)
+ m.Option("name", arg[0]+":"+kit.Select("2.1", arg, 1))
+ m.Option("host", "http://"+m.Conf("runtime", "boot.hostname")+".local:9095")
+ m.Option("user", kit.Select("shy", arg, 2))
+ m.Option("file", "etc/Dockerfile")
+
+ if f, _, e := kit.Create(m.Option("file")); m.Assert(e) {
+ defer f.Close()
+ if m.Assert(ctx.ExecuteStr(m, f, m.Conf("docker", arg[0]))) {
+ m.Cmdy("cli.system", "docker", "image", "build", "-f", m.Option("file"), "-t", m.Option("name"), ".")
+ }
+ }
+ }
+
+ case "container":
+ prefix = append(prefix, "container")
+ if len(arg) > 1 {
+ switch arg[2] {
+ case "进入":
+ m.Cmdy("cli.system", "tmux", "new-window", "-dPF", "#{session_name}:#{window_name}.1", "docker exec -it "+arg[1]+" sh")
+ return
+
+ case "停止":
+ m.Cmd(prefix, "stop", arg[1])
+
+ case "启动":
+ m.Cmd(prefix, "start", arg[1])
+
+ case "重启":
+ m.Cmd(prefix, "restart", arg[1])
+
+ case "清理":
+ m.Cmd(prefix, "prune", "-f")
+
+ case "modify":
+ switch arg[3] {
+ case "NAMES":
+ m.Cmd(prefix, "rename", arg[1], arg[4:])
+ }
+
+ // 删除容器
+ case "delete":
+ m.Cmd(prefix, "rm", arg[1])
+
+ default:
+ if len(arg) > 2 {
+ m.Cmdy(prefix, "exec", arg[1], arg[2:])
+ } else {
+ m.Cmdy(prefix, "inspect", arg[1])
+ }
+ return
+ }
+ }
+ m.Cmdy(prefix, "ls", "-a", "cmd_parse", "cut", "cmd_headers", "CONTAINER ID", "CONTAINER_ID")
+
+ case "network":
+ if len(arg) == 1 {
+ m.Cmdy("cli.system", "docker", "network", "ls", "cmd_parse", "cut", "cmd_headers", "NETWORK ID", "NETWORK_ID")
+ break
+ }
+
+ kit.Map(kit.Chain(kit.UnMarshal(m.Cmdx("cli.system", "docker", "network", "inspect", arg[1])), "0.Containers"), "", func(key string, value map[string]interface{}) {
+ m.Push("CONTAINER_ID", key[:12])
+ m.Push("name", value["Name"])
+ m.Push("IPv4", value["IPv4Address"])
+ m.Push("IPv6", value["IPV4Address"])
+ m.Push("Mac", value["MacAddress"])
+ })
+ m.Table()
+
+ case "volume":
+ if len(arg) == 1 {
+ m.Cmdy("cli.system", "docker", "volume", "ls", "cmd_parse", "cut", "cmd_headers", "VOLUME NAME", "VOLUME_NAME")
+ break
+ }
+
+ default:
+ m.Cmdy("cli.system", "docker", arg)
+ }
+ return
+ }},
+ "git": {Name: "git", Help: "版本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
m.Echo("git")
return
}},
- "docker": &ctx.Command{Name: "docker", Help: "容器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
- m.Echo("docker")
- return
- }},
- "git": &ctx.Command{Name: "git", Help: "版本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
- m.Echo("git")
- return
- }},
- "vim": &ctx.Command{Name: "vim", Help: "编辑器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
+ "vim": {Name: "vim", Help: "编辑器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
m.Echo("vim")
return
}},
diff --git a/src/plugin/docker/index.css b/src/plugin/docker/index.css
new file mode 100644
index 00000000..928bca5f
--- /dev/null
+++ b/src/plugin/docker/index.css
@@ -0,0 +1,3 @@
+fieldset.item.docker div.output {
+}
+
diff --git a/src/plugin/docker/index.go b/src/plugin/docker/index.go
new file mode 100644
index 00000000..0e326b29
--- /dev/null
+++ b/src/plugin/docker/index.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "contexts/cli"
+ "contexts/ctx"
+ "toolkit"
+
+ "fmt"
+ "os"
+)
+
+var Index = &ctx.Context{Name: `docker`, Help: `plugin`,
+ Caches: map[string]*ctx.Cache{},
+ Configs: map[string]*ctx.Config{
+ "_index": &ctx.Config{Name: "index", Value: []interface{}{
+ map[string]interface{}{"name": "demo", "help": "demo",
+ "tmpl": "componet", "view": "", "init": "",
+ "type": "public", "ctx": "demo", "cmd": "demo",
+ "args": []interface{}{}, "inputs": []interface{}{
+ map[string]interface{}{"type": "text", "name": "pod", "value": "hello world"},
+ map[string]interface{}{"type": "button", "value": "执行"},
+ },
+ },
+ }},
+ },
+ Commands: map[string]*ctx.Command{
+ "demo": {Name: "demo", Help: "demo", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
+ m.Echo(kit.Select("hello world", arg, 0))
+ return
+ }},
+ },
+}
+
+func main() {
+ fmt.Print(cli.Index.Plugin(Index, os.Args[1:]))
+}
diff --git a/src/plugin/docker/index.js b/src/plugin/docker/index.js
new file mode 100644
index 00000000..17b83ae2
--- /dev/null
+++ b/src/plugin/docker/index.js
@@ -0,0 +1,3 @@
+Script["docker/index.js"] = function(field, option, output) {return {
+}}
+
diff --git a/src/plugin/docker/index.shy b/src/plugin/docker/index.shy
new file mode 100644
index 00000000..7280bc31
--- /dev/null
+++ b/src/plugin/docker/index.shy
@@ -0,0 +1,49 @@
+kit shell "命令" private "web.code.zsh" \
+ text "" name dir imports plugin_path action auto \
+ select "" name cmd values list values find values grep values tail \
+ exports path path \
+ text "" name txt \
+ feature display editor \
+ button "搜索" \
+ button "返回" cb Last
+
+kit clip "文本" private "web.code.tmux" "" "" "" "buffer" \
+ text "" name tag imports plugin_buffer action auto \
+ text "" name txt \
+ exports buffer buffer \
+ feature detail "复制" "下载" "修改" \
+ button "查看" action auto \
+ button "返回" cb Last
+
+kit tmux "终端" private "web.code.tmux" \
+ text "context" name session imports plugin_session action auto \
+ text "" name window imports plugin_window action auto \
+ text "" name pane imports plugin_pane view char action auto \
+ text "" name cmd \
+ exports session session "" window window "" pane pane "" \
+ feature detail "复制" "下载" "修改" \
+ button "查看" action auto
+
+kit image "镜像" private "web.code.docker" "image" \
+ text "" name pos imports plugin_REPOSITORY \
+ text "" name tag imports plugin_TAG \
+ exports IMAGE_ID IMAGE_ID "" REPOSITORY REPOSITORY "" TAG TAG "" \
+ feature detail "运行" "删除" "清理" \
+ button "查看" action auto
+
+kit container "容器" private "web.code.docker" "container" \
+ text "" name arg imports plugin_CONTAINER_ID \
+ exports CONTAINER_ID CONTAINER_ID \
+ feature detail "进入" "停止" "启动" "重启" "修改" "删除" "清理" \
+ button "查看" action auto
+
+kit network "网络" private "web.code.docker" "network" \
+ text "" name arg imports plugin_NETWORK_ID action auto \
+ exports NETWORK_ID NETWORK_ID \
+ button "查看" action auto
+
+kit volume "存储" private "web.code.docker" "volume" \
+ text "" name arg imports plugin_CONTAINER_ID \
+ exports CONTAINER_ID CONTAINER_ID \
+ button "查看"
+
diff --git a/src/toolkit/misc.go b/src/toolkit/misc.go
index 2ac7c69c..bb3358ec 100644
--- a/src/toolkit/misc.go
+++ b/src/toolkit/misc.go
@@ -218,3 +218,43 @@ func List(arg interface{}, cb interface{}) {
}
}
}
+
+func Merge(list interface{}, value string) interface{} {
+ switch val := list.(type) {
+ case nil:
+ return value
+ case string:
+ return []interface{}{val, value}
+ case []interface{}:
+ return append(val, value)
+ }
+ return list
+}
+func Contains(list interface{}, value string) bool {
+ switch val := list.(type) {
+ case nil:
+ case string:
+ case []string:
+ for _, v := range val {
+ if v == value {
+ return true
+ }
+ }
+ case []interface{}:
+ }
+ return false
+}
+func IndexOf(list interface{}, value string) int {
+ switch val := list.(type) {
+ case nil:
+ case string:
+ case []string:
+ for i, v := range val {
+ if strings.TrimSpace(v) == strings.TrimSpace(value) {
+ return i
+ }
+ }
+ case []interface{}:
+ }
+ return -1
+}
diff --git a/usr/librarys/example.js b/usr/librarys/example.js
index e37893bd..717ef075 100644
--- a/usr/librarys/example.js
+++ b/usr/librarys/example.js
@@ -1220,10 +1220,12 @@ function Plugin(page, pane, field, inits, runs) {
var meta = arguments.callee.meta
var list = arguments.callee.list
- for (var i = 0; i < list.length; i += 3) {
- (list[1] && line[list[1]] || list[i+1] && line[list[i+1]] || list[i+2]) &&
+ for (var i = 0; i < list.length; i += 3) {if (list[i+1] == name) {
+ for (var i = 0; i < list.length; i += 3) {
page.Sync("plugin_"+list[i]).set(meta[list[i+2]||""](list[i+1]? line[list[i+1]]: value, list[i+1]||name, line, list))
- }
+ }
+ break
+ }}
}),
onchoice: shy("菜单列表", {
"返回": "Last",
@@ -1232,7 +1234,7 @@ function Plugin(page, pane, field, inits, runs) {
"减参": "Remove",
"删除": "Delete",
}, ["返回", "复制", "加参", "减参", "删除"], function(event, value, meta) {
- kit._call(plugin, plugin[meta[value]])
+ kit._call(plugin, plugin[meta[value]], [event])
return true
}),
onaction: shy("事件列表", {
@@ -1290,7 +1292,7 @@ function Inputs(plugin, meta, item, target, option) {
onimport: shy("导入数据", {}, [item.imports], function() {
kit.List(arguments.callee.list, function(imports) {
page.Sync(imports).change(function(value) {
- plugin.History(target.value, target), target.value = value
+ plugin.History(target.value, target), target.value = value.trim()
input.Event(event = document.createEvent("Event"))
item.action == "auto" && plugin.Runs(event)
})
@@ -1372,10 +1374,10 @@ function Inputs(plugin, meta, item, target, option) {
return true
})
+ // Event入口 2.1
if (event.key == "Enter" && (event.ctrlKey || item.type == "text")) {
- // Event入口 2.1
input.which.set(target.value) != undefined && plugin.History(target.value, target)
- input.Event(event, {}) && plugin.Check(event, target)
+ input.Event(event, {}) && event.ctrlKey? plugin.Runs(event): plugin.Check(event, target)
}
},
onkeyup: function(event) {
@@ -1409,11 +1411,27 @@ function Inputs(plugin, meta, item, target, option) {
return plugin.Inputs[item.name] = target, target.Input = input
}
function Output(plugin, type, msg, cb, target, option) {
- var exports = plugin.target.Meta.exports
+ var name = plugin.target.Meta.name+"."+type
+ var feature = JSON.parse(plugin.target.Meta.feature||'{}')
+ var exports = JSON.parse(plugin.target.Meta.exports||'{}')
+
var output = Meta(plugin.Zone(type), target, {
_table: function() {plugin.onfigure("table")},
_canvas: function() {plugin.onfigure("canvas")},
clear: function() {target.innerHTML = ""},
+ Format: function() {
+ var ext = ".csv", txt = kit.Selector(target, "tr", function(tr) {
+ return kit.Selector(tr, "td,th", function(td) {
+ return td.innerText
+ }).join(",")
+ }).join("\n");
+ type == "editor" && msg.file && (ext = ".txt", txt = msg.result.join("\n"));
+ !txt && (ext = ".txt", txt = msg.result.join(""))
+ return [name, ext, txt]
+ },
+ Copy: function(event) {
+ kit.CopyText(output.Format()[2])
+ },
Jshy: function(event, args) {
// 内部命令
@@ -1425,19 +1443,44 @@ function Output(plugin, type, msg, cb, target, option) {
},
Download: function() {
- var type = ".csv", text = kit.Selector(target, "tr", function(tr) {
- return kit.Selector(tr, "td,th", function(td) {
- return td.innerText
- }).join(",")
- }).join("\n")
- !text && (type = ".txt", text = plugin.msg.result.join(""))
+ var ps = output.Format()
- plugin.ontoast({text:''+name+type+'', title: "下载中...", width: 200})
+ plugin.ontoast({text:''+ps[0]+ps[1]+'', title: "下载中...", width: 200})
kit.Selector(page.toast, "a", function(item) {item.click()})
},
onimport: shy("导入数据", {
_table: function(msg, list) {
- return list && list.length > 0 && kit.OrderTable(kit.AppendTable(kit.AppendChild(target, "table"), msg.Table(), list), "", output.onexport)
+ return list && list.length > 0 && kit.OrderTable(kit.AppendTable(kit.AppendChild(target, "table"), msg.Table(), list), "", output.onexport, function(event, value, name, line, index) {
+ var td = event.target
+ plugin.oncarte(event, shy("菜单列表", {
+ "修改": "modify",
+ "删除": "delete",
+ "下载": "Download",
+ "复制": function(event, text) {kit.CopyText(text), plugin.ontoast(text, "Copy to ClipBoard!")},
+ }, feature.detail||["复制", "下载"], function(event, item, meta) {
+ var text = td.innerText.trim()
+ if (typeof meta[item] == "function") {meta[item](event, text); return}
+
+ item == "修改"? (text = kit.AppendChilds(td, [{type: "input", value: text, data: {onkeydown: function(event) {
+ if (event.key == "Enter") {
+ var id = ""
+ for (var i = 0; i < exports.length-1; i += 3) {
+ id = (id || line[exports[i+1]] || "").trim()
+ }
+ plugin.Run(event, [id, meta[item], name, event.target.value], function(msg) {
+ td.innerHTML = event.target.value
+ plugin.ontoast("修改成功")
+ }, true)
+ return
+ }
+ }}}]).input, text.focus(), text.setSelectionRange(0, -1)): output[meta[item]]? output[meta[item]](event): plugin.Run(event, [line[exports[1]].trim(), meta[item]||item], function(msg) {
+ console.log(msg)
+ })
+
+ return true
+ }),
+ )
+ })
},
_code: function(msg) {
return msg.result && msg.result.length > 0 && kit.OrderCode(kit.AppendChild(target, [{view: ["code", "div", msg.Results()]}]).first)
@@ -1489,13 +1532,21 @@ function Output(plugin, type, msg, cb, target, option) {
page.output = target
meta[type](msg, cb)
}),
+ ondetail: shy("菜单列表", {
+ "删除": "_table",
+ "修改": "_canvas",
+ }, ["删除", "修改"], function(event, value, meta) {
+ kit._call(output, output[meta[value]], [event])
+ return true
+ }),
onchoice: shy("菜单列表", {
"表格": "_table",
"绘图": "_canvas",
+ "复制": "Copy",
"下载": "Download",
"返回": "Last",
"清空": "clear",
- }, ["表格", "绘图", "下载", "返回", "清空"], function(event, value, meta) {
+ }, ["表格", "绘图", "复制", "下载", "返回", "清空"], function(event, value, meta) {
kit._call(output, output[meta[value]], [event])
return true
}),
diff --git a/usr/librarys/toolkit.js b/usr/librarys/toolkit.js
index d7d451db..b519f938 100644
--- a/usr/librarys/toolkit.js
+++ b/usr/librarys/toolkit.js
@@ -303,7 +303,7 @@ kit = toolkit = (function() {var kit = {__proto__: document,
var td = kit.AppendChild(tr, "td", kit.Color(row[key]))
if (key == "when") {td.className = "when"}
- if (row[key].startsWith("http")) {
+ if ((row[key]||"").startsWith("http")) {
td.innerHTML = ""+row[key]+""
}
@@ -353,8 +353,8 @@ kit = toolkit = (function() {var kit = {__proto__: document,
tbody.appendChild(list[i])
}
},
- OrderTable: function(table, field, cb) {if (!table) {return}
- table.onclick = function(event) {var target = event.target
+ OrderTable: function(table, field, cb, cbs) {if (!table) {return}
+ table.oncontextmenu = table.onclick = function(event) {var target = event.target
target.parentElement.childNodes.forEach(function(item, i) {if (item != target) {return}
if (target.tagName == "TH") {var dataset = target.dataset
dataset["sort_asc"] = (dataset["sort_asc"] == "1") ? 0: 1
@@ -362,7 +362,7 @@ kit = toolkit = (function() {var kit = {__proto__: document,
} else if (target.tagName == "TD") {var index = 0
kit.Selector(table, "tr", function(item, i) {item == target.parentElement && (index = i)})
var name = target.parentElement.parentElement.querySelector("tr").childNodes[i].innerText
- name.startsWith(field) && kit._call(cb, [event, item.innerText, name, item.parentNode.Meta, index])
+ name.startsWith(field) && kit._call(event.type=="contextmenu"? cbs: cb, [event, item.innerText, name, item.parentNode.Meta, index])
}
})
kit.CopyText()
@@ -439,7 +439,7 @@ kit = toolkit = (function() {var kit = {__proto__: document,
// HTML输入文本
CopyText: function(text) {
if (text) {
- var input = kit.AppendChild(document.body, [{type: "input", value: text}]).input
+ var input = kit.AppendChild(document.body, [{type: "textarea", inner: text}]).last
input.focus(), input.setSelectionRange(0, text.length)
}
@@ -544,6 +544,7 @@ kit = toolkit = (function() {var kit = {__proto__: document,
s = s.replace(/\033\[31m/g, "")
s = s.replace(/\033\[0m/g, "")
s = s.replace(/\033\[m/g, "")
+ s = s.replace(/\n/g, "
")
return s
},
Value: function() {