forked from x/ContextOS
opt nfs&cli
This commit is contained in:
parent
dc791f2519
commit
014a591bb6
@ -132,6 +132,129 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||
"timer_next": &ctx.Config{Name: "timer_next", Value: "", Help: "定时器"},
|
||||
},
|
||||
Commands: map[string]*ctx.Command{
|
||||
"system": &ctx.Command{Name: "system word...", Help: []string{"调用系统命令, word: 命令",
|
||||
"cmd_active(true/false): 是否交互", "cmd_timeout: 命令超时", "cmd_env: 环境变量", "cmd_dir: 工作目录"},
|
||||
Form: map[string]int{"cmd_active": 1, "cmd_timeout": 1, "cmd_env": 2, "cmd_dir": 1, "cmd_error": 0, "cmd_parse": 1},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
for _, v := range m.Meta["result"] {
|
||||
if strings.TrimSpace(v) != "" {
|
||||
arg = append(arg, v)
|
||||
}
|
||||
}
|
||||
|
||||
conf := m.Confm("cmd_combine", arg[0])
|
||||
if v, ok := kit.Chain(conf, "cmd").(string); ok {
|
||||
arg[0] = m.Parse(v)
|
||||
}
|
||||
cmd := exec.Command(arg[0])
|
||||
if v, ok := kit.Chain(conf, "path").(string); ok {
|
||||
cmd.Path = m.Parse(v)
|
||||
}
|
||||
m.Log("info", "cmd.path %v", cmd.Path)
|
||||
|
||||
args := []string{}
|
||||
if list, ok := kit.Chain(conf, "arg").([]interface{}); ok {
|
||||
for _, v := range list {
|
||||
args = append(args, m.Parse(v))
|
||||
}
|
||||
}
|
||||
if args = append(args, arg[1:]...); len(args) > 0 {
|
||||
cmd.Args = args
|
||||
}
|
||||
m.Log("info", "cmd.arg %v", cmd.Args)
|
||||
|
||||
for k, v := range m.Confm("system_env") {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, m.Parse(v)))
|
||||
}
|
||||
if list, ok := kit.Chain(conf, "env").([]interface{}); ok {
|
||||
for k, v := range list {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, m.Parse(v)))
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(m.Meta["cmd_env"])-1; i += 2 {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", m.Meta["cmd_env"][i], m.Parse(m.Meta["cmd_env"][i+1])))
|
||||
}
|
||||
m.Log("info", "cmd.env %v", cmd.Env)
|
||||
for _, v := range os.Environ() {
|
||||
cmd.Env = append(cmd.Env, v)
|
||||
}
|
||||
|
||||
if m.Options("cmd_dir") {
|
||||
cmd.Dir = m.Option("cmd_dir")
|
||||
} else if v, ok := kit.Chain(conf, "dir").(string); ok {
|
||||
cmd.Dir = m.Parse(v)
|
||||
}
|
||||
m.Log("info", "cmd.dir %v", cmd.Dir)
|
||||
|
||||
if m.Options("cmd_active") || kit.Right(conf["active"]) {
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
if e := cmd.Start(); e != nil {
|
||||
m.Echo("error: ").Echo("%s\n", e)
|
||||
} else if e := cmd.Wait(); e != nil {
|
||||
m.Echo("error: ").Echo("%s\n", e)
|
||||
}
|
||||
} else {
|
||||
wait := make(chan bool, 1)
|
||||
go func() {
|
||||
out := bytes.NewBuffer(make([]byte, 1024))
|
||||
err := bytes.NewBuffer(make([]byte, 1024))
|
||||
cmd.Stdout = out
|
||||
cmd.Stderr = err
|
||||
|
||||
if e := cmd.Run(); e != nil {
|
||||
m.Echo("error: ").Echo("%s\n", e).Echo(err.String())
|
||||
m.Log("trace", "%s\n", e)
|
||||
|
||||
b, _ := cmd.CombinedOutput()
|
||||
m.Echo("error: %s", string(b))
|
||||
m.Log("trace", "error: %s", string(b))
|
||||
} else {
|
||||
switch m.Option("cmd_parse") {
|
||||
case "json":
|
||||
var data interface{}
|
||||
if json.Unmarshal(out.Bytes(), &data) == nil {
|
||||
msg := m.Spawn().Put("option", "data", data).Cmd("trans", "data", "")
|
||||
m.Copy(msg, "append").Copy(msg, "result")
|
||||
} else {
|
||||
m.Echo(out.String())
|
||||
}
|
||||
|
||||
case "csv":
|
||||
data, e := csv.NewReader(out).ReadAll()
|
||||
m.Assert(e)
|
||||
for i := 1; i < len(data); i++ {
|
||||
for j := 0; j < len(data[i]); j++ {
|
||||
m.Add("append", data[0][j], data[i][j])
|
||||
}
|
||||
}
|
||||
m.Table()
|
||||
default:
|
||||
m.Echo(out.String())
|
||||
}
|
||||
}
|
||||
wait <- true
|
||||
}()
|
||||
|
||||
timeout := m.Conf("cmd_timeout")
|
||||
if conf["timeout"] != nil {
|
||||
timeout = conf["timeout"].(string)
|
||||
}
|
||||
if m.Option("timeout") != "" {
|
||||
timeout = m.Option("timeout")
|
||||
}
|
||||
|
||||
d, e := time.ParseDuration(timeout)
|
||||
m.Assert(e)
|
||||
|
||||
select {
|
||||
case <-time.After(d):
|
||||
cmd.Process.Kill()
|
||||
m.Echo("%s: %s timeout", arg[0], m.Conf("cmd_timeout"))
|
||||
case <-wait:
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
"alias": &ctx.Command{Name: "alias [short [long...]]|[delete short]|[import module [command [alias]]]",
|
||||
Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名, import导入模块所有命令",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
@ -554,6 +677,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||
m.Add("append", "return", arg[1:])
|
||||
return
|
||||
}},
|
||||
"arguments": &ctx.Command{Name: "arguments", Help: "脚本参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
m.Set("result", m.Optionv("arguments"))
|
||||
return
|
||||
}},
|
||||
"source": &ctx.Command{Name: "source [stdio [init_shy [exit_shy]]]|[filename [async]]|string", Help: "解析脚本, filename: 文件名, async: 异步执行",
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if _, ok := m.Source().Server.(*CLI); ok {
|
||||
@ -615,10 +742,6 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||
}, "parse", "line", "void", strings.Join(arg, " "))
|
||||
return
|
||||
}},
|
||||
"arguments": &ctx.Command{Name: "arguments", Help: "脚本参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
m.Set("result", m.Optionv("arguments"))
|
||||
return
|
||||
}},
|
||||
"run": &ctx.Command{Name: "run", Help: "脚本参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(arg) == 0 {
|
||||
name := path.Join(m.Option("dir_root"), m.Option("download_dir"))
|
||||
@ -663,133 +786,6 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||
}
|
||||
return
|
||||
}},
|
||||
"system": &ctx.Command{Name: "system word...", Help: []string{"调用系统命令, word: 命令",
|
||||
"cmd_active(true/false): 是否交互", "cmd_timeout: 命令超时", "cmd_env: 环境变量", "cmd_dir: 工作目录"},
|
||||
Form: map[string]int{"cmd_active": 1, "cmd_timeout": 1, "cmd_env": 2, "cmd_dir": 1, "cmd_error": 0, "cmd_parse": 1},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(m.Meta["result"]) > 0 {
|
||||
for _, v := range m.Meta["result"] {
|
||||
if strings.TrimSpace(v) != "" {
|
||||
arg = append(arg, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conf := map[string]interface{}{}
|
||||
if m.Confv("cmd_combine", arg[0]) != nil {
|
||||
conf = m.Confv("cmd_combine", arg[0]).(map[string]interface{})
|
||||
}
|
||||
|
||||
if conf["cmd"] != nil {
|
||||
arg[0] = m.Parse(conf["cmd"])
|
||||
}
|
||||
args := []string{}
|
||||
if conf["arg"] != nil {
|
||||
for _, v := range conf["arg"].([]interface{}) {
|
||||
args = append(args, m.Parse(v))
|
||||
}
|
||||
}
|
||||
args = append(args, arg[1:]...)
|
||||
if conf["args"] != nil {
|
||||
for _, v := range conf["args"].([]interface{}) {
|
||||
args = append(args, m.Parse(v))
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(arg[0], args...)
|
||||
if conf["path"] != nil {
|
||||
cmd.Path = m.Parse(conf["path"])
|
||||
}
|
||||
|
||||
for k, v := range m.Confv("system_env").(map[string]interface{}) {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, m.Parse(v)))
|
||||
}
|
||||
if conf["env"] != nil {
|
||||
for k, v := range conf["env"].(map[string]interface{}) {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, m.Parse(v)))
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(m.Meta["cmd_env"])-1; i += 2 {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", m.Meta["cmd_env"][i], m.Parse(m.Meta["cmd_env"][i+1])))
|
||||
}
|
||||
m.Log("info", "cmd.env %v", cmd.Env)
|
||||
for _, v := range os.Environ() {
|
||||
cmd.Env = append(cmd.Env, v)
|
||||
}
|
||||
|
||||
if conf["dir"] != nil {
|
||||
cmd.Dir = m.Parse(conf["dir"])
|
||||
}
|
||||
if m.Options("cmd_dir") {
|
||||
cmd.Dir = m.Option("cmd_dir")
|
||||
}
|
||||
|
||||
if m.Options("cmd_active") || kit.Right(conf["active"]) {
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
if e := cmd.Start(); e != nil {
|
||||
m.Echo("error: ").Echo("%s\n", e)
|
||||
} else if e := cmd.Wait(); e != nil {
|
||||
m.Echo("error: ").Echo("%s\n", e)
|
||||
}
|
||||
} else {
|
||||
wait := make(chan bool, 1)
|
||||
go func() {
|
||||
|
||||
out := bytes.NewBuffer(make([]byte, 1024))
|
||||
err := bytes.NewBuffer(make([]byte, 1024))
|
||||
cmd.Stdout = out
|
||||
cmd.Stderr = err
|
||||
|
||||
if e := cmd.Run(); e == nil {
|
||||
m.Echo("error: ").Echo("%s", e).Echo(string(err))
|
||||
} else {
|
||||
|
||||
switch m.Option("cmd_parse") {
|
||||
case "json":
|
||||
var data interface{}
|
||||
if json.Unmarshal(out, &data) == nil {
|
||||
msg := m.Spawn().Put("option", "data", data).Cmd("trans", "data", "")
|
||||
m.Copy(msg, "append").Copy(msg, "result")
|
||||
} else {
|
||||
m.Echo(string(out))
|
||||
}
|
||||
|
||||
case "csv":
|
||||
data, e := csv.NewReader(bytes.NewReader(out)).ReadAll()
|
||||
m.Assert(e)
|
||||
for i := 1; i < len(data); i++ {
|
||||
for j := 0; j < len(data[i]); j++ {
|
||||
m.Add("append", data[0][j], data[i][j])
|
||||
}
|
||||
}
|
||||
m.Table()
|
||||
default:
|
||||
m.Echo(string(out))
|
||||
}
|
||||
}
|
||||
wait <- true
|
||||
}()
|
||||
|
||||
timeout := m.Conf("cmd_timeout")
|
||||
if conf["timeout"] != nil {
|
||||
timeout = conf["timeout"].(string)
|
||||
}
|
||||
if m.Option("timeout") != "" {
|
||||
timeout = m.Option("timeout")
|
||||
}
|
||||
|
||||
d, e := time.ParseDuration(timeout)
|
||||
m.Assert(e)
|
||||
|
||||
select {
|
||||
case <-time.After(d):
|
||||
cmd.Process.Kill()
|
||||
m.Echo("%s: %s timeout", arg[0], m.Conf("cmd_timeout"))
|
||||
case <-wait:
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
"sysinfo": &ctx.Command{Name: "sysinfo", Help: "sysinfo", Hand: sysinfo},
|
||||
"runtime": &ctx.Command{Name: "runtime", Help: "runtime", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
mem := &runtime.MemStats{}
|
||||
|
@ -1252,6 +1252,12 @@ func (m *Message) Confm(key string, args ...interface{}) map[string]interface{}
|
||||
}
|
||||
|
||||
switch fun := args[0].(type) {
|
||||
case func(int, string) bool:
|
||||
for i, v := range table {
|
||||
if fun(i, kit.Format(v)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
case func(map[string]interface{}):
|
||||
fun(value)
|
||||
case func(string, map[string]interface{}):
|
||||
|
@ -87,6 +87,10 @@ func dir(m *ctx.Message, name string, level int, deep bool, dir_type string, tri
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(f.Name(), ".") && dir_type != "both" {
|
||||
continue
|
||||
}
|
||||
|
||||
f, _ := os.Stat(f.Name())
|
||||
if !(dir_type == "file" && f.IsDir() || dir_type == "dir" && !f.IsDir()) && (dir_reg == nil || dir_reg.MatchString(f.Name())) {
|
||||
for _, field := range fields {
|
||||
@ -885,6 +889,338 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
"paths": &ctx.Config{Name: "paths", Value: []interface{}{"var", "usr", "etc", ""}, Help: "文件路径"},
|
||||
},
|
||||
Commands: map[string]*ctx.Command{
|
||||
"pwd": &ctx.Command{Name: "pwd [all] | [[index] path] ", Help: "工作目录,all: 查看所有, index path: 设置路径, path: 设置当前路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(arg) > 0 && arg[0] == "all" {
|
||||
m.Cmdy("nfs.config", "paths")
|
||||
return
|
||||
}
|
||||
|
||||
index := 0
|
||||
if len(arg) > 1 {
|
||||
index, arg = kit.Int(arg[0]), arg[1:]
|
||||
}
|
||||
for i, v := range arg {
|
||||
m.Log("info", "paths %s %s", index+i, v)
|
||||
m.Confv("paths", index+i, v)
|
||||
}
|
||||
|
||||
if p := m.Conf("paths", index); path.IsAbs(p) {
|
||||
m.Echo("%s", p)
|
||||
} else if wd, e := os.Getwd(); m.Assert(e) {
|
||||
m.Echo("%s", path.Join(wd, p))
|
||||
}
|
||||
return
|
||||
}},
|
||||
"dir": &ctx.Command{Name: "dir path [dir_deep] [dir_type both|file|dir] [dir_reg reg] [dir_sort field order] fields...",
|
||||
Help: "查看目录, path: 路径, dir_deep: 递归查询, dir_type: 文件类型, dir_reg: 正则表达式, dir_sort: 排序, fields: 查询字段",
|
||||
Form: map[string]int{"dir_deep": 0, "dir_type": 1, "dir_reg": 1, "dir_sort": 2},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, "")
|
||||
}
|
||||
|
||||
wd, e := os.Getwd()
|
||||
m.Assert(e)
|
||||
trip := len(wd) + 1
|
||||
|
||||
rg, e := regexp.Compile(m.Option("dir_reg"))
|
||||
|
||||
m.Confm("paths", func(index int, value string) bool {
|
||||
p := path.Join(value, m.Option("dir_root"), kit.Select("", arg))
|
||||
if s, e := os.Stat(p); e == nil {
|
||||
if s.IsDir() {
|
||||
dir(m, p, 0, kit.Right(m.Has("dir_deep")), m.Confx("dir_type"), trip, rg,
|
||||
strings.Split(m.Confx("dir_fields", strings.Join(arg[1:], " ")), " "),
|
||||
m.Conf("time_format"))
|
||||
} else {
|
||||
m.Append("directory", p)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if m.Has("dir_sort") {
|
||||
m.Sort(m.Meta["dir_sort"][0], m.Meta["dir_sort"][1:]...)
|
||||
}
|
||||
|
||||
if len(m.Meta["append"]) == 1 {
|
||||
for _, v := range m.Meta[m.Meta["append"][0]] {
|
||||
m.Echo(v).Echo(" ")
|
||||
}
|
||||
} else {
|
||||
m.Table()
|
||||
}
|
||||
return
|
||||
}},
|
||||
"git": &ctx.Command{
|
||||
Name: "git branch|status|diff|log|info arg... [dir path]...",
|
||||
Help: "版本控制, branch: 分支管理, status: 查看状态, info: 查看分支与状态, dir: 指定路径",
|
||||
Form: map[string]int{"dir": 1, "git_info": 1, "git_log": 1, "git_log_form": 1},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
m.Cmdy("cli.system", "git", arg)
|
||||
|
||||
return
|
||||
if len(arg) == 0 {
|
||||
arg = []string{"info"}
|
||||
}
|
||||
cmds := []string{arg[0]}
|
||||
switch arg[0] {
|
||||
case "s":
|
||||
arg[0] = "status"
|
||||
case "b":
|
||||
arg[0] = "branch"
|
||||
case "d":
|
||||
arg[0] = "diff"
|
||||
}
|
||||
if arg[0] == "info" {
|
||||
cmds = strings.Split(m.Confx("git_info"), " ")
|
||||
}
|
||||
wd, e := os.Getwd()
|
||||
m.Assert(e)
|
||||
if !m.Has("dir") {
|
||||
m.Option("dir", m.Confx("dir"))
|
||||
}
|
||||
for _, p := range m.Meta["dir"] {
|
||||
if !path.IsAbs(p) {
|
||||
p = path.Join(wd, p)
|
||||
}
|
||||
m.Echo("path: %s\n", p)
|
||||
for _, c := range cmds {
|
||||
args := []string{}
|
||||
switch c {
|
||||
case "branch", "status", "diff":
|
||||
if c != "status" {
|
||||
args = append(args, "--color")
|
||||
}
|
||||
args = append(args, strings.Split(m.Confx("git_"+c, arg, 1), " ")...)
|
||||
if len(arg) > 2 {
|
||||
args = append(args, arg[2:]...)
|
||||
}
|
||||
case "difftool":
|
||||
cmd := exec.Command("git", "difftool", "-y")
|
||||
m.Log("info", "cmd: %s %v", "git", "difftool", "-y")
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
if e := cmd.Start(); e != nil {
|
||||
m.Echo("error: ")
|
||||
m.Echo("%s\n", e)
|
||||
} else if e := cmd.Wait(); e != nil {
|
||||
m.Echo("error: ")
|
||||
m.Echo("%s\n", e)
|
||||
}
|
||||
continue
|
||||
case "csv":
|
||||
cmd := exec.Command("git", "log", "--shortstat", "--pretty=commit: %ad", "--date=format:%Y-%m-%d")
|
||||
if out, e := cmd.CombinedOutput(); e != nil {
|
||||
m.Echo("error: ")
|
||||
m.Echo("%s\n", e)
|
||||
} else {
|
||||
f, e := os.Create(arg[1])
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
|
||||
type stat struct {
|
||||
date string
|
||||
adds int
|
||||
dels int
|
||||
}
|
||||
stats := []*stat{}
|
||||
list := strings.Split(string(out), "commit: ")
|
||||
for _, v := range list {
|
||||
l := strings.Split(v, "\n")
|
||||
if len(l) > 2 {
|
||||
fs := strings.Split(strings.Trim(l[2], " "), ", ")
|
||||
stat := &stat{date: l[0]}
|
||||
if len(fs) > 2 {
|
||||
adds := strings.Split(fs[1], " ")
|
||||
dels := strings.Split(fs[2], " ")
|
||||
a, e := strconv.Atoi(adds[0])
|
||||
m.Assert(e)
|
||||
stat.adds = a
|
||||
d, e := strconv.Atoi(dels[0])
|
||||
m.Assert(e)
|
||||
stat.dels = d
|
||||
} else {
|
||||
adds := strings.Split(fs[1], " ")
|
||||
a, e := strconv.Atoi(adds[0])
|
||||
m.Assert(e)
|
||||
if adds[1] == "insertions(+)" {
|
||||
stat.adds = a
|
||||
} else {
|
||||
stat.dels = a
|
||||
}
|
||||
}
|
||||
|
||||
stats = append(stats, stat)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(f, "order,date,adds,dels,sum,top,bottom,last\n")
|
||||
l := len(stats)
|
||||
for i := 0; i < l/2; i++ {
|
||||
stats[i], stats[l-i-1] = stats[l-i-1], stats[i]
|
||||
}
|
||||
sum := 0
|
||||
for i, v := range stats {
|
||||
fmt.Fprintf(f, "%d,%s,%d,%d,%d,%d,%d,%d\n", i, v.date, v.adds, v.dels, sum, sum+v.adds, sum-v.dels, sum+v.adds-v.dels)
|
||||
sum += v.adds - v.dels
|
||||
}
|
||||
}
|
||||
continue
|
||||
|
||||
case "log":
|
||||
args = append(args, "--color")
|
||||
args = append(args, strings.Split(m.Confx("git_log"), " ")...)
|
||||
args = append(args, fmt.Sprintf("--%s", m.Confx("git_log_form")))
|
||||
args = append(args, m.Confx("git_log_skip", arg, 1, "--skip=%s"))
|
||||
args = append(args, m.Confx("git_log_line", arg, 2, "-n %s"))
|
||||
default:
|
||||
args = append(args, arg[1:]...)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case "commit":
|
||||
m.Find("web.code").Cmd("counter", "ncommit", 1)
|
||||
case "push":
|
||||
m.Find("web.code").Cmd("counter", "npush", 1)
|
||||
}
|
||||
|
||||
m.Log("info", "cmd: %s %v", "git", kit.Trans("-C", p, c, args))
|
||||
msg := m.Sess("cli").Cmd("system", "git", "-C", p, c, args)
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
m.Echo("\n")
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
||||
"path": &ctx.Command{Name: "path file", Help: "查找文件路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
for _, v := range m.Confv("paths").([]interface{}) {
|
||||
p := path.Join(v.(string), arg[0])
|
||||
if _, e := os.Stat(p); e == nil {
|
||||
m.Echo(p)
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
"load": &ctx.Command{Name: "load file [buf_size [pos]]", Help: "加载文件, buf_size: 加载大小, pos: 加载位置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if p, f, e := open(m, arg[0]); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
pos := 0
|
||||
if len(arg) > 2 {
|
||||
i, e := strconv.Atoi(arg[2])
|
||||
m.Assert(e)
|
||||
pos = i
|
||||
}
|
||||
|
||||
s, e := strconv.Atoi(m.Confx("buf_size", arg, 1))
|
||||
m.Assert(e)
|
||||
buf := make([]byte, s)
|
||||
|
||||
if l, e := f.ReadAt(buf, int64(pos)); e == io.EOF || m.Assert(e) {
|
||||
m.Log("info", "load %s %d %d", p, l, pos)
|
||||
m.Echo(string(buf[:l]))
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
"save": &ctx.Command{Name: "save file string...", Help: "保存文件, file: 保存的文件, string: 保存的内容", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(arg) == 1 && m.Has("data") {
|
||||
arg = append(arg, m.Option("data"))
|
||||
}
|
||||
if p, f, e := open(m, arg[0], os.O_WRONLY|os.O_CREATE|os.O_TRUNC); m.Assert(e) {
|
||||
defer f.Close()
|
||||
m.Append("directory", p)
|
||||
m.Echo(p)
|
||||
|
||||
for _, v := range arg[1:] {
|
||||
n, e := fmt.Fprint(f, v)
|
||||
m.Assert(e)
|
||||
m.Log("info", "save %s %d", p, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
"export": &ctx.Command{Name: "export filename", Help: "导出数据", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
name := time.Now().Format(arg[0])
|
||||
_, f, e := open(m, name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC)
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
|
||||
switch {
|
||||
case strings.HasSuffix(arg[0], ".json") && len(m.Meta["append"]) > 0:
|
||||
data := []interface{}{}
|
||||
|
||||
nrow := len(m.Meta[m.Meta["append"][0]])
|
||||
for i := 0; i < nrow; i++ {
|
||||
line := map[string]interface{}{}
|
||||
for _, k := range m.Meta["append"] {
|
||||
line[k] = m.Meta[k][i]
|
||||
}
|
||||
data = append(data, line)
|
||||
}
|
||||
en := json.NewEncoder(f)
|
||||
en.SetIndent("", " ")
|
||||
en.Encode(data)
|
||||
|
||||
case strings.HasSuffix(arg[0], ".csv") && len(m.Meta["append"]) > 0:
|
||||
w := csv.NewWriter(f)
|
||||
|
||||
line := []string{}
|
||||
for _, v := range m.Meta["append"] {
|
||||
line = append(line, v)
|
||||
}
|
||||
w.Write(line)
|
||||
|
||||
nrow := len(m.Meta[m.Meta["append"][0]])
|
||||
for i := 0; i < nrow; i++ {
|
||||
line := []string{}
|
||||
for _, k := range m.Meta["append"] {
|
||||
line = append(line, m.Meta[k][i])
|
||||
}
|
||||
w.Write(line)
|
||||
}
|
||||
w.Flush()
|
||||
default:
|
||||
for _, v := range m.Meta["result"] {
|
||||
f.WriteString(v)
|
||||
}
|
||||
}
|
||||
m.Set("append").Set("result").Add("append", "directory", name).Echo(name)
|
||||
return
|
||||
}},
|
||||
"import": &ctx.Command{Name: "import filename [index]", Help: "导入数据", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
_, f, e := open(m, arg[0])
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
|
||||
switch {
|
||||
case strings.HasSuffix(arg[0], ".json"):
|
||||
var data interface{}
|
||||
de := json.NewDecoder(f)
|
||||
de.Decode(&data)
|
||||
|
||||
msg := m.Spawn().Put("option", "data", data).Cmd("trans", "data", arg[1:])
|
||||
m.Copy(msg, "append").Copy(msg, "result")
|
||||
case strings.HasSuffix(arg[0], ".csv"):
|
||||
r := csv.NewReader(f)
|
||||
|
||||
l, e := r.Read()
|
||||
m.Assert(e)
|
||||
m.Meta["append"] = l
|
||||
|
||||
for l, e = r.Read(); e != nil; l, e = r.Read() {
|
||||
for i, v := range l {
|
||||
m.Add("append", m.Meta["append"][i], v)
|
||||
}
|
||||
}
|
||||
m.Table()
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
||||
"open": &ctx.Command{Name: "open file", Help: "打开文件, file: 文件名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if m.Has("io") {
|
||||
} else if p, f, e := open(m, arg[0], os.O_RDWR|os.O_CREATE); e == nil {
|
||||
@ -1022,46 +1358,6 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
||||
"load": &ctx.Command{Name: "load file [buf_size [pos]]", Help: "加载文件, buf_size: 加载大小, pos: 加载位置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if p, f, e := open(m, arg[0]); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
pos := 0
|
||||
if len(arg) > 2 {
|
||||
i, e := strconv.Atoi(arg[2])
|
||||
m.Assert(e)
|
||||
pos = i
|
||||
}
|
||||
|
||||
s, e := strconv.Atoi(m.Confx("buf_size", arg, 1))
|
||||
m.Assert(e)
|
||||
buf := make([]byte, s)
|
||||
|
||||
if l, e := f.ReadAt(buf, int64(pos)); e == io.EOF || m.Assert(e) {
|
||||
m.Log("info", "load %s %d %d", p, l, pos)
|
||||
m.Echo(string(buf[:l]))
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
"save": &ctx.Command{Name: "save file string...", Help: "保存文件, file: 保存的文件, string: 保存的内容", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(arg) == 1 && m.Has("data") {
|
||||
arg = append(arg, m.Option("data"))
|
||||
}
|
||||
if p, f, e := open(m, arg[0], os.O_WRONLY|os.O_CREATE|os.O_TRUNC); m.Assert(e) {
|
||||
defer f.Close()
|
||||
m.Append("directory", p)
|
||||
m.Echo(p)
|
||||
|
||||
for _, v := range arg[1:] {
|
||||
n, e := fmt.Fprint(f, v)
|
||||
m.Assert(e)
|
||||
m.Log("info", "save %s %d", p, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
"print": &ctx.Command{Name: "print file string...", Help: "输出文件, file: 输出的文件, string: 输出的内容", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if p, f, e := open(m, arg[0], os.O_WRONLY|os.O_CREATE|os.O_APPEND); m.Assert(e) {
|
||||
defer f.Close()
|
||||
@ -1074,122 +1370,6 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
}
|
||||
return
|
||||
}},
|
||||
"export": &ctx.Command{Name: "export filename", Help: "导出数据", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
name := time.Now().Format(arg[0])
|
||||
_, f, e := open(m, name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC)
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
|
||||
switch {
|
||||
case strings.HasSuffix(arg[0], ".json") && len(m.Meta["append"]) > 0:
|
||||
data := []interface{}{}
|
||||
|
||||
nrow := len(m.Meta[m.Meta["append"][0]])
|
||||
for i := 0; i < nrow; i++ {
|
||||
line := map[string]interface{}{}
|
||||
for _, k := range m.Meta["append"] {
|
||||
line[k] = m.Meta[k][i]
|
||||
}
|
||||
data = append(data, line)
|
||||
}
|
||||
en := json.NewEncoder(f)
|
||||
en.SetIndent("", " ")
|
||||
en.Encode(data)
|
||||
|
||||
case strings.HasSuffix(arg[0], ".csv") && len(m.Meta["append"]) > 0:
|
||||
w := csv.NewWriter(f)
|
||||
|
||||
line := []string{}
|
||||
for _, v := range m.Meta["append"] {
|
||||
line = append(line, v)
|
||||
}
|
||||
w.Write(line)
|
||||
|
||||
nrow := len(m.Meta[m.Meta["append"][0]])
|
||||
for i := 0; i < nrow; i++ {
|
||||
line := []string{}
|
||||
for _, k := range m.Meta["append"] {
|
||||
line = append(line, m.Meta[k][i])
|
||||
}
|
||||
w.Write(line)
|
||||
}
|
||||
w.Flush()
|
||||
default:
|
||||
for _, v := range m.Meta["result"] {
|
||||
f.WriteString(v)
|
||||
}
|
||||
}
|
||||
m.Set("append").Set("result").Add("append", "directory", name).Echo(name)
|
||||
return
|
||||
}},
|
||||
"import": &ctx.Command{Name: "import filename [index]", Help: "导入数据", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
_, f, e := open(m, arg[0])
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
|
||||
switch {
|
||||
case strings.HasSuffix(arg[0], ".json"):
|
||||
var data interface{}
|
||||
de := json.NewDecoder(f)
|
||||
de.Decode(&data)
|
||||
|
||||
msg := m.Spawn().Put("option", "data", data).Cmd("trans", "data", arg[1:])
|
||||
m.Copy(msg, "append").Copy(msg, "result")
|
||||
case strings.HasSuffix(arg[0], ".csv"):
|
||||
r := csv.NewReader(f)
|
||||
|
||||
l, e := r.Read()
|
||||
m.Assert(e)
|
||||
m.Meta["append"] = l
|
||||
|
||||
for l, e = r.Read(); e != nil; l, e = r.Read() {
|
||||
for i, v := range l {
|
||||
m.Add("append", m.Meta["append"][i], v)
|
||||
}
|
||||
}
|
||||
m.Table()
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
||||
"pwd": &ctx.Command{Name: "pwd [all] | [[index] path] ", Help: "工作目录,all: 查看所有, index path: 设置路径, path: 设置当前路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(arg) > 0 && arg[0] == "all" {
|
||||
list := m.Confv("paths").([]interface{})
|
||||
for i, v := range list {
|
||||
m.Add("append", "index", i)
|
||||
m.Add("append", "path", v)
|
||||
}
|
||||
m.Table()
|
||||
return
|
||||
} else if len(arg) > 1 {
|
||||
m.Log("info", "paths %s %s", arg[0], arg[1])
|
||||
m.Confv("paths", arg[0], arg[1])
|
||||
} else if len(arg) > 0 {
|
||||
m.Log("info", "paths 0 %s", arg[0])
|
||||
m.Confv("paths", 0, arg[0])
|
||||
}
|
||||
|
||||
p := m.Confv("paths", 0).(string)
|
||||
if path.IsAbs(p) {
|
||||
m.Echo("%s", p)
|
||||
return
|
||||
}
|
||||
|
||||
wd, e := os.Getwd()
|
||||
m.Assert(e)
|
||||
m.Echo("%s", path.Join(wd, p))
|
||||
return
|
||||
}},
|
||||
"path": &ctx.Command{Name: "path file", Help: "查找文件路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
for _, v := range m.Confv("paths").([]interface{}) {
|
||||
p := path.Join(v.(string), arg[0])
|
||||
if _, e := os.Stat(p); e == nil {
|
||||
m.Echo(p)
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
"json": &ctx.Command{Name: "json [key value]...", Help: "生成格式化内容, key: 参数名, value: 参数值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(arg) == 1 {
|
||||
var data interface{}
|
||||
@ -1242,189 +1422,6 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
||||
"dir": &ctx.Command{Name: "dir dir [dir_type both|file|dir] [dir_deep] fields...",
|
||||
Help: "查看目录, dir: 目录名, dir_type: 文件类型, dir_deep: 递归查询, fields: 查询字段",
|
||||
Form: map[string]int{"dir_reg": 1, "dir_type": 1, "dir_deep": 0, "dir_sort": 2},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
wd, e := os.Getwd()
|
||||
m.Assert(e)
|
||||
trip := len(wd) + 1
|
||||
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, "")
|
||||
}
|
||||
dirs := arg[0]
|
||||
if m.Options("dir_root") {
|
||||
dirs = path.Join(m.Option("dir_root"), dirs)
|
||||
}
|
||||
|
||||
rg, e := regexp.Compile(m.Option("dir_reg"))
|
||||
|
||||
for _, v := range m.Confv("paths").([]interface{}) {
|
||||
d := path.Join(v.(string), dirs)
|
||||
if s, e := os.Stat(d); e == nil {
|
||||
if s.IsDir() {
|
||||
dir(m, d, 0, kit.Right(m.Has("dir_deep")), m.Confx("dir_type"), trip, rg,
|
||||
strings.Split(m.Confx("dir_fields", strings.Join(arg[1:], " ")), " "),
|
||||
m.Conf("time_format"))
|
||||
} else {
|
||||
m.Append("directory", d)
|
||||
return e
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if m.Has("dir_sort") {
|
||||
m.Sort(m.Meta["dir_sort"][1], m.Meta["dir_sort"][0])
|
||||
}
|
||||
|
||||
if len(m.Meta["append"]) == 1 {
|
||||
for _, v := range m.Meta[m.Meta["append"][0]] {
|
||||
m.Echo(v).Echo(" ")
|
||||
}
|
||||
} else {
|
||||
m.Table()
|
||||
}
|
||||
return
|
||||
}},
|
||||
"git": &ctx.Command{
|
||||
Name: "git branch|status|diff|log|info arg... [dir path]...",
|
||||
Help: "版本控制, branch: 分支管理, status: 查看状态, info: 查看分支与状态, dir: 指定路径",
|
||||
Form: map[string]int{"dir": 1, "git_info": 1, "git_log": 1, "git_log_form": 1},
|
||||
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if len(arg) == 0 {
|
||||
arg = []string{"info"}
|
||||
}
|
||||
cmds := []string{arg[0]}
|
||||
switch arg[0] {
|
||||
case "s":
|
||||
arg[0] = "status"
|
||||
case "b":
|
||||
arg[0] = "branch"
|
||||
case "d":
|
||||
arg[0] = "diff"
|
||||
}
|
||||
if arg[0] == "info" {
|
||||
cmds = strings.Split(m.Confx("git_info"), " ")
|
||||
}
|
||||
wd, e := os.Getwd()
|
||||
m.Assert(e)
|
||||
if !m.Has("dir") {
|
||||
m.Option("dir", m.Confx("dir"))
|
||||
}
|
||||
for _, p := range m.Meta["dir"] {
|
||||
if !path.IsAbs(p) {
|
||||
p = path.Join(wd, p)
|
||||
}
|
||||
m.Echo("path: %s\n", p)
|
||||
for _, c := range cmds {
|
||||
args := []string{}
|
||||
switch c {
|
||||
case "branch", "status", "diff":
|
||||
if c != "status" {
|
||||
args = append(args, "--color")
|
||||
}
|
||||
args = append(args, strings.Split(m.Confx("git_"+c, arg, 1), " ")...)
|
||||
if len(arg) > 2 {
|
||||
args = append(args, arg[2:]...)
|
||||
}
|
||||
case "difftool":
|
||||
cmd := exec.Command("git", "difftool", "-y")
|
||||
m.Log("info", "cmd: %s %v", "git", "difftool", "-y")
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
if e := cmd.Start(); e != nil {
|
||||
m.Echo("error: ")
|
||||
m.Echo("%s\n", e)
|
||||
} else if e := cmd.Wait(); e != nil {
|
||||
m.Echo("error: ")
|
||||
m.Echo("%s\n", e)
|
||||
}
|
||||
continue
|
||||
case "csv":
|
||||
cmd := exec.Command("git", "log", "--shortstat", "--pretty=commit: %ad", "--date=format:%Y-%m-%d")
|
||||
if out, e := cmd.CombinedOutput(); e != nil {
|
||||
m.Echo("error: ")
|
||||
m.Echo("%s\n", e)
|
||||
} else {
|
||||
f, e := os.Create(arg[1])
|
||||
m.Assert(e)
|
||||
defer f.Close()
|
||||
|
||||
type stat struct {
|
||||
date string
|
||||
adds int
|
||||
dels int
|
||||
}
|
||||
stats := []*stat{}
|
||||
list := strings.Split(string(out), "commit: ")
|
||||
for _, v := range list {
|
||||
l := strings.Split(v, "\n")
|
||||
if len(l) > 2 {
|
||||
fs := strings.Split(strings.Trim(l[2], " "), ", ")
|
||||
stat := &stat{date: l[0]}
|
||||
if len(fs) > 2 {
|
||||
adds := strings.Split(fs[1], " ")
|
||||
dels := strings.Split(fs[2], " ")
|
||||
a, e := strconv.Atoi(adds[0])
|
||||
m.Assert(e)
|
||||
stat.adds = a
|
||||
d, e := strconv.Atoi(dels[0])
|
||||
m.Assert(e)
|
||||
stat.dels = d
|
||||
} else {
|
||||
adds := strings.Split(fs[1], " ")
|
||||
a, e := strconv.Atoi(adds[0])
|
||||
m.Assert(e)
|
||||
if adds[1] == "insertions(+)" {
|
||||
stat.adds = a
|
||||
} else {
|
||||
stat.dels = a
|
||||
}
|
||||
}
|
||||
|
||||
stats = append(stats, stat)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(f, "order,date,adds,dels,sum,top,bottom,last\n")
|
||||
l := len(stats)
|
||||
for i := 0; i < l/2; i++ {
|
||||
stats[i], stats[l-i-1] = stats[l-i-1], stats[i]
|
||||
}
|
||||
sum := 0
|
||||
for i, v := range stats {
|
||||
fmt.Fprintf(f, "%d,%s,%d,%d,%d,%d,%d,%d\n", i, v.date, v.adds, v.dels, sum, sum+v.adds, sum-v.dels, sum+v.adds-v.dels)
|
||||
sum += v.adds - v.dels
|
||||
}
|
||||
}
|
||||
continue
|
||||
|
||||
case "log":
|
||||
args = append(args, "--color")
|
||||
args = append(args, strings.Split(m.Confx("git_log"), " ")...)
|
||||
args = append(args, fmt.Sprintf("--%s", m.Confx("git_log_form")))
|
||||
args = append(args, m.Confx("git_log_skip", arg, 1, "--skip=%s"))
|
||||
args = append(args, m.Confx("git_log_line", arg, 2, "-n %s"))
|
||||
default:
|
||||
args = append(args, arg[1:]...)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case "commit":
|
||||
m.Find("web.code").Cmd("counter", "ncommit", 1)
|
||||
case "push":
|
||||
m.Find("web.code").Cmd("counter", "npush", 1)
|
||||
}
|
||||
|
||||
m.Log("info", "cmd: %s %v", "git", kit.Trans("-C", p, c, args))
|
||||
msg := m.Sess("cli").Cmd("system", "git", "-C", p, c, args)
|
||||
m.Copy(msg, "result").Copy(msg, "append")
|
||||
m.Echo("\n")
|
||||
}
|
||||
}
|
||||
return
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -280,6 +280,14 @@ func Select(value string, args ...interface{}) string {
|
||||
|
||||
switch arg := args[0].(type) {
|
||||
case string:
|
||||
if len(args) > 1 {
|
||||
switch b := args[1].(type) {
|
||||
case bool:
|
||||
if b && arg != "" {
|
||||
return arg
|
||||
}
|
||||
}
|
||||
}
|
||||
if arg != "" {
|
||||
return arg
|
||||
}
|
||||
@ -414,6 +422,11 @@ func Chain(root interface{}, args ...interface{}) interface{} {
|
||||
return root
|
||||
}
|
||||
|
||||
func Duration(arg ...string) time.Duration {
|
||||
d, _ := time.ParseDuration(arg[0])
|
||||
return d
|
||||
}
|
||||
|
||||
func Time(arg ...string) int {
|
||||
if len(arg) == 0 {
|
||||
return Int(time.Now())
|
||||
|
Loading…
x
Reference in New Issue
Block a user