diff --git a/base/base.shy b/base/base.shy new file mode 100644 index 00000000..ed35653e --- /dev/null +++ b/base/base.shy @@ -0,0 +1,5 @@ +label ` +ctx mdb web aaa +lex yac ssh gdb +tcp nfs cli log +` \ No newline at end of file diff --git a/base/cli/system.go b/base/cli/system.go index 537ed8f3..03b0a8ab 100644 --- a/base/cli/system.go +++ b/base/cli/system.go @@ -165,7 +165,7 @@ func init() { mdb.HashSelect(m) return } - mdb.HashCreate(m.Spawn(), ice.CMD, arg[0], ice.ARG, kit.Join(arg[1:], ice.SP)) + // mdb.HashCreate(m.Spawn(), ice.CMD, arg[0], ice.ARG, kit.Join(arg[1:], ice.SP)) if _system_exec(m, _system_cmd(m, kit.Simple(kit.Split(arg[0]), arg[1:])...)); IsSuccess(m) && m.Append(CMD_ERR) == "" { m.SetAppend() } diff --git a/base/ctx/display.go b/base/ctx/display.go index 2712aea5..a14fb231 100644 --- a/base/ctx/display.go +++ b/base/ctx/display.go @@ -27,6 +27,9 @@ func DisplayTableCard(m *ice.Message, arg ...ice.Any) *ice.Message { return DisplayTable(m, "style", "card") } func DisplayStory(m *ice.Message, file string, arg ...ice.Any) *ice.Message { + if file == "" { + file = kit.ExtChange(kit.FileName(2), nfs.JS) + } if !strings.HasPrefix(file, ice.PS) && !strings.HasPrefix(file, ice.HTTP) { file = path.Join(ice.PLUGIN_STORY, file) } diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index 16395e9a..0cb9594f 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -3,6 +3,7 @@ package mdb import ( "path" "strings" + "sync" ice "shylinux.com/x/icebergs" kit "shylinux.com/x/toolkits" @@ -303,3 +304,20 @@ func Config(m *ice.Message, key string, arg ...ice.Any) string { } return m.Config(key, arg...) } + +var cache = sync.Map{} + +func Cache(m *ice.Message, key string, add func() ice.Any) ice.Any { + if add == nil { + cache.Delete(key) + return nil + } + if val, ok := cache.Load(key); ok { + return val + } + if val := add(); val != nil { + cache.Store(key, val) + return val + } + return nil +} diff --git a/base/web/option.go b/base/web/option.go index f0fe63ad..cfd840ec 100644 --- a/base/web/option.go +++ b/base/web/option.go @@ -21,9 +21,10 @@ func PushNotice(m *ice.Message, arg ...ice.Any) { if m.Option(ice.MSG_DAEMON) == "" { return } - m.Optionv(ice.MSG_OPTS, m.Optionv(ice.MSG_OPTION)) if m.Option(ice.MSG_USERPOD) == "" { - m.Cmd(SPACE, m.Option(ice.MSG_DAEMON), arg) + msg := m.Spawn() + msg.Optionv(ice.MSG_OPTS, msg.Optionv(ice.MSG_OPTION, []string{})) + msg.Cmd(SPACE, m.Option(ice.MSG_DAEMON), arg) } else { opts := kit.Dict(ice.POD, m.Option(ice.MSG_DAEMON), "cmds", kit.Simple(arg...)) for _, k := range kit.Simple(m.Optionv(ice.MSG_OPTS)) { @@ -66,8 +67,9 @@ func Toast(m *ice.Message, text string, arg ...ice.Any) { // [title [duration [p } PushNoticeToast(m, text, arg) } -func Toast3s(m *ice.Message, text string, arg ...ice.Any) { +func Toast3s(m *ice.Message, text string, arg ...ice.Any) *ice.Message { Toast(m, text, kit.List(kit.Select("", arg, 0), kit.Select("3s", arg, 1))...) + return m } func Toast30s(m *ice.Message, text string, arg ...ice.Any) { Toast(m, text, kit.List(kit.Select("", arg, 0), kit.Select("30s", arg, 1))...) diff --git a/base/web/render.go b/base/web/render.go index fdd351eb..21aa4272 100644 --- a/base/web/render.go +++ b/base/web/render.go @@ -29,7 +29,9 @@ const ( ) func Render(m *ice.Message, cmd string, args ...ice.Any) bool { - if cmd != "" { + if cmd == ice.RENDER_VOID { + return true + } else if cmd != "" { defer func() { m.Logs(mdb.EXPORT, cmd, args) }() } @@ -69,9 +71,6 @@ func Render(m *ice.Message, cmd string, args ...ice.Any) bool { RenderType(m.W, nfs.JSON, "") m.W.Write([]byte(arg[0])) - case ice.RENDER_VOID: - // no output - default: for _, k := range kit.Simple(m.Optionv("option"), m.Optionv("_option")) { if m.Option(k) == "" { diff --git a/misc/git/configs.go b/misc/git/configs.go index 6e26f8d4..abf58ed6 100644 --- a/misc/git/configs.go +++ b/misc/git/configs.go @@ -1,10 +1,7 @@ package git import ( - "strings" - ice "shylinux.com/x/icebergs" - "shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/mdb" kit "shylinux.com/x/toolkits" ) @@ -13,65 +10,56 @@ func _configs_set(m *ice.Message, key, value string) string { return _git_cmds(m, "config", "--global", key, value) } func _configs_get(m *ice.Message, key string) string { - if msg := _git_cmd(m, "config", "--global", key); cli.IsSuccess(msg) { - return msg.Result() - } - return "" + return _git_cmds(m, "config", "--global", key) } func _configs_list(m *ice.Message) { - for _, v := range strings.Split(_configs_get(m, "--list"), ice.NL) { - if ls := strings.Split(v, "="); len(ls) > 1 { - m.Push(mdb.NAME, ls[0]) - m.Push(mdb.VALUE, ls[1]) - m.PushButton(mdb.REMOVE) - } - } - m.Sort(mdb.NAME) - - mdb.HashSelectValue(m, func(value ice.Maps) { - m.Push("", value, kit.Split("name,value")).PushButton(mdb.CREATE) + kit.SplitKV(ice.EQ, ice.NL, _configs_get(m, "--list"), func(text string, ls []string) { + m.Push(mdb.NAME, ls[0]).Push(mdb.VALUE, ls[1]).PushButton(mdb.REMOVE) }) + mdb.HashSelectValue(m, func(value ice.Maps) { m.Push("", value, kit.Split("name,value")).PushButton(mdb.CREATE) }) + m.StatusTimeCount() } const CONFIGS = "configs" func init() { - Index.Merge(&ice.Context{Configs: ice.Configs{ - CONFIGS: {Name: CONFIGS, Help: "配置键", Value: kit.Data( + Index.MergeCommands(ice.Commands{ + CONFIGS: {Name: "configs name value auto create import", Help: "配置键", Actions: ice.MergeActions(ice.Actions{ + mdb.IMPORT: {Help: "初始化", Hand: func(m *ice.Message, arg ...string) { + kit.Fetch(m.Configv(ice.INIT), func(p string, v ice.Any) { + kit.Fetch(v, func(k string, v string) { _configs_set(m, kit.Keys(p, k), v) }) + }) + }}, + mdb.CREATE: {Name: "create name* value*", Hand: func(m *ice.Message, arg ...string) { + _configs_set(m, m.Option(mdb.NAME), m.Option(mdb.VALUE)) + mdb.HashRemove(m, m.Option(mdb.NAME)) + }}, + mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { + mdb.HashCreate(m.Spawn(), m.OptionSimple(mdb.NAME, mdb.VALUE)) + _configs_set(m, "--unset", m.Option(mdb.NAME)) + }}, + mdb.MODIFY: {Hand: func(m *ice.Message, arg ...string) { + if arg[0] == mdb.VALUE { + mdb.HashRemove(m, m.Option(mdb.NAME)) + _configs_set(m, m.Option(mdb.NAME), arg[1]) + } + }}, + }, mdb.HashAction( mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,value", ice.INIT, kit.Dict( "alias", kit.Dict("s", "status", "b", "branch", "l", "log --oneline --decorate"), "credential", kit.Dict("helper", "store"), "core", kit.Dict("quotepath", "false"), "push", kit.Dict("default", "simple"), "color", kit.Dict("ui", "always"), - ))}, - }, Commands: ice.Commands{ - CONFIGS: {Name: "configs name auto create import", Help: "配置键", Actions: ice.Actions{ - mdb.IMPORT: {Name: "import", Help: "初始化", Hand: func(m *ice.Message, arg ...string) { - kit.Fetch(m.Configv(ice.INIT), func(conf string, value ice.Any) { - kit.Fetch(value, func(key string, value string) { _configs_set(m, kit.Keys(conf, key), value) }) - }) - }}, - mdb.CREATE: {Name: "create name value", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - _configs_set(m, m.Option(mdb.NAME), m.Option(mdb.VALUE)) - mdb.HashRemove(m, m.Option(mdb.NAME)) - }}, - mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { - mdb.HashCreate(m.Spawn(), m.OptionSimple(mdb.NAME, mdb.VALUE)) - _configs_set(m, "--unset", m.Option(mdb.NAME)) - }}, - mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { - if arg[0] == mdb.VALUE { - mdb.HashRemove(m, m.Option(mdb.NAME)) - _configs_set(m, m.Option(mdb.NAME), arg[1]) - } - }}, - }, Hand: func(m *ice.Message, arg ...string) { + ), + )), Hand: func(m *ice.Message, arg ...string) { if len(arg) == 0 { _configs_list(m) - } else { + } else if len(arg) == 1 { m.Echo(_configs_get(m, arg[0])) + } else { + m.Echo(_configs_set(m, arg[0], arg[1])) } }}, - }}) + }) } diff --git a/misc/git/count.go b/misc/git/count.go index e79706ee..7c5958bd 100644 --- a/misc/git/count.go +++ b/misc/git/count.go @@ -16,9 +16,7 @@ func _count_count(m *ice.Message, arg []string, cb func(string)) { m.Echo("to many file, please choice sub dir") return } - m.Option(nfs.DIR_DEEP, ice.TRUE) - m.Option(nfs.DIR_TYPE, nfs.TYPE_CAT) - m.Cmdy(nfs.DIR, arg, func(file string) { + m.Cmdy(nfs.DIR, arg, kit.Dict(nfs.DIR_DEEP, ice.TRUE, nfs.DIR_TYPE, nfs.TYPE_CAT), func(file string) { if strings.Contains(file, "node_modules/") { return } @@ -44,46 +42,35 @@ const COUNT = "count" func init() { Index.MergeCommands(ice.Commands{ COUNT: {Name: "count path auto count order tags", Help: "代码行", Actions: ice.Actions{ - "order": {Name: "order", Help: "排行", Hand: func(m *ice.Message, arg ...string) { + "order": {Help: "排行", Hand: func(m *ice.Message, arg ...string) { files := map[string]int{} _count_count(m, arg, func(file string) { - m.Cmdy(nfs.CAT, file, func(text string, line int) { - files[strings.TrimPrefix(file, arg[0])]++ - }) + m.Cmdy(nfs.CAT, file, func(text string) { files[strings.TrimPrefix(file, arg[0])]++ }) }) - for k, n := range files { - m.Push("files", k) - m.Push("lines", n) - } + kit.Fetch(files, func(k string, v int) { m.Push("files", k).Push("lines", v) }) m.StatusTimeCount().SortIntR("lines") }}, - "tags": {Name: "tags", Help: "索引", Hand: func(m *ice.Message, arg ...string) { + "tags": {Help: "索引", Hand: func(m *ice.Message, arg ...string) { count := map[string]int{} - m.Cmd(nfs.CAT, path.Join(arg[0], "tags"), func(line string) { - ls := strings.SplitN(line, ice.TB, 3) - if len(ls) < 3 { + m.Cmd(nfs.CAT, path.Join(arg[0], nfs.TAGS), func(line string) { + if ls := strings.SplitN(line, ice.TB, 3); len(ls) < 3 { return - } - ls = strings.SplitN(ls[2], ";\"", 2) - if len(ls) < 2 { + } else if ls = strings.SplitN(ls[2], ";\"", 2); len(ls) < 2 { return + } else { + count[kit.Split(ls[1])[0]]++ } - ls = kit.Split(ls[1]) - count[ls[0]]++ }) - for k, v := range count { - m.Push("type", k) - m.Push("count", v) - } - m.SortIntR("count") + kit.Fetch(count, func(k string, v int) { m.Push(mdb.TYPE, k).Push(mdb.COUNT, v) }) + m.SortIntR(mdb.COUNT) }}, - COUNT: {Name: "count", Help: "计数", Hand: func(m *ice.Message, arg ...string) { + COUNT: {Help: "计数", Hand: func(m *ice.Message, arg ...string) { files := map[string]int{} lines := map[string]int{} _count_count(m, arg, func(file string) { files[mdb.TOTAL]++ files[kit.Ext(file)]++ - m.Cmdy(nfs.CAT, file, func(text string, line int) { + m.Cmdy(nfs.CAT, file, func(text string) { if kit.Ext(file) == code.GO { switch { case strings.HasPrefix(text, "func"): @@ -92,16 +79,11 @@ func init() { lines["_type"]++ } } - lines[mdb.TOTAL]++ lines[kit.Ext(file)]++ }) }) - for k := range lines { - m.Push(mdb.TYPE, k) - m.Push("files", files[k]) - m.Push("lines", lines[k]) - } + kit.Fetch(lines, func(k string, v int) { m.Push(mdb.TYPE, k).Push("files", files[k]).Push("lines", lines[k]) }) m.StatusTime().SortIntR("lines") }}, }, Hand: func(m *ice.Message, arg ...string) { m.Cmdy(nfs.DIR, arg) }}, diff --git a/misc/git/git.go b/misc/git/git.go index 24c1b68d..f09d38f1 100644 --- a/misc/git/git.go +++ b/misc/git/git.go @@ -1,26 +1,35 @@ package git import ( + "path" + "strings" + ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/web" "shylinux.com/x/icebergs/core/code" + kit "shylinux.com/x/toolkits" ) +func _git_url(m *ice.Message, repos string) string { return web.MergeLink(m, "/x/"+repos+".git") } +func _git_dir(arg ...string) string { return path.Join(path.Join(arg...), ".git") } func _git_cmd(m *ice.Message, arg ...string) *ice.Message { return m.Cmd(cli.SYSTEM, GIT, arg) } -func _git_cmds(m *ice.Message, arg ...string) string { return _git_cmd(m, arg...).Result() } +func _git_cmds(m *ice.Message, arg ...string) string { + msg := _git_cmd(m, arg...) + return kit.Select("", strings.TrimSpace(msg.Result()), !msg.IsErr()) +} const GIT = "git" var Index = &ice.Context{Name: GIT, Help: "代码库", Commands: ice.Commands{ GIT: {Name: "git path auto order build download", Help: "代码库", Actions: ice.MergeActions(ice.Actions{ - cli.ORDER: {Name: "order", Help: "加载", Hand: func(m *ice.Message, arg ...string) { + cli.ORDER: {Help: "加载", Hand: func(m *ice.Message, arg ...string) { m.Cmd(code.INSTALL, cli.ORDER, m.Config(nfs.SOURCE), "_install/libexec/git-core") m.Cmdy(code.INSTALL, cli.ORDER, m.Config(nfs.SOURCE), "_install/bin") }}, }, code.InstallAction(nfs.SOURCE, "http://mirrors.tencent.com/macports/distfiles/git-cinnabar/git-2.31.1.tar.gz")), Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(code.INSTALL, nfs.SOURCE, m.Config(nfs.SOURCE), arg) + m.Cmdy(code.INSTALL, m.ConfigSimple(nfs.SOURCE), arg) }}, }} diff --git a/misc/git/repos.go b/misc/git/repos.go index 61e23543..4a8b44fd 100644 --- a/misc/git/repos.go +++ b/misc/git/repos.go @@ -1,6 +1,7 @@ package git import ( + "os" "path" "strings" @@ -19,27 +20,34 @@ func _repos_path(name string) string { return kit.Select(path.Join(ice.USR, name)+ice.PS, nfs.PWD, name == path.Base(kit.Pwd())) } func _repos_cmd(m *ice.Message, name string, arg ...string) *ice.Message { - return m.Cmdy(cli.SYSTEM, GIT, arg, ice.Option{cli.CMD_DIR, _repos_path(name)}) + m.Option(cli.CMD_DIR, _repos_path(name)) + return m.Copy(_git_cmd(m, arg...)) } -func _repos_insert(m *ice.Message, name string, dir string) { - if s, e := nfs.StatFile(m, m.Option(cli.CMD_DIR, path.Join(dir, ".git"))); e == nil && s.IsDir() { - ci, _ := gogit.OpenRepository(path.Join(dir, ".git")).GetCurrentCommit() - mdb.HashCreate(m, mdb.NAME, name, nfs.PATH, dir, - COMMIT, strings.TrimSpace(ci.CommitMessage), mdb.TIME, ci.Author.When.Format(ice.MOD_TIME), - REMOTE, strings.SplitN(nfs.CatFile(m, path.Join(dir, ".git", "FETCH_HEAD")), ice.SP, 2)[1], - BRANCH, path.Base(nfs.CatFile(m, path.Join(dir, ".git", "HEAD"))), - ) +func _repos_init(m *ice.Message, p string) string { + os.MkdirAll(path.Join(p, "refs/heads/"), ice.MOD_DIR) + os.MkdirAll(path.Join(p, "objects/info/"), ice.MOD_DIR) + m.Cmd(nfs.SAVE, path.Join(p, "HEAD"), "ref: refs/heads/master") + return p +} +func _repos_insert(m *ice.Message, name string, path string) bool { + if repos, e := gogit.OpenRepository(_git_dir(path)); e == nil { + if ci, e := repos.GetCommit(); e == nil { + mdb.HashCreate(m, REPOS, name, nfs.PATH, path, mdb.TIME, ci.Author.When.Format(ice.MOD_TIME), COMMIT, strings.TrimSpace(ci.Message), + BRANCH, repos.GetBranch(), ORIGIN, kit.Select("", kit.Slice(kit.Split(repos.GetOrigin()), -1), 0)) + } else { + mdb.HashCreate(m, REPOS, name, nfs.PATH, path, mdb.TIME, m.Time(), + BRANCH, repos.GetBranch(), ORIGIN, kit.Select("", kit.Slice(kit.Split(repos.GetOrigin()), -1), 0)) + } + return true } + return false } const ( - REMOTE = "remote" ORIGIN = "origin" BRANCH = "branch" MASTER = "master" - - CLONE = "clone" - INIT = "init" + INIT = "init" ) const REPOS = "repos" @@ -49,34 +57,39 @@ func init() { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(nfs.DIR, ice.USR, "name,path", func(value ice.Maps) { _repos_insert(m, value[mdb.NAME], value[nfs.PATH]) }) _repos_insert(m, path.Base(kit.Pwd()), kit.Pwd()) - cli.IsAlpine(m, GIT) - cli.IsCentos(m, GIT) - cli.IsUbuntu(m, GIT) + cli.IsSystem(m, GIT) }}, - mdb.CREATE: {Name: "create repos branch name path", Hand: func(m *ice.Message, arg ...string) { - m.OptionDefault(mdb.NAME, strings.TrimSuffix(path.Base(m.Option(REPOS)), ".git")) + INIT: {Hand: func(m *ice.Message, arg ...string) { + if dir := _repos_init(m, _git_dir(m.Option(cli.CMD_DIR))); m.Option(ORIGIN, kit.Select("", kit.Split(m.Option(ORIGIN)), -1)) != "" { + m.Cmd(nfs.SAVE, path.Join(dir, "config"), kit.Format(_repos_config, m.Option(ORIGIN))) + _git_cmd(m, PULL, ORIGIN, m.OptionDefault(BRANCH, MASTER)) + } + }}, + mdb.CREATE: {Name: "create origin name path", Hand: func(m *ice.Message, arg ...string) { + m.OptionDefault(mdb.NAME, strings.TrimSuffix(path.Base(m.Option(ORIGIN)), ".git")) m.OptionDefault(nfs.PATH, path.Join(ice.USR, m.Option(mdb.NAME))) - m.OptionDefault(REPOS, m.Config(REPOS)+m.Option(mdb.NAME)) - _repos_insert(m, m.Option(mdb.NAME), m.Option(nfs.PATH)) - if s, e := nfs.StatFile(m, path.Join(m.Option(nfs.PATH), ".git")); e == nil && s.IsDir() { + if _repos_insert(m, m.Option(mdb.NAME), m.Option(nfs.PATH)) { return } - if s, e := nfs.StatFile(m, m.Option(nfs.PATH)); e == nil && s.IsDir() { - m.Option(cli.CMD_DIR, m.Option(nfs.PATH)) - _git_cmd(m, INIT) - _git_cmd(m, REMOTE, ADD, ORIGIN, m.Option(REPOS)) - _git_cmd(m, PULL, ORIGIN, kit.Select(MASTER, m.Option(BRANCH))) - } else { - m.Option(cli.CMD_DIR, "") - _git_cmd(m, CLONE, "-b", kit.Select(MASTER, m.Option(BRANCH)), m.Option(REPOS), m.Option(nfs.PATH)) - } + m.Cmd("", INIT, kit.Dict(cli.CMD_DIR, m.Option(nfs.PATH))) + _repos_insert(m, m.Option(mdb.NAME), m.Option(nfs.PATH)) }}, - }, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,branch,commit,remote", REPOS, "https://shylinux.com/x/"), mdb.ClearHashOnExitAction()), Hand: func(m *ice.Message, arg ...string) { + }, mdb.HashAction(mdb.SHORT, REPOS, mdb.FIELD, "time,repos,branch,commit,origin"), mdb.ClearHashOnExitAction()), Hand: func(m *ice.Message, arg ...string) { if len(arg) == 0 { - mdb.HashSelect(m, arg...).Sort(mdb.NAME).RenameAppend(mdb.NAME, REPOS) + mdb.HashSelect(m, arg...) } else { - m.Cmdy(nfs.DIR, kit.Select("", arg, 1), "time,line,path", kit.Dict(nfs.DIR_ROOT, _repos_path(arg[0]))) + m.Cmdy(nfs.CAT, kit.Select(nfs.PWD, arg, 1), "time,line,path", kit.Dict(nfs.DIR_ROOT, _repos_path(arg[0]))) } }}, }) } +func ReposList(m *ice.Message) *ice.Message { return m.Cmd(REPOS, ice.OptionFields("repos,path")) } + +var _repos_config = ` +[remote "origin"] + url = %s + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master +` diff --git a/misc/git/server.go b/misc/git/server.go index c7dfa29c..bcbd522b 100644 --- a/misc/git/server.go +++ b/misc/git/server.go @@ -6,7 +6,6 @@ import ( "encoding/base64" "fmt" "io" - "net/http" "path" "strconv" "strings" @@ -22,26 +21,10 @@ import ( kit "shylinux.com/x/toolkits" ) -func _server_rewrite(m *ice.Message, p string, r *http.Request) { - if ua := r.Header.Get(web.UserAgent); strings.HasPrefix(ua, "Mozilla") { - ls := kit.Split(r.URL.Path, "/") - r.URL = kit.ParseURL(kit.MergeURL("/chat/cmd/web.code.inner", "path", "usr/"+ls[1]+"/", "file", path.Join(ls[2:]...))) - - // r.URL.Path = strings.Replace(r.URL.Path, "/x/", "/chat/pod/", 1) - m.Info("rewrite %v -> %v", p, r.URL.Path) // 访问服务 - - } else { - r.URL.Path = strings.Replace(r.URL.Path, "/x/", "/code/git/repository/", 1) - m.Info("rewrite %v -> %v", p, r.URL.Path) // 下载源码 - } -} func _server_login(m *ice.Message) error { - if m.Conf("web.serve", kit.Keym(tcp.LOCALHOST)) != ice.FALSE { - if tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) { - return nil // 本机请求 - } + if tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) && m.Conf("web.serve", kit.Keym(tcp.LOCALHOST)) == ice.TRUE { + return nil } - ls := strings.SplitN(m.R.Header.Get(web.Authorization), ice.SP, 2) if strings.ToLower(ls[0]) != "basic" { return fmt.Errorf("Authentication '%s' was not of 'Basic' type", ls[0]) @@ -50,43 +33,37 @@ func _server_login(m *ice.Message) error { if err != nil { return err } - if ls = strings.SplitN(string(data), ice.DF, 2); !aaa.UserLogin(m, ls[0], ls[1]) { - return fmt.Errorf("username or password error") // 登录失败 + return fmt.Errorf("username or password error") } if aaa.UserRole(m, ls[0]) == aaa.VOID { - return fmt.Errorf("userrole has no right") // 没有权限 + return fmt.Errorf("userrole has no right") } return nil } func _server_param(m *ice.Message, arg ...string) (string, string) { repos, service := path.Join(arg...), kit.Select(arg[len(arg)-1], m.Option("service")) switch { - case strings.HasSuffix(repos, "info/refs"): - repos = strings.TrimSuffix(repos, "info/refs") + case strings.HasSuffix(repos, INFO_REFS): + repos = strings.TrimSuffix(repos, INFO_REFS) default: repos = strings.TrimSuffix(repos, service) } - return kit.Path(m.Config(nfs.PATH), REPOS, strings.TrimSuffix(repos, ".git/")), strings.TrimPrefix(service, "git-") + return kit.Path(ice.USR_LOCAL_REPOS, strings.TrimSuffix(repos, ".git/")), strings.TrimPrefix(service, "git-") } func _server_repos(m *ice.Message, arg ...string) error { repos, service := _server_param(m, arg...) - - if m.Option(cli.CMD_DIR, repos); strings.HasSuffix(path.Join(arg...), "info/refs") { + if m.Option(cli.CMD_DIR, repos); strings.HasSuffix(path.Join(arg...), INFO_REFS) { web.RenderType(m.W, "", kit.Format("application/x-git-%s-advertisement", service)) - msg := _git_cmd(m, service, "--stateless-rpc", "--advertise-refs", ice.PT) - _server_writer(m, "# service=git-"+service+ice.NL, msg.Result()) + _server_writer(m, "# service=git-"+service+ice.NL, _git_cmds(m, service, "--stateless-rpc", "--advertise-refs", ice.PT)) return nil } - reader, err := _server_reader(m) if err != nil { return err } defer reader.Close() - - m.Option(cli.CMD_OUTPUT, m.W) - m.Option(cli.CMD_INPUT, reader) + m.Options(cli.CMD_INPUT, reader, cli.CMD_OUTPUT, m.W) web.RenderType(m.W, "", kit.Format("application/x-git-%s-result", service)) _git_cmd(m, service, "--stateless-rpc", ice.PT) return nil @@ -108,49 +85,43 @@ func _server_reader(m *ice.Message) (io.ReadCloser, error) { return m.R.Body, nil } +const ( + INFO_REFS = "info/refs" +) const SERVER = "server" func init() { - web.Index.MergeCommands(ice.Commands{"/x/": {Hand: func(m *ice.Message, arg ...string) { m.Cmdy("web.code.git.repository", arg) }}}) - Index.MergeCommands(ice.Commands{ - web.WEB_LOGIN: {Hand: func(m *ice.Message, arg ...string) { m.Render(ice.RENDER_VOID) }}, - "repository": {Name: "repository", Help: "代码库", Hand: func(m *ice.Message, arg ...string) { - if m.Option("go-get") == "1" { // 下载地址 - p := web.MergeLink(m, "/x/"+path.Join(arg...)) - m.RenderResult(kit.Format(``, "go-import", kit.Format(`%s git %s`, strings.Split(p, "://")[1], p))) + web.Index.MergeCommands(ice.Commands{"/x/": {Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) { + if m.RenderVoid(); m.Option("go-get") == "1" { + p := _git_url(m, path.Join(arg...)) + m.RenderResult(kit.Format(``, kit.Format(`%s git %s`, strings.Split(p, "://")[1], p))) + return + } + switch repos, service := _server_param(m, arg...); service { + case "receive-pack": + if err := _server_login(m); m.Warn(err, ice.ErrNotLogin) { + web.RenderHeader(m.W, "WWW-Authenticate", `Basic realm="git server"`) + return + } else if !nfs.ExistsFile(m, repos) { + m.Logs(mdb.CREATE, REPOS, repos) + _repos_init(m, path.Join(ice.USR_LOCAL_REPOS, repos)) + } + case "upload-pack": + if m.Warn(!nfs.ExistsFile(m, repos), ice.ErrNotFound, arg[0]) { return } - - switch repos, service := _server_param(m, arg...); service { - case "receive-pack": // 上传代码 - if err := _server_login(m); err != nil { - web.RenderHeader(m.W, "WWW-Authenticate", `Basic realm="git server"`) - web.RenderStatus(m.W, http.StatusUnauthorized, err.Error()) - return // 没有权限 - } - if !nfs.ExistsFile(m, repos) { // 创建仓库 - _git_cmd(m, INIT, "--bare", repos) - m.Logs(mdb.CREATE, REPOS, repos) - } - case "upload-pack": // 下载代码 - if m.Warn(!nfs.ExistsFile(m, repos), ice.ErrNotFound, arg[0]) { - return - } - } - - if err := _server_repos(m, arg...); err != nil { - web.RenderStatus(m.W, http.StatusInternalServerError, err.Error()) - } - }}, + } + m.Warn(_server_repos(m, arg...), ice.ErrNotValid) + }}}) + Index.MergeCommands(ice.Commands{ SERVER: {Name: "server path auto create import", Help: "服务器", Actions: ice.MergeActions(ice.Actions{ - mdb.CREATE: {Name: "create name", Help: "创建", Hand: func(m *ice.Message, arg ...string) { - m.Option(cli.CMD_DIR, ice.USR_LOCAL_REPOS) - _git_cmd(m, INIT, "--bare", m.Option(mdb.NAME)) + mdb.CREATE: {Name: "create name*", Hand: func(m *ice.Message, arg ...string) { + _repos_init(m, path.Join(ice.USR_LOCAL_REPOS, m.Option(mdb.NAME))) }}, - mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(REPOS, ice.OptionFields("time,name,path"), func(value ice.Maps) { + mdb.IMPORT: {Hand: func(m *ice.Message, arg ...string) { + ReposList(m).Tables(func(value ice.Maps) { m.Option(cli.CMD_DIR, value[nfs.PATH]) - remote := web.MergeLink(m, "/x/"+value[REPOS]) + remote := _git_url(m, value[REPOS]) _git_cmd(m, PUSH, remote, MASTER) _git_cmd(m, PUSH, "--tags", remote, MASTER) }) @@ -162,20 +133,15 @@ func init() { web.DREAM_INPUTS: {Hand: func(m *ice.Message, arg ...string) { switch arg[0] { case nfs.REPOS: - m.Cmd("web.code.git.server", func(value ice.Maps) { - m.Push(nfs.PATH, web.MergeLink(m, path.Join("/x/", path.Clean(value[nfs.PATH])+".git"))) + m.Cmd("", func(value ice.Maps) { + m.Push(nfs.PATH, _git_url(m, value[nfs.PATH])) }) - m.Sort(nfs.PATH) } }}, }, gdb.EventAction(web.DREAM_INPUTS)), Hand: func(m *ice.Message, arg ...string) { if m.Option(nfs.DIR_ROOT, ice.USR_LOCAL_REPOS); len(arg) == 0 { - m.Cmdy(nfs.DIR, nfs.PWD, func(value ice.Maps) { - m.PushScript("git clone " + web.MergeLink(m, "/x/"+path.Clean(value[nfs.PATH]))) - }).Cut("time,path,size,script,action") - return + m.Cmdy(nfs.DIR, nfs.PWD, func(value ice.Maps) { m.PushScript("git clone " + _git_url(m, value[nfs.PATH]) }).Cut("time,path,size,script,action") } - m.Cmdy("_sum", path.Join(m.Option(nfs.DIR_ROOT), arg[0])) }}, }) } diff --git a/misc/git/spide.go b/misc/git/spide.go index 1dfe87b3..6deff80d 100644 --- a/misc/git/spide.go +++ b/misc/git/spide.go @@ -5,130 +5,59 @@ import ( "strings" ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/nfs" + "shylinux.com/x/icebergs/base/web" "shylinux.com/x/icebergs/core/code" kit "shylinux.com/x/toolkits" ) -func _spide_for(text string, cb func([]string)) { - for _, line := range strings.Split(text, ice.NL) { - if len(line) == 0 || strings.HasPrefix(line, "!_") { - continue - } - cb(kit.Split(line, "\t ", "\t ", "\t ")) - } -} -func _spide_go(m *ice.Message, file string) { - _spide_for(m.Cmdx(cli.SYSTEM, "gotags", file), func(ls []string) { - switch ls[3] { - case "i": - return - case "w", "e": - return - ls[0] = "-" + ls[0] + ice.DF + strings.TrimPrefix(ls[len(ls)-1], "type:") - case "m": - if strings.HasPrefix(ls[6], "ntype") { - return - } else if strings.HasPrefix(ls[5], "ctype") { - ls[0] = strings.TrimPrefix(ls[5], "ctype:") + ice.DF + ls[0] - } else { - ls[0] = ls[3] + ice.DF + ls[0] - } - default: - ls[0] = ls[3] + ice.DF + ls[0] - } - - m.Push(mdb.NAME, ls[0]) - m.Push(nfs.FILE, ls[1]) - m.Push(nfs.LINE, strings.TrimSuffix(ls[2], ";\"")) - m.Push(mdb.TYPE, ls[3]) - m.Push(mdb.EXTRA, strings.Join(ls[4:], ice.SP)) - }) -} -func _spide_c(m *ice.Message, file string) { - _spide_for(m.Cmdx(cli.SYSTEM, "ctags", "-f", file), func(ls []string) { - m.Push(mdb.NAME, ls[0]) - m.Push(nfs.FILE, ls[1]) - m.Push(nfs.LINE, "1") - }) -} - const SPIDE = "spide" func init() { Index.MergeCommands(ice.Commands{ - SPIDE: {Name: "spide repos auto", Help: "构架图", Actions: ice.MergeActions(ice.Actions{ - "depend": {Name: "depend path=icebergs/base", Help: "依赖", Hand: func(m *ice.Message, arg ...string) { - keys := map[string]bool{} - list := map[string]map[string]bool{} - dir := path.Join(ice.USR, m.Option(nfs.PATH)) + ice.PS - _spide_for(m.Cmdx(cli.SYSTEM, "gotags", "-R", dir), func(ls []string) { - if kit.Select("", ls, 3) != "i" { + SPIDE: {Name: "spide repos auto depend", Help: "构架图", Actions: ice.MergeActions(ice.Actions{ + "depend": {Name: "depend path*=icebergs/base pkg=shy,all", Help: "依赖", Hand: func(m *ice.Message, arg ...string) { + list, keys := map[string]map[string]bool{}, map[string]bool{} + kit.SplitKV(ice.TB, ice.NL, m.Cmdx(cli.SYSTEM, "gotags", "-R", path.Join(ice.USR, m.Option(nfs.PATH)) + ice.PS), func(text string, ls []string) { + if strings.HasPrefix(text, "!_") { + return + } else if kit.Select("", ls, 3) != "i" { + return + } else if !strings.Contains(ls[0], m.Option(nfs.PATH)) && m.Option("pkg") == "shy" { return } - if !strings.Contains(ls[0], m.Option(nfs.PATH)) { - return - } - item, ok := list[ls[0]] if !ok { item = map[string]bool{} list[ls[0]] = item } - p := strings.TrimPrefix(path.Dir(ls[1]), path.Join(ice.USR, m.Option(nfs.PATH))) keys[p], item[p] = true, true }) - item := kit.SortedKey(keys) - for k, v := range list { - m.Push("pkg", k) - m.Push(mdb.COUNT, len(v)) + m.Push("pkg", k).Push(mdb.COUNT, len(v)) for _, i := range item { m.Push(i, kit.Select("", ice.OK, v[i])) } } - m.SortIntR(mdb.COUNT) - m.ProcessInner() - }}, code.INNER: {Name: "web.code.inner"}, + m.StatusTimeCount().SortIntR(mdb.COUNT) + }}, code.INNER: {Name: web.CODE_INNER}, }, ctx.CmdAction()), Hand: func(m *ice.Message, arg ...string) { - if len(kit.Slice(arg, 0, 1)) == 0 { // 仓库列表 + if len(kit.Slice(arg, 0, 1)) == 0 { m.Cmdy(REPOS) - return - } - - if arg[0] = kit.Replace(arg[0], ice.SRC, ice.CONTEXTS); arg[0] == path.Base(kit.Pwd()) { - m.Option(nfs.DIR_ROOT, path.Join(ice.SRC)+ice.PS) - } else { - m.Option(nfs.DIR_ROOT, path.Join(ice.USR, arg[0])+ice.PS) - } - ctx.DisplayStory(m, "spide.js", mdb.FIELD, nfs.PATH, "root", arg[0]) - - if len(arg) == 1 { // 目录列表 - m.Option(nfs.DIR_DEEP, ice.TRUE) + } else if len(arg) == 1 { color := []string{cli.YELLOW, cli.BLUE, cli.CYAN, cli.RED} - nfs.Dir(m, nfs.PATH).Tables(func(value ice.Maps) { + ctx.DisplayStory(m, "spide.js", mdb.FIELD, nfs.PATH, aaa.ROOT, arg[0]) + nfs.DirDeepAll(m, _repos_path(arg[0]), "", func(value ice.Maps) { m.Push(cli.COLOR, color[strings.Count(value[nfs.PATH], ice.PS)%len(color)]) - }) - return + m.Push("", value, []string{nfs.PATH}) + }, nfs.PATH) } - if arg[1] != arg[2] { - return - } - - // 语法解析 - switch m.Option(cli.CMD_DIR, m.Option(nfs.DIR_ROOT)); kit.Ext(arg[1]) { - case code.GO: - _spide_go(m, arg[1]) - case code.JS: - default: - _spide_c(m, arg[1]) - } - m.SortInt(nfs.LINE) }}, }) } diff --git a/misc/git/status.go b/misc/git/status.go index af97c628..0eaf365a 100644 --- a/misc/git/status.go +++ b/misc/git/status.go @@ -2,9 +2,11 @@ package git import ( "path" + "runtime" "strings" "time" + "shylinux.com/x/gogit" ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/cli" @@ -18,6 +20,9 @@ import ( ) func _status_tag(m *ice.Message, tags string) string { + if tags == "" { + return "v0.0.1" + } ls := kit.Split(strings.TrimPrefix(kit.Split(tags, "-")[0], "v"), ice.PT) if v := kit.Int(ls[2]); v < 9 { return kit.Format("v%v.%v.%v", ls[0], ls[1], v+1) @@ -28,7 +33,7 @@ func _status_tag(m *ice.Message, tags string) string { } return "v0.0.1" } -func _status_tags(m *ice.Message, repos string) { +func _status_tags(m *ice.Message) { vs := ice.Maps{} m.Cmd(STATUS, func(value ice.Maps) { if value[mdb.TYPE] == "##" { @@ -38,23 +43,15 @@ func _status_tags(m *ice.Message, repos string) { vs[value[REPOS]] = strings.Split(value[TAGS], "-")[0] } }) - web.GoToast(m, TAGS, func(toast func(string, int, int)) { count, total := 0, len(vs) - toast(cli.BEGIN, count, total) - defer web.PushNoticeRefresh(m) - + defer toast(ice.SUCCESS, count, count) for k := range vs { - if k != repos && repos != "" { - continue - } - if k == ice.ICE { + if count++; k == ice.ICE { k = ice.RELEASE } - count++ - toast(k, count, total) - change := false + toast(k, count, total) m.Option(nfs.DIR_ROOT, _repos_path(k)) mod := m.Cmdx(nfs.CAT, ice.GO_MOD, func(text string, line int) string { ls := kit.Split(strings.TrimPrefix(text, ice.REQUIRE)) @@ -63,61 +60,50 @@ func _status_tags(m *ice.Message, repos string) { } if v, ok := vs[kit.Slice(strings.Split(ls[0], ice.PS), -1)[0]]; ok && ls[1] != v { m.Logs(mdb.MODIFY, REPOS, ls[0], "from", ls[1], "to", v) - text = strings.ReplaceAll(text, ls[1], v) - change = true + text, change = strings.ReplaceAll(text, ls[1], v), true } return text }) - if !change || mod == "" { + if mod == "" || !change { continue } - - m.Cmd(nfs.SAVE, ice.GO_SUM, "") m.Cmd(nfs.SAVE, ice.GO_MOD, mod) switch m.Option(cli.CMD_DIR, _repos_path(k)); k { case ice.RELEASE, ice.ICEBERGS, ice.TOOLKITS: m.Cmd(cli.SYSTEM, code.GO, cli.BUILD) + case ice.CONTEXTS: + defer m.Cmd(cli.SYSTEM, cli.MAKE) default: m.Cmd(cli.SYSTEM, cli.MAKE) } } - toast(ice.SUCCESS, count, count) }) } func _status_each(m *ice.Message, title string, cmds ...string) { web.GoToast(m, title, func(toast func(string, int, int)) { - count, total := 0, len(m.Confm(REPOS, mdb.HASH)) - toast(cli.BEGIN, count, total) - - list := []string{} - m.Cmd(REPOS, ice.OptionFields("name,path"), func(value ice.Maps) { + list, count, total := []string{}, 0, len(m.Confm(REPOS, mdb.HASH)) + ReposList(m).Tables(func(value ice.Maps) { toast(value[REPOS], count, total) - - if msg := m.Cmd(cmds, ice.Option{cli.CMD_DIR, value[nfs.PATH]}); !cli.IsSuccess(msg) { - web.Toast3s(m, msg.Append(cli.CMD_ERR), "error: "+value[REPOS]) + if msg := m.Cmd(cmds, kit.Dict(cli.CMD_DIR, value[nfs.PATH])); !cli.IsSuccess(msg) { + web.Toast3s(m, msg.Append(cli.CMD_ERR), "error: "+value[REPOS]).Sleep3s() list = append(list, value[REPOS]) - m.Sleep3s() } count++ }) - if len(list) > 0 { web.Toast30s(m, strings.Join(list, ice.NL), ice.FAILURE) } else { toast(ice.SUCCESS, count, total) - web.PushNoticeRefresh(m) } }) - m.ProcessHold() } func _status_stat(m *ice.Message, files, adds, dels int) (int, int, int) { - res := _git_cmds(m, DIFF, "--shortstat") - for _, v := range kit.Split(res, ice.FS, ice.FS) { + for _, v := range kit.Split(_git_cmds(m, DIFF, "--shortstat") , ice.FS, ice.FS) { n := kit.Int(kit.Split(strings.TrimSpace(v))[0]) switch { case strings.Contains(v, "file"): files += n - case strings.Contains(v, "insert"): + case strings.Contains(v, "inser"): adds += n case strings.Contains(v, "delet"): dels += n @@ -126,19 +112,17 @@ func _status_stat(m *ice.Message, files, adds, dels int) (int, int, int) { return files, adds, dels } func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) { - defer m.Sort("repos,type") - m.Cmd(REPOS, ice.OptionFields("name,path")).Tables(func(value ice.Maps) { - msg := m.Spawn(kit.Dict(cli.CMD_DIR, value[nfs.PATH])) - diff := _git_cmds(msg, STATUS, "-sb") - tags := _git_cmds(msg, "describe", "--tags") - _files, _adds, _dels := _status_stat(msg, 0, 0, 0) - now, _ := time.Parse("2006-01-02 15:04:05 -0700", strings.TrimSpace(_git_cmds(msg, "log", `--pretty=%cd`, "--date=iso", "-n1"))) - - if files, adds, dels = files+_files, adds+_adds, dels+_dels; now.After(last) { - last = now + ReposList(m).Tables(func(value ice.Maps) { + if m.Option(cli.CMD_DIR, value[nfs.PATH]); runtime.GOOS != cli.DARWIN { + files, adds, dels = _status_stat(m, files, adds, dels) } - - for _, v := range strings.Split(strings.TrimSpace(diff), ice.NL) { + if repos, e := gogit.OpenRepository(_git_dir(value[nfs.PATH])); e == nil { + if ci, e := repos.GetCommit(); e == nil && ci.Author.When.After(last) { + last = ci.Author.When + } + } + tags := kit.Format(mdb.Cache(m, m.PrefixKey(value[REPOS], TAGS), func() ice.Any { return _git_cmds(m, "describe", "--tags") })) + for _, v := range strings.Split(strings.TrimSpace(_git_cmds(m, STATUS, "-sb")), ice.NL) { if v == "" { continue } @@ -147,42 +131,34 @@ func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) { case "swp", "swo", ice.BIN, ice.VAR: continue } - - m.Push(REPOS, value[REPOS]) - m.Push(mdb.TYPE, vs[0]) - m.Push(nfs.FILE, vs[1]) - - list := []string{} - switch vs[0] { + switch m.Push(REPOS, value[REPOS]).Push(mdb.TYPE, vs[0]).Push(nfs.FILE, vs[1]); vs[0] { case "##": - m.Push(TAGS, strings.TrimSpace(tags)) - if tags == ice.ErrWarn || tags == "" { - list = append(list, TAG) - } - - if strings.Contains(vs[1], "ahead") || !strings.Contains(vs[1], "...") { - list = append(list, PUSH) - } else if strings.Contains(tags, "-") { - list = append(list, TAG) + if m.Push(TAGS, strings.TrimSpace(tags)); strings.Contains(vs[1], "ahead") || !strings.Contains(vs[1], "...") { + m.PushButton(PUSH) + } else if tags == "" || strings.Contains(tags, "-") { + m.PushButton(TAG) + } else { + m.PushButton("") } default: - m.Push(TAGS, "") - if strings.Contains(vs[0], "??") { - list = append(list, ADD, nfs.TRASH) + if m.Push(TAGS, ""); strings.Contains(vs[0], "??") { + m.PushButton(ADD, nfs.TRASH) } else { - list = append(list, COMMIT) + m.PushButton(COMMIT) } } - m.PushButton(list) } }) return } const ( - PULL = "pull" - MAKE = "make" - PUSH = "push" + PULL = "pull" + PUSH = "push" + DIFF = "diff" + TAGS = "tags" + STASH = "stash" + COMMIT = "commit" ADD = "add" OPT = "opt" @@ -190,12 +166,8 @@ const ( TAG = "tag" PIE = "pie" - TAGS = "tags" - DIFF = "diff" - COMMIT = "commit" COMMENT = "comment" VERSION = "version" - STASH = "stash" ) const STATUS = "status" @@ -204,118 +176,101 @@ func init() { STATUS: {Name: "status repos auto", Help: "状态机", Actions: ice.MergeActions(ice.Actions{ mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { switch arg[0] { - case mdb.NAME, REPOS: - m.Cmdy(REPOS).Cut(REPOS) - - case TAGS, VERSION: - if m.Option(TAGS) == ice.ErrWarn { - m.Push(VERSION, "v0.0.1") - } else { - m.Push(VERSION, _status_tag(m, m.Option(TAGS))) - } - case COMMENT: m.Push(mdb.TEXT, m.Option(nfs.FILE)) for _, v := range kit.Split(m.Option(nfs.FILE), " /") { m.Push(mdb.TEXT, v) } + case VERSION, TAGS: + if m.Option(TAGS) == "" { + m.Push(VERSION, "v0.0.1") + } else { + m.Push(VERSION, _status_tag(m, m.Option(TAGS))) + } + case aaa.EMAIL: + m.Push(arg[0], _configs_get(m, "user.email")) case aaa.USERNAME: m.Push(arg[0], kit.Select(m.Option(ice.MSG_USERNAME), _configs_get(m, "user.name"))) - case "email": - m.Push(arg[0], _configs_get(m, "user.email")) } }}, CONFIGS: {Name: "configs email username", Help: "配置", Hand: func(m *ice.Message, arg ...string) { _configs_set(m, "user.name", m.Option(aaa.USERNAME)) _configs_set(m, "user.email", m.Option(aaa.EMAIL)) }}, - CLONE: {Name: "clone repos='https://shylinux.com/x/volcanos' path=", Help: "克隆", Hand: func(m *ice.Message, arg ...string) { + INIT: {Name: "init origin*='https://shylinux.com/x/volcanos' name path", Help: "克隆", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(REPOS, mdb.CREATE) }}, - PULL: {Name: "pull", Help: "下载", Hand: func(m *ice.Message, arg ...string) { + PULL: {Help: "下载", Hand: func(m *ice.Message, arg ...string) { _status_each(m, PULL, cli.SYSTEM, GIT, PULL) }}, - code.COMPILE: {Name: "compile", Help: "编译", Hand: func(m *ice.Message, arg ...string) { - web.ToastProcess(m) - defer web.ToastSuccess(m) - m.Cmdy(code.VIMER, code.COMPILE) - }}, - PUSH: {Name: "push", Help: "上传", Hand: func(m *ice.Message, arg ...string) { + PUSH: {Help: "上传", Hand: func(m *ice.Message, arg ...string) { if m.Option(REPOS) == "" { _status_each(m, PUSH, cli.SYSTEM, GIT, PUSH) return } - m.Option(cli.CMD_DIR, _repos_path(m.Option(REPOS))) if strings.TrimSpace(_git_cmds(m, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}")) == "" { - _git_cmd(m, PUSH, "--set-upstream", "origin", "master") + _git_cmd(m, PUSH, "--set-upstream", ORIGIN, MASTER) } else { _git_cmd(m, PUSH) } _git_cmd(m, PUSH, "--tags") }}, - TAGS: {Name: "tags", Help: "标签", Hand: func(m *ice.Message, arg ...string) { - _status_tags(m, kit.Select("", arg, 0)) - m.ProcessHold() - }}, - PIE: {Name: "pie", Help: "饼图", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(TOTAL, PIE) - }}, - STASH: {Name: "stash", Help: "缓存", Hand: func(m *ice.Message, arg ...string) { - if len(arg) == 0 && m.Option(REPOS) == "" { - _status_each(m, STASH, cli.SYSTEM, GIT, STASH) - } else { - _git_cmd(m, STASH) - } - }}, - - ADD: {Name: "add", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - _repos_cmd(m, m.Option(REPOS), ADD, m.Option(nfs.FILE)).SetAppend() - }}, OPT: {Name: "opt", Help: "优化"}, PRO: {Name: "pro", Help: "升级"}, - COMMIT: {Name: "commit action=opt,add,pro comment=some@key", Help: "提交", Hand: func(m *ice.Message, arg ...string) { - if arg[0] == ctx.ACTION { - m.Option(mdb.TEXT, arg[1]+ice.SP+arg[3]) - } else { - m.Option(mdb.TEXT, kit.Select("opt some", strings.Join(arg, ice.SP))) - } - _repos_cmd(m, m.Option(REPOS), COMMIT, "-am", m.Option(mdb.TEXT)) + ADD: {Help: "添加", Hand: func(m *ice.Message, arg ...string) { + _repos_cmd(m, m.Option(REPOS), ADD, m.Option(nfs.FILE)) + }}, OPT: {Help: "优化"}, PRO: {Help: "升级"}, + COMMIT: {Name: "commit action=opt,add,pro comment=some", Help: "提交", Hand: func(m *ice.Message, arg ...string) { + _repos_cmd(m, m.Option(REPOS), COMMIT, "-am", m.Option("action")+ice.SP+m.Option(COMMENT)) + mdb.Cache(m, m.PrefixKey(m.Option(REPOS), TAGS), nil) m.ProcessBack() }}, - TAG: {Name: "tag version@key", Help: "标签", Hand: func(m *ice.Message, arg ...string) { + TAG: {Name: "tag version", Help: "标签", Hand: func(m *ice.Message, arg ...string) { if m.Option(VERSION) == "" { m.Option(VERSION, _status_tag(m, m.Option(TAGS))) } _repos_cmd(m, m.Option(REPOS), TAG, m.Option(VERSION)) _repos_cmd(m, m.Option(REPOS), PUSH, "--tags") - m.ProcessRefresh() + mdb.Cache(m, m.PrefixKey(m.Option(REPOS), TAGS), nil) + ctx.ProcessRefresh(m) }}, - BRANCH: {Name: "branch", Help: "分支", Hand: func(m *ice.Message, arg ...string) { + TAGS: {Help: "标签", Hand: func(m *ice.Message, arg ...string) { _status_tags(m) }}, + PIE: {Help: "饼图", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(TOTAL, PIE) }}, + STASH: {Help: "缓存", Hand: func(m *ice.Message, arg ...string) { + if len(arg) == 0 && m.Option(REPOS) == "" { + _status_each(m, STASH, cli.SYSTEM, GIT, STASH) + } else { + _repos_cmd(m, kit.Select(m.Option(REPOS), arg, 0), STASH) + } + }}, + BRANCH: {Help: "分支", Hand: func(m *ice.Message, arg ...string) { for _, line := range kit.Split(_repos_cmd(m.Spawn(), arg[0], BRANCH).Result(), ice.NL, ice.NL) { if strings.HasPrefix(line, "*") { - m.Push(BRANCH, strings.TrimPrefix(line, "* ")) - m.PushButton("") + m.Push(BRANCH, strings.TrimPrefix(line, "* ")).PushButton("") } else { - m.Push(BRANCH, strings.TrimSpace(line)) - m.PushButton("branch_switch") + m.Push(BRANCH, strings.TrimSpace(line)).PushButton("branch_switch") } } }}, - "branch_switch": {Name: "branch_switch", Help: "切换", Hand: func(m *ice.Message, arg ...string) { - _repos_cmd(m.Spawn(), m.Option(REPOS), "checkout", m.Option(BRANCH)) - }}, - code.PUBLISH: {Name: "publish", Help: "发布", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(code.PUBLISH, ice.CONTEXTS, ice.MISC, ice.CORE) + "branch_switch": {Help: "切换", Hand: func(m *ice.Message, arg ...string) { + _repos_cmd(m, m.Option(REPOS), "checkout", m.Option(BRANCH)) }}, nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { nfs.Trash(m, path.Join(_repos_path(m.Option(REPOS)), m.Option(nfs.FILE))) }}, - code.BINPACK: {Name: "binpack", Help: "发布模式", Hand: func(m *ice.Message, arg ...string) { + code.COMPILE: {Help: "编译", Hand: func(m *ice.Message, arg ...string) { + defer web.ToastProcess(m)() + m.Cmdy(code.VIMER, code.COMPILE) + }}, + code.PUBLISH: {Help: "发布", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(code.PUBLISH, ice.CONTEXTS, ice.MISC, ice.CORE) + }}, + code.BINPACK: {Help: "发布模式", Hand: func(m *ice.Message, arg ...string) { m.Cmd(nfs.LINK, ice.GO_SUM, path.Join(ice.SRC_RELEASE, ice.GO_SUM)) m.Cmd(nfs.LINK, ice.GO_MOD, path.Join(ice.SRC_RELEASE, ice.GO_MOD)) m.Cmdy(nfs.CAT, ice.GO_MOD) m.Cmdy(code.VIMER, code.BINPACK) }}, - code.DEVPACK: {Name: "devpack", Help: "开发模式", Hand: func(m *ice.Message, arg ...string) { + code.DEVPACK: {Help: "开发模式", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(code.VIMER, code.DEVPACK) }}, web.DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) { @@ -323,7 +278,7 @@ func init() { return } text := []string{} - for _, line := range kit.Split(m.Cmdx(web.SPACE, m.Option(mdb.NAME), cli.SYSTEM, "git", "diff", "--shortstat"), ice.FS, ice.FS) { + for _, line := range kit.Split(m.Cmdx(web.SPACE, m.Option(mdb.NAME), cli.SYSTEM, GIT, DIFF, "--shortstat"), ice.FS, ice.FS) { if list := kit.Split(line); strings.Contains(line, "file") { text = append(text, list[0]+" file") } else if strings.Contains(line, "ins") { @@ -336,24 +291,18 @@ func init() { }}, }, gdb.EventAction(web.DREAM_TABLES), ctx.CmdAction(), aaa.RoleAction()), Hand: func(m *ice.Message, arg ...string) { if _configs_get(m, "user.email") == "" { - m.Echo("please config user.email") - m.Action(CONFIGS) - return - } - if len(arg) == 0 { - web.ToastProcess(m, "status") - m.Action(PULL, code.COMPILE, PUSH, TAGS, PIE, code.PUBLISH) + m.Echo("please config user.email").Action(CONFIGS) + } else if len(arg) == 0 { + defer web.ToastProcess(m)() files, adds, dels, last := _status_list(m) - m.Status("cost", m.FormatCost(), "repos", m.Length(), "files", files, "adds", adds, "dels", dels, "last", last.Format(ice.MOD_TIME)) - web.Toast3s(m, kit.Format("files: %d, adds: %d, dels: %d", files, adds, dels), ice.CONTEXTS) - return + m.StatusTimeCount("files", files, "adds", adds, "dels", dels, "last", last.Format(ice.MOD_TIME)) + m.Action(PULL, PUSH, TAGS, PIE, code.COMPILE, code.PUBLISH) + } else { + _repos_cmd(m, arg[0], DIFF) + files, adds, dels := _status_stat(m, 0, 0, 0) + m.StatusTime("files", files, "adds", adds, "dels", dels) + m.Action(COMMIT, TAGS, STASH, BRANCH) } - - _repos_cmd(m, arg[0], DIFF) - m.Action(COMMIT, TAGS, STASH, BRANCH) - files, adds, dels := _status_stat(m, 0, 0, 0) - m.Status("files", files, "adds", adds, "dels", dels) - web.Toast3s(m, kit.Format("files: %d, adds: %d, dels: %d", files, adds, dels), arg[0]) }}, }) } diff --git a/misc/git/total.go b/misc/git/total.go index de628e30..af44e696 100644 --- a/misc/git/total.go +++ b/misc/git/total.go @@ -17,154 +17,113 @@ import ( const TOTAL = "total" func init() { - Index.Merge(&ice.Context{Configs: ice.Configs{ - TOTAL: {Name: TOTAL, Help: "统计量", Value: kit.Data( - "skip", kit.Dict( - "wubi-dict", ice.TRUE, "word-dict", ice.TRUE, - "websocket", ice.TRUE, "go-qrcode", ice.TRUE, - "go-sql-mysql", ice.TRUE, "echarts", ice.TRUE, - ), - )}, - }, Commands: ice.Commands{ - TOTAL: {Name: "total repos auto pie", Help: "统计量", Actions: ice.Actions{ - PIE: {Name: "pie", Help: "饼图", Hand: func(m *ice.Message, arg ...string) { + const ( + FROM = "from" + DAYS = "days" + COMMIT = "commit" + ADDS = "adds" + DELS = "dels" + REST = "rest" + ) + Index.MergeCommands(ice.Commands{ + TOTAL: {Name: "total repos auto pie", Help: "统计量", Actions: ice.MergeActions(ice.Actions{ + PIE: {Help: "饼图", Hand: func(m *ice.Message, arg ...string) { defer ctx.DisplayStory(m, "pie.js") - m.Cmd(TOTAL, func(value ice.Maps) { - if value[REPOS] == mdb.TOTAL { - m.StatusTimeCount(REPOS, mdb.TOTAL, mdb.VALUE, "1", mdb.TOTAL, value["rest"]) - return + m.Cmd("", func(value ice.Maps) { + if value[REPOS] != mdb.TOTAL { + m.Push(REPOS, value[REPOS]).Push(mdb.VALUE, value[REST]).Push("", value, []string{FROM, DAYS, COMMIT, ADDS, DELS}) } - m.Push(REPOS, value[REPOS]) - m.Push(mdb.VALUE, value["rest"]) }) }}, - }, Hand: func(m *ice.Message, arg ...string) { - if len(arg) > 0 { // 提交详情 - arg[0] = kit.Replace(arg[0], ice.SRC, ice.CONTEXTS) - m.Cmd(REPOS, ice.OptionFields("name,path"), func(value ice.Maps) { - if value[REPOS] == arg[0] { - m.Cmdy("_sum", value[nfs.PATH], arg[1:]) - } + }, ctx.ConfAction("skip", kit.DictList("wubi-dict", "word-dict", "websocket", "go-qrcode", "go-sql-mysql", "echarts"))), Hand: func(m *ice.Message, arg ...string) { + if len(arg) > 0 { + ReposList(m).Tables(func(value ice.Maps) { + kit.If(value[REPOS] == arg[0], func() { m.Cmdy("_sum", value[nfs.PATH], arg[1:]) }) }) + m.StatusTimeCount(FROM, m.Append(FROM)) return } - - // 提交统计 from, days, commit, adds, dels, rest := "", 0, 0, 0, 0, 0 - m.Cmd(REPOS, ice.OptionFields("name,path")).TableGo(func(value ice.Maps, lock *task.Lock) { + ReposList(m).TableGo(func(value ice.Maps, lock *task.Lock) { if m.Config(kit.Keys("skip", value[REPOS])) == ice.TRUE { return } msg := m.Cmd("_sum", value[nfs.PATH], mdb.TOTAL, "10000") - // msg := m.Cmd("_sum", value[nfs.PATH], mdb.TOTAL, "2022-01-01") - defer lock.Lock()() msg.Tables(func(value ice.Maps) { - if kit.Int(value["days"]) > days { - days = kit.Int(value["days"]) - from = value["from"] + if kit.Int(value[DAYS]) > days { + from, days = value[FROM], kit.Int(value[DAYS]) } - commit += kit.Int(value["commit"]) - adds += kit.Int(value["adds"]) - dels += kit.Int(value["dels"]) - rest += kit.Int(value["rest"]) + commit += kit.Int(value[COMMIT]) + adds += kit.Int(value[ADDS]) + dels += kit.Int(value[DELS]) + rest += kit.Int(value[REST]) }) - - m.Push(REPOS, value[REPOS]) - m.Copy(msg) + m.Push(REPOS, value[REPOS]).Copy(msg) }) - - m.Push(REPOS, mdb.TOTAL) - m.Push("tags", "v3.0.0") - m.Push("days", days) - m.Push("commit", commit) - m.Push("adds", adds) - m.Push("dels", dels) - m.Push("rest", rest) - m.SortIntR("rest") - m.StatusTimeCount("from", from) + m.Push(REPOS, mdb.TOTAL).Push(TAGS, "v3.0.0").Push(FROM, from).Push(DAYS, days).Push(COMMIT, commit).Push(ADDS, adds).Push(DELS, dels).Push(REST, rest) + m.StatusTimeCount().SortIntR(REST) }}, "_sum": {Name: "_sum [path] [total] [count|date] args...", Help: "统计量", Hand: func(m *ice.Message, arg ...string) { if len(arg) > 0 { - if s, e := nfs.StatFile(m, path.Join(arg[0], ".git")); e == nil && s.IsDir() { - m.Option(cli.CMD_DIR, arg[0]) - arg = arg[1:] - } else if s, e := nfs.StatFile(m, path.Join(arg[0], "refs")); e == nil && s.IsDir() { + if nfs.ExistsFile(m, _git_dir(arg[0])) || nfs.ExistsFile(m, path.Join(arg[0], "refs/heads")) { m.Option(cli.CMD_DIR, arg[0]) arg = arg[1:] } } - - total := false // 累积求和 + total := false if len(arg) > 0 && arg[0] == mdb.TOTAL { total, arg = true, arg[1:] } - args := []string{"log", "--shortstat", "--pretty=commit: %ad %n%s", "--date=iso", "--reverse"} if len(arg) > 0 { - if strings.Contains(arg[0], "-") && !strings.Contains(arg[0], ":") { - arg[0] = arg[0] + " 00:00:00" - } + arg[0] += kit.Select("", " 00:00:00", strings.Contains(arg[0], "-") && !strings.Contains(arg[0], ice.DF)) args = append(args, kit.Select("-n", "--since", strings.Contains(arg[0], "-"))) args = append(args, arg...) } else { args = append(args, "-n", "30") } - - var total_day time.Duration - from, count, count_add, count_del := "", 0, 0, 0 + from, days, commit, adds, dels := "", time.Second, 0, 0, 0 for i, v := range strings.Split(_git_cmds(m, args...), "commit: ") { - l := strings.Split(v, ice.NL) - hs := strings.Split(l[0], ice.SP) - if len(l) < 2 { + ls := strings.Split(strings.TrimSpace(v), ice.NL) + if len(ls) < 2 { continue } - add, del := "0", "0" - if len(l) > 3 { - for _, v := range kit.Split(strings.TrimSpace(l[3]), ice.FS) { - switch { - case strings.Contains(v, "insert"): - add = kit.Split(v)[0] - case strings.Contains(v, "delet"): - del = kit.Split(v)[0] - } + for _, v := range kit.Split(strings.TrimSpace(kit.Select("", ls, -1)), ice.FS) { + switch { + case strings.Contains(v, "inser"): + add = kit.Split(v)[0] + case strings.Contains(v, "delet"): + del = kit.Split(v)[0] } } - - if total { // 累积求和 - if count++; i == 1 { + hs := strings.Split(ls[0], ice.SP) + if total { + if commit++; i == 1 { if t, e := time.Parse("2006-01-02", hs[0]); e == nil { - total_day = time.Now().Sub(t) - m.Append("from", hs[0]) + from, days = hs[0], time.Now().Sub(t) } } - count_add += kit.Int(add) - count_del += kit.Int(del) + adds += kit.Int(add) + dels += kit.Int(del) continue } - - if i == 0 { - from = hs[0] - } - m.Push("date", hs[0]) - m.Push("adds", add) - m.Push("dels", del) - m.Push("rest", kit.Int(add)-kit.Int(del)) - m.Push("note", l[1]) - m.Push("hour", strings.Split(hs[1], ":")[0]) - m.Push("time", hs[1]) + m.Push(FROM, ls[0]) + m.Push(ADDS, add) + m.Push(DELS, del) + m.Push(REST, kit.Int(add)-kit.Int(del)) + m.Push(COMMIT, ls[1]) } - - if total { // 累积求和 - m.Push("from", from) - m.Push("tags", _git_cmds(m, "describe", "--tags")) - m.Push("days", int(total_day.Hours())/24) - m.Push("commit", count) - m.Push("adds", count_add) - m.Push("dels", count_del) - m.Push("rest", count_add-count_del) + if total { + m.Push(TAGS, _git_cmds(m, "describe", "--tags")) + m.Push(FROM, from) + m.Push(DAYS, int(days.Hours())/24) + m.Push(COMMIT, commit) + m.Push(ADDS, adds) + m.Push(DELS, dels) + m.Push(REST, adds-dels) } }}, - }}) + }) } diff --git a/misc/git/trend.go b/misc/git/trend.go index b58adae6..d737ab0a 100644 --- a/misc/git/trend.go +++ b/misc/git/trend.go @@ -4,7 +4,6 @@ import ( ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/mdb" - "shylinux.com/x/icebergs/core/code" kit "shylinux.com/x/toolkits" ) @@ -12,18 +11,15 @@ const TREND = "trend" func init() { Index.MergeCommands(ice.Commands{ - TREND: {Name: "trend repos@key begin_time@date auto", Help: "趋势图", Actions: ice.MergeActions(ice.Actions{ - mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(REPOS, ice.OptionFields("name,time")) - }}, code.INNER: {Name: "web.code.inner"}, - }, ctx.CmdAction()), Hand: func(m *ice.Message, arg ...string) { - if len(arg) == 0 { // 仓库列表 + TREND: {Name: "trend repos@key begin_time@date auto", Help: "趋势图", Actions: ice.Actions{ + mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(REPOS, ice.OptionFields("repos,time")) }}, + }, Hand: func(m *ice.Message, arg ...string) { + if len(arg) == 0 { m.Cmdy(REPOS) - return + } else { + m.Cmdy(TOTAL, kit.Slice(arg, 0, 2)) + ctx.DisplayStory(m, "") } - arg[0] = kit.Replace(arg[0], ice.SRC, ice.CONTEXTS) - m.Cmdy(TOTAL, kit.Slice(arg, 0, 2)) - ctx.DisplayStory(m, "trend.js") }}, }) } diff --git a/option.go b/option.go index 3e67d631..804c8b2b 100644 --- a/option.go +++ b/option.go @@ -93,6 +93,10 @@ func (m *Message) Action(arg ...Any) *Message { func (m *Message) Status(arg ...Any) *Message { list, args := kit.List(), kit.Simple(arg) for i := 0; i < len(args)-1; i += 2 { + switch args[i+1] { + case "", "0": + continue + } list = append(list, kit.Dict(NAME, args[i], VALUE, args[i+1])) } m.Option(MSG_STATUS, kit.Format(list)) diff --git a/render.go b/render.go index 985ba785..7571198e 100644 --- a/render.go +++ b/render.go @@ -111,6 +111,9 @@ func (m *Message) RenderResult(arg ...Any) *Message { func (m *Message) RenderJson(arg ...Any) *Message { return m.Render(RENDER_JSON, kit.Format(kit.Dict(arg...))) } +func (m *Message) RenderVoid(arg ...Any) *Message { + return m.Render(RENDER_VOID, arg...) +} func (m *Message) IsCliUA() bool { if m.Option(MSG_USERUA) == "" || !strings.HasPrefix(m.Option(MSG_USERUA), "Mozilla") {