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)
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()
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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))...)

View File

@ -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) == "" {

View File

@ -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]))
}
}},
}})
})
}

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")
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) }},

View File

@ -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)
}},
}}

View File

@ -1,6 +1,7 @@
package git
import (
"os"
"path"
"strings"
@ -19,26 +20,33 @@ 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"
)
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
`

View File

@ -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(`<meta name="%s" content="%s">`, "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(`<meta name="go-import" content="%s">`, 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); err != nil {
case "receive-pack":
if err := _server_login(m); m.Warn(err, ice.ErrNotLogin) {
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)
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": // 下载代码
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]))
}},
})
}

View File

@ -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)
}},
})
}

View File

@ -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,33 +131,22 @@ 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
@ -181,8 +154,11 @@ func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) {
const (
PULL = "pull"
MAKE = "make"
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)
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])
m.StatusTime("files", files, "adds", adds, "dels", dels)
m.Action(COMMIT, TAGS, STASH, BRANCH)
}
}},
})
}

View File

@ -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) {
for _, v := range kit.Split(strings.TrimSpace(kit.Select("", ls, -1)), ice.FS) {
switch {
case strings.Contains(v, "insert"):
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(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])
}
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])
}
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)
}
}},
}})
})
}

View File

@ -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
}
arg[0] = kit.Replace(arg[0], ice.SRC, ice.CONTEXTS)
} else {
m.Cmdy(TOTAL, kit.Slice(arg, 0, 2))
ctx.DisplayStory(m, "trend.js")
ctx.DisplayStory(m, "")
}
}},
})
}

View File

@ -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))

View File

@ -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") {