1
0
forked from x/icebergs
This commit is contained in:
harveyshao 2022-12-07 03:12:29 +08:00
parent bff7fab4d6
commit 35c5a799f1
17 changed files with 378 additions and 553 deletions

5
base/base.shy Normal file
View File

@ -0,0 +1,5 @@
label `
ctx mdb web aaa
lex yac ssh gdb
tcp nfs cli log
`

View File

@ -165,7 +165,7 @@ func init() {
mdb.HashSelect(m) mdb.HashSelect(m)
return 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) == "" { if _system_exec(m, _system_cmd(m, kit.Simple(kit.Split(arg[0]), arg[1:])...)); IsSuccess(m) && m.Append(CMD_ERR) == "" {
m.SetAppend() m.SetAppend()
} }

View File

@ -27,6 +27,9 @@ func DisplayTableCard(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayTable(m, "style", "card") return DisplayTable(m, "style", "card")
} }
func DisplayStory(m *ice.Message, file string, arg ...ice.Any) *ice.Message { 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) { if !strings.HasPrefix(file, ice.PS) && !strings.HasPrefix(file, ice.HTTP) {
file = path.Join(ice.PLUGIN_STORY, file) file = path.Join(ice.PLUGIN_STORY, file)
} }

View File

@ -3,6 +3,7 @@ package mdb
import ( import (
"path" "path"
"strings" "strings"
"sync"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits" 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...) 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
}

View File

@ -21,9 +21,10 @@ func PushNotice(m *ice.Message, arg ...ice.Any) {
if m.Option(ice.MSG_DAEMON) == "" { if m.Option(ice.MSG_DAEMON) == "" {
return return
} }
m.Optionv(ice.MSG_OPTS, m.Optionv(ice.MSG_OPTION))
if m.Option(ice.MSG_USERPOD) == "" { 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 { } else {
opts := kit.Dict(ice.POD, m.Option(ice.MSG_DAEMON), "cmds", kit.Simple(arg...)) opts := kit.Dict(ice.POD, m.Option(ice.MSG_DAEMON), "cmds", kit.Simple(arg...))
for _, k := range kit.Simple(m.Optionv(ice.MSG_OPTS)) { 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) 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))...) 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) { func Toast30s(m *ice.Message, text string, arg ...ice.Any) {
Toast(m, text, kit.List(kit.Select("", arg, 0), kit.Select("30s", arg, 1))...) Toast(m, text, kit.List(kit.Select("", arg, 0), kit.Select("30s", arg, 1))...)

View File

@ -29,7 +29,9 @@ const (
) )
func Render(m *ice.Message, cmd string, args ...ice.Any) bool { 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) }() 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, "") RenderType(m.W, nfs.JSON, "")
m.W.Write([]byte(arg[0])) m.W.Write([]byte(arg[0]))
case ice.RENDER_VOID:
// no output
default: default:
for _, k := range kit.Simple(m.Optionv("option"), m.Optionv("_option")) { for _, k := range kit.Simple(m.Optionv("option"), m.Optionv("_option")) {
if m.Option(k) == "" { if m.Option(k) == "" {

View File

@ -1,10 +1,7 @@
package git package git
import ( import (
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits" 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) return _git_cmds(m, "config", "--global", key, value)
} }
func _configs_get(m *ice.Message, key string) string { func _configs_get(m *ice.Message, key string) string {
if msg := _git_cmd(m, "config", "--global", key); cli.IsSuccess(msg) { return _git_cmds(m, "config", "--global", key)
return msg.Result()
}
return ""
} }
func _configs_list(m *ice.Message) { func _configs_list(m *ice.Message) {
for _, v := range strings.Split(_configs_get(m, "--list"), ice.NL) { kit.SplitKV(ice.EQ, ice.NL, _configs_get(m, "--list"), func(text string, ls []string) {
if ls := strings.Split(v, "="); len(ls) > 1 { m.Push(mdb.NAME, ls[0]).Push(mdb.VALUE, ls[1]).PushButton(mdb.REMOVE)
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)
}) })
mdb.HashSelectValue(m, func(value ice.Maps) { m.Push("", value, kit.Split("name,value")).PushButton(mdb.CREATE) })
m.StatusTimeCount()
} }
const CONFIGS = "configs" const CONFIGS = "configs"
func init() { func init() {
Index.Merge(&ice.Context{Configs: ice.Configs{ Index.MergeCommands(ice.Commands{
CONFIGS: {Name: CONFIGS, Help: "配置键", Value: kit.Data( 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( mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,value", ice.INIT, kit.Dict(
"alias", kit.Dict("s", "status", "b", "branch", "l", "log --oneline --decorate"), "alias", kit.Dict("s", "status", "b", "branch", "l", "log --oneline --decorate"),
"credential", kit.Dict("helper", "store"), "credential", kit.Dict("helper", "store"),
"core", kit.Dict("quotepath", "false"), "core", kit.Dict("quotepath", "false"),
"push", kit.Dict("default", "simple"), "push", kit.Dict("default", "simple"),
"color", kit.Dict("ui", "always"), "color", kit.Dict("ui", "always"),
))}, ),
}, Commands: ice.Commands{ )), Hand: func(m *ice.Message, arg ...string) {
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) {
if len(arg) == 0 { if len(arg) == 0 {
_configs_list(m) _configs_list(m)
} else { } else if len(arg) == 1 {
m.Echo(_configs_get(m, arg[0])) m.Echo(_configs_get(m, arg[0]))
} else {
m.Echo(_configs_set(m, arg[0], arg[1]))
} }
}}, }},
}}) })
} }

View File

@ -16,9 +16,7 @@ func _count_count(m *ice.Message, arg []string, cb func(string)) {
m.Echo("to many file, please choice sub dir") m.Echo("to many file, please choice sub dir")
return return
} }
m.Option(nfs.DIR_DEEP, ice.TRUE) m.Cmdy(nfs.DIR, arg, kit.Dict(nfs.DIR_DEEP, ice.TRUE, nfs.DIR_TYPE, nfs.TYPE_CAT), func(file string) {
m.Option(nfs.DIR_TYPE, nfs.TYPE_CAT)
m.Cmdy(nfs.DIR, arg, func(file string) {
if strings.Contains(file, "node_modules/") { if strings.Contains(file, "node_modules/") {
return return
} }
@ -44,46 +42,35 @@ const COUNT = "count"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.MergeCommands(ice.Commands{
COUNT: {Name: "count path auto count order tags", Help: "代码行", Actions: ice.Actions{ 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{} files := map[string]int{}
_count_count(m, arg, func(file string) { _count_count(m, arg, func(file string) {
m.Cmdy(nfs.CAT, file, func(text string, line int) { m.Cmdy(nfs.CAT, file, func(text string) { files[strings.TrimPrefix(file, arg[0])]++ })
files[strings.TrimPrefix(file, arg[0])]++
})
}) })
for k, n := range files { kit.Fetch(files, func(k string, v int) { m.Push("files", k).Push("lines", v) })
m.Push("files", k)
m.Push("lines", n)
}
m.StatusTimeCount().SortIntR("lines") 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{} count := map[string]int{}
m.Cmd(nfs.CAT, path.Join(arg[0], "tags"), func(line string) { m.Cmd(nfs.CAT, path.Join(arg[0], nfs.TAGS), func(line string) {
ls := strings.SplitN(line, ice.TB, 3) if ls := strings.SplitN(line, ice.TB, 3); len(ls) < 3 {
if len(ls) < 3 {
return return
} } else if ls = strings.SplitN(ls[2], ";\"", 2); len(ls) < 2 {
ls = strings.SplitN(ls[2], ";\"", 2)
if len(ls) < 2 {
return return
} else {
count[kit.Split(ls[1])[0]]++
} }
ls = kit.Split(ls[1])
count[ls[0]]++
}) })
for k, v := range count { kit.Fetch(count, func(k string, v int) { m.Push(mdb.TYPE, k).Push(mdb.COUNT, v) })
m.Push("type", k) m.SortIntR(mdb.COUNT)
m.Push("count", v)
}
m.SortIntR("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{} files := map[string]int{}
lines := map[string]int{} lines := map[string]int{}
_count_count(m, arg, func(file string) { _count_count(m, arg, func(file string) {
files[mdb.TOTAL]++ files[mdb.TOTAL]++
files[kit.Ext(file)]++ 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 { if kit.Ext(file) == code.GO {
switch { switch {
case strings.HasPrefix(text, "func"): case strings.HasPrefix(text, "func"):
@ -92,16 +79,11 @@ func init() {
lines["_type"]++ lines["_type"]++
} }
} }
lines[mdb.TOTAL]++ lines[mdb.TOTAL]++
lines[kit.Ext(file)]++ lines[kit.Ext(file)]++
}) })
}) })
for k := range lines { kit.Fetch(lines, func(k string, v int) { m.Push(mdb.TYPE, k).Push("files", files[k]).Push("lines", lines[k]) })
m.Push(mdb.TYPE, k)
m.Push("files", files[k])
m.Push("lines", lines[k])
}
m.StatusTime().SortIntR("lines") m.StatusTime().SortIntR("lines")
}}, }},
}, Hand: func(m *ice.Message, arg ...string) { m.Cmdy(nfs.DIR, arg) }}, }, Hand: func(m *ice.Message, arg ...string) { m.Cmdy(nfs.DIR, arg) }},

View File

@ -1,26 +1,35 @@
package git package git
import ( import (
"path"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web" "shylinux.com/x/icebergs/base/web"
"shylinux.com/x/icebergs/core/code" "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_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" const GIT = "git"
var Index = &ice.Context{Name: GIT, Help: "代码库", Commands: ice.Commands{ var Index = &ice.Context{Name: GIT, Help: "代码库", Commands: ice.Commands{
GIT: {Name: "git path auto order build download", Help: "代码库", Actions: ice.MergeActions(ice.Actions{ 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.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") 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) { }, 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)
}}, }},
}} }}

View File

@ -1,6 +1,7 @@
package git package git
import ( import (
"os"
"path" "path"
"strings" "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())) 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 { 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) { func _repos_init(m *ice.Message, p string) string {
if s, e := nfs.StatFile(m, m.Option(cli.CMD_DIR, path.Join(dir, ".git"))); e == nil && s.IsDir() { os.MkdirAll(path.Join(p, "refs/heads/"), ice.MOD_DIR)
ci, _ := gogit.OpenRepository(path.Join(dir, ".git")).GetCurrentCommit() os.MkdirAll(path.Join(p, "objects/info/"), ice.MOD_DIR)
mdb.HashCreate(m, mdb.NAME, name, nfs.PATH, dir, m.Cmd(nfs.SAVE, path.Join(p, "HEAD"), "ref: refs/heads/master")
COMMIT, strings.TrimSpace(ci.CommitMessage), mdb.TIME, ci.Author.When.Format(ice.MOD_TIME), return p
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_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 ( const (
REMOTE = "remote"
ORIGIN = "origin" ORIGIN = "origin"
BRANCH = "branch" BRANCH = "branch"
MASTER = "master" MASTER = "master"
INIT = "init"
CLONE = "clone"
INIT = "init"
) )
const REPOS = "repos" const REPOS = "repos"
@ -49,34 +57,39 @@ func init() {
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { 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]) }) 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()) _repos_insert(m, path.Base(kit.Pwd()), kit.Pwd())
cli.IsAlpine(m, GIT) cli.IsSystem(m, GIT)
cli.IsCentos(m, GIT)
cli.IsUbuntu(m, GIT)
}}, }},
mdb.CREATE: {Name: "create repos branch name path", Hand: func(m *ice.Message, arg ...string) { INIT: {Hand: func(m *ice.Message, arg ...string) {
m.OptionDefault(mdb.NAME, strings.TrimSuffix(path.Base(m.Option(REPOS)), ".git")) 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(nfs.PATH, path.Join(ice.USR, m.Option(mdb.NAME)))
m.OptionDefault(REPOS, m.Config(REPOS)+m.Option(mdb.NAME)) if _repos_insert(m, m.Option(mdb.NAME), m.Option(nfs.PATH)) {
_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() {
return return
} }
if s, e := nfs.StatFile(m, m.Option(nfs.PATH)); e == nil && s.IsDir() { m.Cmd("", INIT, kit.Dict(cli.CMD_DIR, m.Option(nfs.PATH)))
m.Option(cli.CMD_DIR, m.Option(nfs.PATH)) _repos_insert(m, m.Option(mdb.NAME), 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))
}
}}, }},
}, 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 { if len(arg) == 0 {
mdb.HashSelect(m, arg...).Sort(mdb.NAME).RenameAppend(mdb.NAME, REPOS) mdb.HashSelect(m, arg...)
} else { } 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
`

View File

@ -6,7 +6,6 @@ import (
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"io" "io"
"net/http"
"path" "path"
"strconv" "strconv"
"strings" "strings"
@ -22,26 +21,10 @@ import (
kit "shylinux.com/x/toolkits" 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 { 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)) && m.Conf("web.serve", kit.Keym(tcp.LOCALHOST)) == ice.TRUE {
if tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) { return nil
return nil // 本机请求
}
} }
ls := strings.SplitN(m.R.Header.Get(web.Authorization), ice.SP, 2) ls := strings.SplitN(m.R.Header.Get(web.Authorization), ice.SP, 2)
if strings.ToLower(ls[0]) != "basic" { if strings.ToLower(ls[0]) != "basic" {
return fmt.Errorf("Authentication '%s' was not of 'Basic' type", ls[0]) 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 { if err != nil {
return err return err
} }
if ls = strings.SplitN(string(data), ice.DF, 2); !aaa.UserLogin(m, ls[0], ls[1]) { 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 { if aaa.UserRole(m, ls[0]) == aaa.VOID {
return fmt.Errorf("userrole has no right") // 没有权限 return fmt.Errorf("userrole has no right")
} }
return nil return nil
} }
func _server_param(m *ice.Message, arg ...string) (string, string) { func _server_param(m *ice.Message, arg ...string) (string, string) {
repos, service := path.Join(arg...), kit.Select(arg[len(arg)-1], m.Option("service")) repos, service := path.Join(arg...), kit.Select(arg[len(arg)-1], m.Option("service"))
switch { switch {
case strings.HasSuffix(repos, "info/refs"): case strings.HasSuffix(repos, INFO_REFS):
repos = strings.TrimSuffix(repos, "info/refs") repos = strings.TrimSuffix(repos, INFO_REFS)
default: default:
repos = strings.TrimSuffix(repos, service) 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 { func _server_repos(m *ice.Message, arg ...string) error {
repos, service := _server_param(m, arg...) 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)) 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, _git_cmds(m, service, "--stateless-rpc", "--advertise-refs", ice.PT))
_server_writer(m, "# service=git-"+service+ice.NL, msg.Result())
return nil return nil
} }
reader, err := _server_reader(m) reader, err := _server_reader(m)
if err != nil { if err != nil {
return err return err
} }
defer reader.Close() defer reader.Close()
m.Options(cli.CMD_INPUT, reader, cli.CMD_OUTPUT, m.W)
m.Option(cli.CMD_OUTPUT, m.W)
m.Option(cli.CMD_INPUT, reader)
web.RenderType(m.W, "", kit.Format("application/x-git-%s-result", service)) web.RenderType(m.W, "", kit.Format("application/x-git-%s-result", service))
_git_cmd(m, service, "--stateless-rpc", ice.PT) _git_cmd(m, service, "--stateless-rpc", ice.PT)
return nil return nil
@ -108,49 +85,43 @@ func _server_reader(m *ice.Message) (io.ReadCloser, error) {
return m.R.Body, nil return m.R.Body, nil
} }
const (
INFO_REFS = "info/refs"
)
const SERVER = "server" const SERVER = "server"
func init() { func init() {
web.Index.MergeCommands(ice.Commands{"/x/": {Hand: func(m *ice.Message, arg ...string) { m.Cmdy("web.code.git.repository", arg) }}}) web.Index.MergeCommands(ice.Commands{"/x/": {Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
Index.MergeCommands(ice.Commands{ if m.RenderVoid(); m.Option("go-get") == "1" {
web.WEB_LOGIN: {Hand: func(m *ice.Message, arg ...string) { m.Render(ice.RENDER_VOID) }}, p := _git_url(m, path.Join(arg...))
"repository": {Name: "repository", Help: "代码库", Hand: func(m *ice.Message, arg ...string) { m.RenderResult(kit.Format(`<meta name="go-import" content="%s">`, kit.Format(`%s git %s`, strings.Split(p, "://")[1], p)))
if m.Option("go-get") == "1" { // 下载地址 return
p := web.MergeLink(m, "/x/"+path.Join(arg...)) }
m.RenderResult(kit.Format(`<meta name="%s" content="%s">`, "go-import", kit.Format(`%s git %s`, strings.Split(p, "://")[1], p))) 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 return
} }
}
switch repos, service := _server_param(m, arg...); service { m.Warn(_server_repos(m, arg...), ice.ErrNotValid)
case "receive-pack": // 上传代码 }}})
if err := _server_login(m); err != nil { Index.MergeCommands(ice.Commands{
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())
}
}},
SERVER: {Name: "server path auto create import", Help: "服务器", Actions: ice.MergeActions(ice.Actions{ 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) { mdb.CREATE: {Name: "create name*", Hand: func(m *ice.Message, arg ...string) {
m.Option(cli.CMD_DIR, ice.USR_LOCAL_REPOS) _repos_init(m, path.Join(ice.USR_LOCAL_REPOS, m.Option(mdb.NAME)))
_git_cmd(m, INIT, "--bare", m.Option(mdb.NAME))
}}, }},
mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { mdb.IMPORT: {Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(REPOS, ice.OptionFields("time,name,path"), func(value ice.Maps) { ReposList(m).Tables(func(value ice.Maps) {
m.Option(cli.CMD_DIR, value[nfs.PATH]) 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, remote, MASTER)
_git_cmd(m, PUSH, "--tags", 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) { web.DREAM_INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] { switch arg[0] {
case nfs.REPOS: case nfs.REPOS:
m.Cmd("web.code.git.server", func(value ice.Maps) { m.Cmd("", func(value ice.Maps) {
m.Push(nfs.PATH, web.MergeLink(m, path.Join("/x/", path.Clean(value[nfs.PATH])+".git"))) 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) { }, 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 { if m.Option(nfs.DIR_ROOT, ice.USR_LOCAL_REPOS); len(arg) == 0 {
m.Cmdy(nfs.DIR, nfs.PWD, func(value ice.Maps) { 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.PushScript("git clone " + web.MergeLink(m, "/x/"+path.Clean(value[nfs.PATH])))
}).Cut("time,path,size,script,action")
return
} }
m.Cmdy("_sum", path.Join(m.Option(nfs.DIR_ROOT), arg[0]))
}}, }},
}) })
} }

View File

@ -5,130 +5,59 @@ import (
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web"
"shylinux.com/x/icebergs/core/code" "shylinux.com/x/icebergs/core/code"
kit "shylinux.com/x/toolkits" 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" const SPIDE = "spide"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.MergeCommands(ice.Commands{
SPIDE: {Name: "spide repos auto", Help: "构架图", Actions: ice.MergeActions(ice.Actions{ SPIDE: {Name: "spide repos auto depend", Help: "构架图", Actions: ice.MergeActions(ice.Actions{
"depend": {Name: "depend path=icebergs/base", Help: "依赖", Hand: func(m *ice.Message, arg ...string) { "depend": {Name: "depend path*=icebergs/base pkg=shy,all", Help: "依赖", Hand: func(m *ice.Message, arg ...string) {
keys := map[string]bool{} list, keys := map[string]map[string]bool{}, map[string]bool{}
list := map[string]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) {
dir := path.Join(ice.USR, m.Option(nfs.PATH)) + ice.PS if strings.HasPrefix(text, "!_") {
_spide_for(m.Cmdx(cli.SYSTEM, "gotags", "-R", dir), func(ls []string) { return
if kit.Select("", ls, 3) != "i" { } else if kit.Select("", ls, 3) != "i" {
return
} else if !strings.Contains(ls[0], m.Option(nfs.PATH)) && m.Option("pkg") == "shy" {
return return
} }
if !strings.Contains(ls[0], m.Option(nfs.PATH)) {
return
}
item, ok := list[ls[0]] item, ok := list[ls[0]]
if !ok { if !ok {
item = map[string]bool{} item = map[string]bool{}
list[ls[0]] = item list[ls[0]] = item
} }
p := strings.TrimPrefix(path.Dir(ls[1]), path.Join(ice.USR, m.Option(nfs.PATH))) p := strings.TrimPrefix(path.Dir(ls[1]), path.Join(ice.USR, m.Option(nfs.PATH)))
keys[p], item[p] = true, true keys[p], item[p] = true, true
}) })
item := kit.SortedKey(keys) item := kit.SortedKey(keys)
for k, v := range list { for k, v := range list {
m.Push("pkg", k) m.Push("pkg", k).Push(mdb.COUNT, len(v))
m.Push(mdb.COUNT, len(v))
for _, i := range item { for _, i := range item {
m.Push(i, kit.Select("", ice.OK, v[i])) m.Push(i, kit.Select("", ice.OK, v[i]))
} }
} }
m.SortIntR(mdb.COUNT) m.StatusTimeCount().SortIntR(mdb.COUNT)
m.ProcessInner() }}, code.INNER: {Name: web.CODE_INNER},
}}, code.INNER: {Name: "web.code.inner"},
}, ctx.CmdAction()), Hand: func(m *ice.Message, arg ...string) { }, 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) m.Cmdy(REPOS)
return } else if len(arg) == 1 {
}
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)
color := []string{cli.YELLOW, cli.BLUE, cli.CYAN, cli.RED} 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)]) m.Push(cli.COLOR, color[strings.Count(value[nfs.PATH], ice.PS)%len(color)])
}) m.Push("", value, []string{nfs.PATH})
return }, 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)
}}, }},
}) })
} }

View File

@ -2,9 +2,11 @@ package git
import ( import (
"path" "path"
"runtime"
"strings" "strings"
"time" "time"
"shylinux.com/x/gogit"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/cli"
@ -18,6 +20,9 @@ import (
) )
func _status_tag(m *ice.Message, tags string) string { 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) ls := kit.Split(strings.TrimPrefix(kit.Split(tags, "-")[0], "v"), ice.PT)
if v := kit.Int(ls[2]); v < 9 { if v := kit.Int(ls[2]); v < 9 {
return kit.Format("v%v.%v.%v", ls[0], ls[1], v+1) 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" return "v0.0.1"
} }
func _status_tags(m *ice.Message, repos string) { func _status_tags(m *ice.Message) {
vs := ice.Maps{} vs := ice.Maps{}
m.Cmd(STATUS, func(value ice.Maps) { m.Cmd(STATUS, func(value ice.Maps) {
if value[mdb.TYPE] == "##" { if value[mdb.TYPE] == "##" {
@ -38,23 +43,15 @@ func _status_tags(m *ice.Message, repos string) {
vs[value[REPOS]] = strings.Split(value[TAGS], "-")[0] vs[value[REPOS]] = strings.Split(value[TAGS], "-")[0]
} }
}) })
web.GoToast(m, TAGS, func(toast func(string, int, int)) { web.GoToast(m, TAGS, func(toast func(string, int, int)) {
count, total := 0, len(vs) count, total := 0, len(vs)
toast(cli.BEGIN, count, total) defer toast(ice.SUCCESS, count, count)
defer web.PushNoticeRefresh(m)
for k := range vs { for k := range vs {
if k != repos && repos != "" { if count++; k == ice.ICE {
continue
}
if k == ice.ICE {
k = ice.RELEASE k = ice.RELEASE
} }
count++
toast(k, count, total)
change := false change := false
toast(k, count, total)
m.Option(nfs.DIR_ROOT, _repos_path(k)) m.Option(nfs.DIR_ROOT, _repos_path(k))
mod := m.Cmdx(nfs.CAT, ice.GO_MOD, func(text string, line int) string { mod := m.Cmdx(nfs.CAT, ice.GO_MOD, func(text string, line int) string {
ls := kit.Split(strings.TrimPrefix(text, ice.REQUIRE)) 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 { 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) m.Logs(mdb.MODIFY, REPOS, ls[0], "from", ls[1], "to", v)
text = strings.ReplaceAll(text, ls[1], v) text, change = strings.ReplaceAll(text, ls[1], v), true
change = true
} }
return text return text
}) })
if !change || mod == "" { if mod == "" || !change {
continue continue
} }
m.Cmd(nfs.SAVE, ice.GO_SUM, "")
m.Cmd(nfs.SAVE, ice.GO_MOD, mod) m.Cmd(nfs.SAVE, ice.GO_MOD, mod)
switch m.Option(cli.CMD_DIR, _repos_path(k)); k { switch m.Option(cli.CMD_DIR, _repos_path(k)); k {
case ice.RELEASE, ice.ICEBERGS, ice.TOOLKITS: case ice.RELEASE, ice.ICEBERGS, ice.TOOLKITS:
m.Cmd(cli.SYSTEM, code.GO, cli.BUILD) m.Cmd(cli.SYSTEM, code.GO, cli.BUILD)
case ice.CONTEXTS:
defer m.Cmd(cli.SYSTEM, cli.MAKE)
default: default:
m.Cmd(cli.SYSTEM, cli.MAKE) m.Cmd(cli.SYSTEM, cli.MAKE)
} }
} }
toast(ice.SUCCESS, count, count)
}) })
} }
func _status_each(m *ice.Message, title string, cmds ...string) { func _status_each(m *ice.Message, title string, cmds ...string) {
web.GoToast(m, title, func(toast func(string, int, int)) { web.GoToast(m, title, func(toast func(string, int, int)) {
count, total := 0, len(m.Confm(REPOS, mdb.HASH)) list, count, total := []string{}, 0, len(m.Confm(REPOS, mdb.HASH))
toast(cli.BEGIN, count, total) ReposList(m).Tables(func(value ice.Maps) {
list := []string{}
m.Cmd(REPOS, ice.OptionFields("name,path"), func(value ice.Maps) {
toast(value[REPOS], count, total) toast(value[REPOS], count, total)
if msg := m.Cmd(cmds, kit.Dict(cli.CMD_DIR, value[nfs.PATH])); !cli.IsSuccess(msg) {
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]).Sleep3s()
web.Toast3s(m, msg.Append(cli.CMD_ERR), "error: "+value[REPOS])
list = append(list, value[REPOS]) list = append(list, value[REPOS])
m.Sleep3s()
} }
count++ count++
}) })
if len(list) > 0 { if len(list) > 0 {
web.Toast30s(m, strings.Join(list, ice.NL), ice.FAILURE) web.Toast30s(m, strings.Join(list, ice.NL), ice.FAILURE)
} else { } else {
toast(ice.SUCCESS, count, total) toast(ice.SUCCESS, count, total)
web.PushNoticeRefresh(m)
} }
}) })
m.ProcessHold()
} }
func _status_stat(m *ice.Message, files, adds, dels int) (int, int, int) { func _status_stat(m *ice.Message, files, adds, dels int) (int, int, int) {
res := _git_cmds(m, DIFF, "--shortstat") for _, v := range kit.Split(_git_cmds(m, DIFF, "--shortstat") , ice.FS, ice.FS) {
for _, v := range kit.Split(res, ice.FS, ice.FS) {
n := kit.Int(kit.Split(strings.TrimSpace(v))[0]) n := kit.Int(kit.Split(strings.TrimSpace(v))[0])
switch { switch {
case strings.Contains(v, "file"): case strings.Contains(v, "file"):
files += n files += n
case strings.Contains(v, "insert"): case strings.Contains(v, "inser"):
adds += n adds += n
case strings.Contains(v, "delet"): case strings.Contains(v, "delet"):
dels += n dels += n
@ -126,19 +112,17 @@ func _status_stat(m *ice.Message, files, adds, dels int) (int, int, int) {
return files, adds, dels return files, adds, dels
} }
func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) { func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) {
defer m.Sort("repos,type") ReposList(m).Tables(func(value ice.Maps) {
m.Cmd(REPOS, ice.OptionFields("name,path")).Tables(func(value ice.Maps) { if m.Option(cli.CMD_DIR, value[nfs.PATH]); runtime.GOOS != cli.DARWIN {
msg := m.Spawn(kit.Dict(cli.CMD_DIR, value[nfs.PATH])) files, adds, dels = _status_stat(m, files, adds, dels)
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
} }
if repos, e := gogit.OpenRepository(_git_dir(value[nfs.PATH])); e == nil {
for _, v := range strings.Split(strings.TrimSpace(diff), ice.NL) { 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 == "" { if v == "" {
continue 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: case "swp", "swo", ice.BIN, ice.VAR:
continue continue
} }
switch m.Push(REPOS, value[REPOS]).Push(mdb.TYPE, vs[0]).Push(nfs.FILE, vs[1]); vs[0] {
m.Push(REPOS, value[REPOS])
m.Push(mdb.TYPE, vs[0])
m.Push(nfs.FILE, vs[1])
list := []string{}
switch vs[0] {
case "##": case "##":
m.Push(TAGS, strings.TrimSpace(tags)) if m.Push(TAGS, strings.TrimSpace(tags)); strings.Contains(vs[1], "ahead") || !strings.Contains(vs[1], "...") {
if tags == ice.ErrWarn || tags == "" { m.PushButton(PUSH)
list = append(list, TAG) } else if tags == "" || strings.Contains(tags, "-") {
} m.PushButton(TAG)
} else {
if strings.Contains(vs[1], "ahead") || !strings.Contains(vs[1], "...") { m.PushButton("")
list = append(list, PUSH)
} else if strings.Contains(tags, "-") {
list = append(list, TAG)
} }
default: default:
m.Push(TAGS, "") if m.Push(TAGS, ""); strings.Contains(vs[0], "??") {
if strings.Contains(vs[0], "??") { m.PushButton(ADD, nfs.TRASH)
list = append(list, ADD, nfs.TRASH)
} else { } else {
list = append(list, COMMIT) m.PushButton(COMMIT)
} }
} }
m.PushButton(list)
} }
}) })
return return
} }
const ( const (
PULL = "pull" PULL = "pull"
MAKE = "make" PUSH = "push"
PUSH = "push" DIFF = "diff"
TAGS = "tags"
STASH = "stash"
COMMIT = "commit"
ADD = "add" ADD = "add"
OPT = "opt" OPT = "opt"
@ -190,12 +166,8 @@ const (
TAG = "tag" TAG = "tag"
PIE = "pie" PIE = "pie"
TAGS = "tags"
DIFF = "diff"
COMMIT = "commit"
COMMENT = "comment" COMMENT = "comment"
VERSION = "version" VERSION = "version"
STASH = "stash"
) )
const STATUS = "status" const STATUS = "status"
@ -204,118 +176,101 @@ func init() {
STATUS: {Name: "status repos auto", Help: "状态机", Actions: ice.MergeActions(ice.Actions{ STATUS: {Name: "status repos auto", Help: "状态机", Actions: ice.MergeActions(ice.Actions{
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] { 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: case COMMENT:
m.Push(mdb.TEXT, m.Option(nfs.FILE)) m.Push(mdb.TEXT, m.Option(nfs.FILE))
for _, v := range kit.Split(m.Option(nfs.FILE), " /") { for _, v := range kit.Split(m.Option(nfs.FILE), " /") {
m.Push(mdb.TEXT, v) 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: case aaa.USERNAME:
m.Push(arg[0], kit.Select(m.Option(ice.MSG_USERNAME), _configs_get(m, "user.name"))) 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: {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.name", m.Option(aaa.USERNAME))
_configs_set(m, "user.email", m.Option(aaa.EMAIL)) _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) 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) _status_each(m, PULL, cli.SYSTEM, GIT, PULL)
}}, }},
code.COMPILE: {Name: "compile", Help: "编译", Hand: func(m *ice.Message, arg ...string) { PUSH: {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) {
if m.Option(REPOS) == "" { if m.Option(REPOS) == "" {
_status_each(m, PUSH, cli.SYSTEM, GIT, PUSH) _status_each(m, PUSH, cli.SYSTEM, GIT, PUSH)
return return
} }
m.Option(cli.CMD_DIR, _repos_path(m.Option(REPOS))) m.Option(cli.CMD_DIR, _repos_path(m.Option(REPOS)))
if strings.TrimSpace(_git_cmds(m, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}")) == "" { 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 { } else {
_git_cmd(m, PUSH) _git_cmd(m, PUSH)
} }
_git_cmd(m, PUSH, "--tags") _git_cmd(m, PUSH, "--tags")
}}, }},
TAGS: {Name: "tags", Help: "标签", Hand: func(m *ice.Message, arg ...string) { ADD: {Help: "添加", Hand: func(m *ice.Message, arg ...string) {
_status_tags(m, kit.Select("", arg, 0)) _repos_cmd(m, m.Option(REPOS), ADD, m.Option(nfs.FILE))
m.ProcessHold() }}, OPT: {Help: "优化"}, PRO: {Help: "升级"},
}}, COMMIT: {Name: "commit action=opt,add,pro comment=some", Help: "提交", Hand: func(m *ice.Message, arg ...string) {
PIE: {Name: "pie", Help: "饼图", Hand: func(m *ice.Message, arg ...string) { _repos_cmd(m, m.Option(REPOS), COMMIT, "-am", m.Option("action")+ice.SP+m.Option(COMMENT))
m.Cmdy(TOTAL, PIE) mdb.Cache(m, m.PrefixKey(m.Option(REPOS), TAGS), nil)
}},
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))
m.ProcessBack() 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) == "" { if m.Option(VERSION) == "" {
m.Option(VERSION, _status_tag(m, m.Option(TAGS))) 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), TAG, m.Option(VERSION))
_repos_cmd(m, m.Option(REPOS), PUSH, "--tags") _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) { for _, line := range kit.Split(_repos_cmd(m.Spawn(), arg[0], BRANCH).Result(), ice.NL, ice.NL) {
if strings.HasPrefix(line, "*") { if strings.HasPrefix(line, "*") {
m.Push(BRANCH, strings.TrimPrefix(line, "* ")) m.Push(BRANCH, strings.TrimPrefix(line, "* ")).PushButton("")
m.PushButton("")
} else { } else {
m.Push(BRANCH, strings.TrimSpace(line)) m.Push(BRANCH, strings.TrimSpace(line)).PushButton("branch_switch")
m.PushButton("branch_switch")
} }
} }
}}, }},
"branch_switch": {Name: "branch_switch", Help: "切换", Hand: func(m *ice.Message, arg ...string) { "branch_switch": {Help: "切换", Hand: func(m *ice.Message, arg ...string) {
_repos_cmd(m.Spawn(), m.Option(REPOS), "checkout", m.Option(BRANCH)) _repos_cmd(m, 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)
}}, }},
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
nfs.Trash(m, path.Join(_repos_path(m.Option(REPOS)), m.Option(nfs.FILE))) 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_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.Cmd(nfs.LINK, ice.GO_MOD, path.Join(ice.SRC_RELEASE, ice.GO_MOD))
m.Cmdy(nfs.CAT, ice.GO_MOD) m.Cmdy(nfs.CAT, ice.GO_MOD)
m.Cmdy(code.VIMER, code.BINPACK) 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) m.Cmdy(code.VIMER, code.DEVPACK)
}}, }},
web.DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) { web.DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) {
@ -323,7 +278,7 @@ func init() {
return return
} }
text := []string{} 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") { if list := kit.Split(line); strings.Contains(line, "file") {
text = append(text, list[0]+" file") text = append(text, list[0]+" file")
} else if strings.Contains(line, "ins") { } 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) { }, gdb.EventAction(web.DREAM_TABLES), ctx.CmdAction(), aaa.RoleAction()), Hand: func(m *ice.Message, arg ...string) {
if _configs_get(m, "user.email") == "" { if _configs_get(m, "user.email") == "" {
m.Echo("please config user.email") m.Echo("please config user.email").Action(CONFIGS)
m.Action(CONFIGS) } else if len(arg) == 0 {
return defer web.ToastProcess(m)()
}
if len(arg) == 0 {
web.ToastProcess(m, "status")
m.Action(PULL, code.COMPILE, PUSH, TAGS, PIE, code.PUBLISH)
files, adds, dels, last := _status_list(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)) m.StatusTimeCount("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) m.Action(PULL, PUSH, TAGS, PIE, code.COMPILE, code.PUBLISH)
return } 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])
}}, }},
}) })
} }

View File

@ -17,154 +17,113 @@ import (
const TOTAL = "total" const TOTAL = "total"
func init() { func init() {
Index.Merge(&ice.Context{Configs: ice.Configs{ const (
TOTAL: {Name: TOTAL, Help: "统计量", Value: kit.Data( FROM = "from"
"skip", kit.Dict( DAYS = "days"
"wubi-dict", ice.TRUE, "word-dict", ice.TRUE, COMMIT = "commit"
"websocket", ice.TRUE, "go-qrcode", ice.TRUE, ADDS = "adds"
"go-sql-mysql", ice.TRUE, "echarts", ice.TRUE, DELS = "dels"
), REST = "rest"
)}, )
}, Commands: ice.Commands{ Index.MergeCommands(ice.Commands{
TOTAL: {Name: "total repos auto pie", Help: "统计量", Actions: ice.Actions{ TOTAL: {Name: "total repos auto pie", Help: "统计量", Actions: ice.MergeActions(ice.Actions{
PIE: {Name: "pie", Help: "饼图", Hand: func(m *ice.Message, arg ...string) { PIE: {Help: "饼图", Hand: func(m *ice.Message, arg ...string) {
defer ctx.DisplayStory(m, "pie.js") defer ctx.DisplayStory(m, "pie.js")
m.Cmd(TOTAL, func(value ice.Maps) { m.Cmd("", func(value ice.Maps) {
if value[REPOS] == mdb.TOTAL { if value[REPOS] != mdb.TOTAL {
m.StatusTimeCount(REPOS, mdb.TOTAL, mdb.VALUE, "1", mdb.TOTAL, value["rest"]) m.Push(REPOS, value[REPOS]).Push(mdb.VALUE, value[REST]).Push("", value, []string{FROM, DAYS, COMMIT, ADDS, DELS})
return
} }
m.Push(REPOS, value[REPOS])
m.Push(mdb.VALUE, value["rest"])
}) })
}}, }},
}, Hand: func(m *ice.Message, arg ...string) { }, 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 { // 提交详情 if len(arg) > 0 {
arg[0] = kit.Replace(arg[0], ice.SRC, ice.CONTEXTS) ReposList(m).Tables(func(value ice.Maps) {
m.Cmd(REPOS, ice.OptionFields("name,path"), func(value ice.Maps) { kit.If(value[REPOS] == arg[0], func() { m.Cmdy("_sum", value[nfs.PATH], arg[1:]) })
if value[REPOS] == arg[0] {
m.Cmdy("_sum", value[nfs.PATH], arg[1:])
}
}) })
m.StatusTimeCount(FROM, m.Append(FROM))
return return
} }
// 提交统计
from, days, commit, adds, dels, rest := "", 0, 0, 0, 0, 0 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 { if m.Config(kit.Keys("skip", value[REPOS])) == ice.TRUE {
return return
} }
msg := m.Cmd("_sum", value[nfs.PATH], mdb.TOTAL, "10000") 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()() defer lock.Lock()()
msg.Tables(func(value ice.Maps) { msg.Tables(func(value ice.Maps) {
if kit.Int(value["days"]) > days { if kit.Int(value[DAYS]) > days {
days = kit.Int(value["days"]) from, days = value[FROM], kit.Int(value[DAYS])
from = value["from"]
} }
commit += kit.Int(value["commit"]) commit += kit.Int(value[COMMIT])
adds += kit.Int(value["adds"]) adds += kit.Int(value[ADDS])
dels += kit.Int(value["dels"]) dels += kit.Int(value[DELS])
rest += kit.Int(value["rest"]) rest += kit.Int(value[REST])
}) })
m.Push(REPOS, value[REPOS]).Copy(msg)
m.Push(REPOS, value[REPOS])
m.Copy(msg)
}) })
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.Push(REPOS, mdb.TOTAL) m.StatusTimeCount().SortIntR(REST)
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)
}}, }},
"_sum": {Name: "_sum [path] [total] [count|date] args...", Help: "统计量", Hand: func(m *ice.Message, arg ...string) { "_sum": {Name: "_sum [path] [total] [count|date] args...", Help: "统计量", Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 { if len(arg) > 0 {
if s, e := nfs.StatFile(m, path.Join(arg[0], ".git")); 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:]
} else if s, e := nfs.StatFile(m, path.Join(arg[0], "refs")); e == nil && s.IsDir() {
m.Option(cli.CMD_DIR, arg[0]) m.Option(cli.CMD_DIR, arg[0])
arg = arg[1:] arg = arg[1:]
} }
} }
total := false
total := false // 累积求和
if len(arg) > 0 && arg[0] == mdb.TOTAL { if len(arg) > 0 && arg[0] == mdb.TOTAL {
total, arg = true, arg[1:] total, arg = true, arg[1:]
} }
args := []string{"log", "--shortstat", "--pretty=commit: %ad %n%s", "--date=iso", "--reverse"} args := []string{"log", "--shortstat", "--pretty=commit: %ad %n%s", "--date=iso", "--reverse"}
if len(arg) > 0 { if len(arg) > 0 {
if strings.Contains(arg[0], "-") && !strings.Contains(arg[0], ":") { arg[0] += kit.Select("", " 00:00:00", strings.Contains(arg[0], "-") && !strings.Contains(arg[0], ice.DF))
arg[0] = arg[0] + " 00:00:00"
}
args = append(args, kit.Select("-n", "--since", strings.Contains(arg[0], "-"))) args = append(args, kit.Select("-n", "--since", strings.Contains(arg[0], "-")))
args = append(args, arg...) args = append(args, arg...)
} else { } else {
args = append(args, "-n", "30") args = append(args, "-n", "30")
} }
from, days, commit, adds, dels := "", time.Second, 0, 0, 0
var total_day time.Duration
from, count, count_add, count_del := "", 0, 0, 0
for i, v := range strings.Split(_git_cmds(m, args...), "commit: ") { for i, v := range strings.Split(_git_cmds(m, args...), "commit: ") {
l := strings.Split(v, ice.NL) ls := strings.Split(strings.TrimSpace(v), ice.NL)
hs := strings.Split(l[0], ice.SP) if len(ls) < 2 {
if len(l) < 2 {
continue continue
} }
add, del := "0", "0" add, del := "0", "0"
if len(l) > 3 { for _, v := range kit.Split(strings.TrimSpace(kit.Select("", ls, -1)), ice.FS) {
for _, v := range kit.Split(strings.TrimSpace(l[3]), ice.FS) { switch {
switch { case strings.Contains(v, "inser"):
case strings.Contains(v, "insert"): add = kit.Split(v)[0]
add = kit.Split(v)[0] case strings.Contains(v, "delet"):
case strings.Contains(v, "delet"): del = kit.Split(v)[0]
del = kit.Split(v)[0]
}
} }
} }
hs := strings.Split(ls[0], ice.SP)
if total { // 累积求和 if total {
if count++; i == 1 { if commit++; i == 1 {
if t, e := time.Parse("2006-01-02", hs[0]); e == nil { if t, e := time.Parse("2006-01-02", hs[0]); e == nil {
total_day = time.Now().Sub(t) from, days = hs[0], time.Now().Sub(t)
m.Append("from", hs[0])
} }
} }
count_add += kit.Int(add) adds += kit.Int(add)
count_del += kit.Int(del) dels += kit.Int(del)
continue continue
} }
m.Push(FROM, ls[0])
if i == 0 { m.Push(ADDS, add)
from = hs[0] m.Push(DELS, del)
} m.Push(REST, kit.Int(add)-kit.Int(del))
m.Push("date", hs[0]) m.Push(COMMIT, ls[1])
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])
} }
if total {
if total { // 累积求和 m.Push(TAGS, _git_cmds(m, "describe", "--tags"))
m.Push("from", from) m.Push(FROM, from)
m.Push("tags", _git_cmds(m, "describe", "--tags")) m.Push(DAYS, int(days.Hours())/24)
m.Push("days", int(total_day.Hours())/24) m.Push(COMMIT, commit)
m.Push("commit", count) m.Push(ADDS, adds)
m.Push("adds", count_add) m.Push(DELS, dels)
m.Push("dels", count_del) m.Push(REST, adds-dels)
m.Push("rest", count_add-count_del)
} }
}}, }},
}}) })
} }

View File

@ -4,7 +4,6 @@ import (
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/core/code"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
@ -12,18 +11,15 @@ const TREND = "trend"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.MergeCommands(ice.Commands{
TREND: {Name: "trend repos@key begin_time@date auto", Help: "趋势图", Actions: ice.MergeActions(ice.Actions{ TREND: {Name: "trend repos@key begin_time@date auto", Help: "趋势图", Actions: ice.Actions{
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(REPOS, ice.OptionFields("repos,time")) }},
m.Cmdy(REPOS, ice.OptionFields("name,time")) }, Hand: func(m *ice.Message, arg ...string) {
}}, code.INNER: {Name: "web.code.inner"}, if len(arg) == 0 {
}, ctx.CmdAction()), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 { // 仓库列表
m.Cmdy(REPOS) 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")
}}, }},
}) })
} }

View File

@ -93,6 +93,10 @@ func (m *Message) Action(arg ...Any) *Message {
func (m *Message) Status(arg ...Any) *Message { func (m *Message) Status(arg ...Any) *Message {
list, args := kit.List(), kit.Simple(arg) list, args := kit.List(), kit.Simple(arg)
for i := 0; i < len(args)-1; i += 2 { 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])) list = append(list, kit.Dict(NAME, args[i], VALUE, args[i+1]))
} }
m.Option(MSG_STATUS, kit.Format(list)) m.Option(MSG_STATUS, kit.Format(list))

View File

@ -111,6 +111,9 @@ func (m *Message) RenderResult(arg ...Any) *Message {
func (m *Message) RenderJson(arg ...Any) *Message { func (m *Message) RenderJson(arg ...Any) *Message {
return m.Render(RENDER_JSON, kit.Format(kit.Dict(arg...))) 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 { func (m *Message) IsCliUA() bool {
if m.Option(MSG_USERUA) == "" || !strings.HasPrefix(m.Option(MSG_USERUA), "Mozilla") { if m.Option(MSG_USERUA) == "" || !strings.HasPrefix(m.Option(MSG_USERUA), "Mozilla") {