package cli import ( "bytes" "io" "net/http" "os" "os/exec" "path" "runtime" "strings" "syscall" ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/lex" "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/nfs" kit "shylinux.com/x/toolkits" "shylinux.com/x/toolkits/file" ) func _path_split(ps string) []string { ps = kit.ReplaceAll(ps, "\\", nfs.PS) return kit.Split(ps, lex.NL+kit.Select(nfs.DF, ";", strings.Contains(ps, ";")), lex.NL) } func _system_cmd(m *ice.Message, arg ...string) *exec.Cmd { bin, env := "", kit.Simple(m.Optionv(CMD_ENV)) kit.For(env, func(k, v string) { if k == PATH { if bin = _system_find(m, arg[0], _path_split(v)...); bin != "" { m.Logs(FIND, "envpath cmd", bin) } } }) if bin == "" { if bin = _system_find(m, arg[0], EtcPath(m)...); bin != "" { m.Logs(FIND, "etcpath cmd", bin) } } if bin == "" { if bin = _system_find(m, arg[0], m.Option(CMD_DIR), ice.BIN, nfs.PWD); bin != "" { m.Logs(FIND, "contexts cmd", bin) } } if bin == "" && !strings.Contains(arg[0], nfs.PS) { if bin = _system_find(m, arg[0]); bin != "" { m.Logs(FIND, "systems cmd", bin) } } if bin == "" && !strings.Contains(arg[0], nfs.PS) { m.Cmd(MIRRORS, CMD, arg[0]) if bin = _system_find(m, arg[0]); bin != "" { m.Logs(FIND, "mirrors cmd", bin) } } arg[0] = kit.Select(arg[0], bin) if m.Cmd(SUDO, arg[0]).Length() > 0 { m.Logs(FIND, "sudo cmd", arg[0]) arg = kit.Simple(SUDO, arg) } cmd := exec.Command(arg[0], arg[1:]...) if cmd.Dir = kit.TrimPath(m.Option(CMD_DIR)); len(cmd.Dir) > 0 { if m.Logs(EXEC, CMD_DIR, cmd.Dir); !nfs.Exists(m, cmd.Dir) { file.MkdirAll(cmd.Dir, ice.MOD_DIR) } } kit.For(env, func(k, v string) { cmd.Env = append(cmd.Env, kit.Format("%s=%s", k, v)) }) kit.If(len(cmd.Env) > 0 && m.IsDebug(), func() { m.Logs(EXEC, CMD_ENV, kit.Format(cmd.Env)) }) if runtime.GOOS == "windows" { cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} } return cmd } func _system_out(m *ice.Message, out string) io.Writer { if w, ok := m.Optionv(out).(io.Writer); ok { return w } else if m.Option(out) == "" { return nil } else if f, p, e := file.CreateFile(m.Option(out)); m.Assert(e) { m.Logs(nfs.SAVE, out, p).Optionv(out, f) return f } return nil } func _system_exec(m *ice.Message, cmd *exec.Cmd) { if r, ok := m.Optionv(CMD_INPUT).(io.Reader); ok { cmd.Stdin = r } if w := _system_out(m, CMD_OUTPUT); w != nil { cmd.Stdout, cmd.Stderr = w, w if w := _system_out(m, CMD_ERRPUT); w != nil { cmd.Stderr = w } } else { out := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS)) err := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS)) cmd.Stdout, cmd.Stderr = out, err defer func() { m.Push(CMD_OUT, out.String()).Push(CMD_ERR, err.String()) if m.Echo(out.String()).Echo(err.String()); m.IsErr() { m.Option(ice.MSG_ARGS, kit.Simple(http.StatusBadRequest, cmd.Args, err.String())) m.Echo(strings.TrimRight(err.String(), lex.NL)) m.Info("err: %v", err.String()) m.Info("out: %v", out.String()) } }() } if e := cmd.Run(); !m.WarnNotValid(e, cmd.Args) { m.Cost(CODE, _system_code(cmd), EXEC, cmd.Args) } m.Push(mdb.TIME, m.Time()).Push(CODE, _system_code(cmd)).StatusTime() } func _system_code(cmd *exec.Cmd) string { return kit.Select("1", "0", cmd.ProcessState != nil && cmd.ProcessState.Success()) } func _system_find(m *ice.Message, bin string, dir ...string) string { if strings.Contains(bin, nfs.DF) { return bin } else if strings.HasPrefix(bin, nfs.PS) { return bin } else if strings.HasPrefix(bin, nfs.PWD) { return bin } kit.If(len(dir) == 0, func() { dir = append(dir, _path_split(kit.Env(PATH))...) }) for _, p := range dir { if nfs.Exists(m, path.Join(p, bin)) { return kit.Path(p, bin) } else if IsWindows() && nfs.Exists(m, path.Join(p, bin)+".exe") { return kit.Path(p, bin) + ".exe" } } if nfs.Exists(m, bin) { return kit.Path(bin) } return "" } const ( TIME_300ms = "300ms" TIME_30ms = "30ms" TIME_30s = "30s" TIME_3s = "3s" TIME_1s = "1s" CMD_DIR = "cmd_dir" CMD_ENV = "cmd_env" CMD_INPUT = "cmd_input" CMD_OUTPUT = "cmd_output" CMD_ERRPUT = "cmd_errput" CMD_ERR = "cmd_err" CMD_OUT = "cmd_out" RUN = "run" REST = "rest" PARAM = "param" OPENS = "opens" RELAY = "relay" ) const ( SH = "sh" LN = "ln" MV = "mv" RM = "rm" CD = "cd" CAT = "cat" FIND = "find" GREP = "grep" TAIL = "tail" WGET = "wget" CURL = "curl" SUDO = "sudo" EXEC = "exec" EXIT = "exit" ECHO = "echo" KILL = "kill" GO = "go" GIT = "git" MAN = "man" YUM = "yum" ) const SYSTEM = "system" func init() { Index.MergeCommands(ice.Commands{ SYSTEM: {Name: "system cmd", Help: "系统命令", Actions: ice.MergeActions(ice.Actions{ nfs.PUSH: {Hand: func(m *ice.Message, arg ...string) { kit.For(arg, func(p string) { kit.If(!kit.IsIn(p, EtcPath(m)...), func() { m.Cmd(nfs.PUSH, ice.ETC_PATH, strings.TrimSpace(p)+lex.NL) }) }) m.Cmdy(nfs.CAT, ice.ETC_PATH) }}, FIND: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_system_find(m, arg[0], arg[1:]...)) }}, MAN: {Hand: func(m *ice.Message, arg ...string) { kit.If(len(arg) == 1, func() { arg = append(arg, "") }) m.Echo(SystemCmds(m, "man %s %s|col -b", kit.Select("", arg[1], arg[1] != "1"), arg[0])) }}, OPENS: {Hand: func(m *ice.Message, arg ...string) { Opens(m, arg...) }}, }), Hand: func(m *ice.Message, arg ...string) { if _system_exec(m, _system_cmd(m, arg...)); IsSuccess(m) && m.Append(CMD_ERR) == "" { m.SetAppend() } }}, }) ice.Info.SystemCmd = func(m *ice.Message, arg ...ice.Any) *ice.Message { return m.Cmd(append([]ice.Any{SYSTEM}, arg...)...) } } func SystemFindGit(m *ice.Message) bool { return SystemFind(m, GIT) != "" } func SystemFindGo(m *ice.Message) bool { return SystemFind(m, GO) != "" } func SystemFind(m *ice.Message, bin string, dir ...string) string { dir = append(dir, EtcPath(m)...) return _system_find(m, bin, append(dir, _path_split(kit.Env(PATH))...)...) } func SystemExec(m *ice.Message, arg ...string) string { return strings.TrimSpace(m.Cmdx(SYSTEM, arg)) } func SystemCmds(m *ice.Message, cmds string, args ...ice.Any) string { return strings.TrimRight(m.Cmdx(SYSTEM, SH, "-c", kit.Format(cmds, args...), ice.Option{CMD_OUTPUT, ""}), lex.NL) } func IsSuccess(m *ice.Message) bool { return m.Append(CODE) == "" || m.Append(CODE) == "0" } var _cache_path []string func Shell(m *ice.Message) string { return kit.Select(SH, os.Getenv(SHELL)) } func EtcPath(m *ice.Message) (res []string) { if len(_cache_path) > 0 { return _cache_path } nfs.Exists(m, ice.ETC_PATH, func(p string) { kit.For(strings.Split(m.Cmdx(nfs.CAT, p, kit.Dict(aaa.UserRole, aaa.ROOT)), lex.NL), func(p string) { kit.If(p != "" && !strings.HasPrefix(p, "# "), func() { res = append(res, p) }) }) }) _cache_path = res return }