From 83c959a14e433dfc722a1af5c3a41785dc9f4baf Mon Sep 17 00:00:00 2001 From: shylinux Date: Sun, 16 Apr 2023 16:01:33 +0800 Subject: [PATCH] opt git --- core/code/repos.go | 6 - go.mod | 2 +- misc/git/configs.go | 1 + misc/git/git.go | 2 + misc/git/repos.go | 456 ++++++++++++++++++++++++-------------------- misc/git/server.go | 215 --------------------- misc/git/spide.go | 4 +- misc/git/status.go | 37 +--- misc/git/total.go | 2 +- misc/repos/repos.go | 309 ------------------------------ 10 files changed, 264 insertions(+), 770 deletions(-) delete mode 100644 misc/git/server.go diff --git a/core/code/repos.go b/core/code/repos.go index 0b2ea31d..3b9df679 100644 --- a/core/code/repos.go +++ b/core/code/repos.go @@ -2,10 +2,7 @@ package code import ( ice "shylinux.com/x/icebergs" - "shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/nfs" - "shylinux.com/x/icebergs/base/web" - kit "shylinux.com/x/toolkits" ) const ( @@ -15,9 +12,6 @@ const REPOS = nfs.REPOS func init() { Index.MergeCommands(ice.Commands{REPOS: {Name: "repos name auto", Actions: ice.Actions{ - web.DREAM_CREATE: {Hand: func(m *ice.Message, arg ...string) { - kit.If(m.Option(nfs.REPOS), func(p string) { m.Cmd(cli.SYSTEM, GIT, "clone", p, m.Option(cli.CMD_DIR), ice.Maps{cli.CMD_DIR: ""}) }) - }}, "status": {Hand: func(m *ice.Message, arg ...string) { m.Cmdy("web.code.git.status", arg) }}, }, Hand: func(m *ice.Message, arg ...string) { m.Cmdy("web.code.git.repos", arg) }}}) } diff --git a/go.mod b/go.mod index 5e0d0422..b68731cb 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module shylinux.com/x/icebergs go 1.11 require ( + shylinux.com/x/go-git/v5 v5.6.2 shylinux.com/x/go-qrcode v0.0.2 - shylinux.com/x/gogit v0.0.7 shylinux.com/x/ice v1.3.0 shylinux.com/x/toolkits v0.7.5 shylinux.com/x/websocket v0.0.2 diff --git a/misc/git/configs.go b/misc/git/configs.go index 67b5689d..ce4efca0 100644 --- a/misc/git/configs.go +++ b/misc/git/configs.go @@ -31,6 +31,7 @@ func _configs_read(m *ice.Message, p string) ice.Maps { } const ( + CONFIG = "config" USER_NAME = "user.name" USER_EMAIL = "user.email" ) diff --git a/misc/git/git.go b/misc/git/git.go index 726a8c6c..3c4e5bd1 100644 --- a/misc/git/git.go +++ b/misc/git/git.go @@ -40,3 +40,5 @@ var Index = &ice.Context{Name: GIT, Help: "代码库", Commands: ice.Commands{ }} func init() { code.Index.Register(Index, &web.Frame{}, REPOS) } + +func Prefix(arg ...string) string { return code.Prefix(GIT, kit.Keys(arg)) } diff --git a/misc/git/repos.go b/misc/git/repos.go index d5200e14..fe318ccb 100644 --- a/misc/git/repos.go +++ b/misc/git/repos.go @@ -1,172 +1,198 @@ package git import ( - "os" + "errors" + "net/url" "path" "strings" - "shylinux.com/x/gogit" + git "shylinux.com/x/go-git/v5" + "shylinux.com/x/go-git/v5/plumbing" + "shylinux.com/x/go-git/v5/plumbing/object" + "shylinux.com/x/go-git/v5/plumbing/transport/http" + 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 _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.Copy(_git_cmd(m.Options(cli.CMD_DIR, _repos_path(name)), arg...)) + return m.Copy(_git_cmd(m.Options(cli.CMD_DIR, _repos_path(m, name)), arg...)) } -func _repos_init(m *ice.Message, dir string) string { - os.MkdirAll(path.Join(dir, REFS_HEADS), ice.MOD_DIR) - os.MkdirAll(path.Join(dir, OBJECTS_INFO), ice.MOD_DIR) - return m.Cmdx(nfs.SAVE, path.Join(dir, "HEAD"), "ref: refs/heads/master") +func _repos_path(m *ice.Message, p string, arg ...string) string { + if p == path.Base(kit.Path("")) { + return kit.Path("", arg...) + } + return path.Join(nfs.USR, p, path.Join(arg...)) } -func _repos_insert(m *ice.Message, name string, path string) bool { - if repos, e := gogit.OpenRepository(_git_dir(path)); e == nil { - origin := kit.Select("", kit.Split(repos.GetOrigin()), -1) - kit.If(origin == "", func() { origin = _configs_read(m, _git_dir(path, CONFIG))["remote.origin.url"] }) - 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, origin) +func _repos_open(m *ice.Message, p string) *git.Repository { + return mdb.HashSelectTarget(m, p, nil).(*git.Repository) +} +func _repos_init(m *ice.Message, p string) { + m.Debug("what %v", p) + git.PlainInit(p, true) +} +func _repos_insert(m *ice.Message, p string) { + if repos, err := git.PlainOpen(p); err == nil { + args := []string{REPOS, path.Base(p), nfs.PATH, p} + if refer, err := repos.Head(); err == nil { + args = append(args, BRANCH, refer.Name().String()) + if commit, err := repos.CommitObject(refer.Hash()); err == nil { + args = append(args, mdb.TIME, commit.Author.When.Format(ice.MOD_TIME), COMMIT, commit.Message) + } + } + if remote, err := repos.Remotes(); err == nil && len(remote) > 0 { + args = append(args, ORIGIN, remote[0].Config().URLs[0]) + } + mdb.HashCreate(m.Options(mdb.TARGET, repos), args) + } +} +func _repos_each(m *ice.Message, title string, cb func(*git.Repository, ice.Maps) error) { + msg := m.Cmd("") + web.GoToast(m, title, func(toast func(string, int, int)) { + list, count, total := []string{}, 0, msg.Length() + msg.Table(func(value ice.Maps) { + toast(value[REPOS], count, total) + if err := cb(_repos_open(m, value[REPOS]), value); err != nil && err != git.NoErrAlreadyUpToDate { + web.Toast(m, err.Error(), "error: "+value[REPOS], "", "3s") + list = append(list, value[REPOS]) + m.Sleep3s() + } + count++ + }) + if len(list) > 0 { + web.Toast(m, strings.Join(list, ice.NL), ice.FAILURE, "30s") } else { - mdb.HashCreate(m, REPOS, name, nfs.PATH, path, mdb.TIME, m.Time(), BRANCH, repos.GetBranch(), ORIGIN, origin) + toast(ice.SUCCESS, count, total) } - return true - } - return false + }) + } -func _repos_branch(m *ice.Message, dir string) { - if repos, e := gogit.OpenRepository(dir); !m.Warn(e, ice.ErrNotFound, dir) { - nfs.DirDeepAll(m, path.Join(dir, REFS_HEADS), "", func(value ice.Maps) { - if refer, e := repos.LookupReference(REFS_HEADS + value[nfs.PATH]); !m.Warn(e, ice.ErrNotValid, value[nfs.PATH]) { - if ci, e := repos.LookupCommit(refer.Oid); !m.Warn(e, ice.ErrNotValid, refer.Oid.String()) { - m.Push(mdb.TIME, ci.Author.When.Format(ice.MOD_TIME)).Push(BRANCH, value[nfs.PATH]) - m.Push(COMMIT, ci.Oid.Short()).Push(AUTHOR, ci.Author.Name).Push(MESSAGE, ci.Message) - } - } - }, nfs.PATH) +func _repos_log(m *ice.Message, repos *git.Repository) error { + iter, err := repos.Log(&git.LogOptions{}) + if err != nil { + return err } -} -func _repos_commit(m *ice.Message, dir, branch string, cb func(*gogit.Commit, *gogit.Repository) bool) { - if repos, e := gogit.OpenRepository(dir); !m.Warn(e, ice.ErrNotFound, dir) { - if refer, e := repos.LookupReference(REFS_HEADS + branch); !m.Warn(e, ice.ErrNotFound, branch) { - if cb == nil { - m.Push(mdb.TIME, m.Time()).Push(COMMIT, cli.PWD).Push(AUTHOR, kit.Select(m.Option(ice.MSG_USERNAME), m.Option(ice.MSG_USERNICK))).Push(MESSAGE, "opt some") - } - for oid := refer.Oid; oid != nil; { - if ci, e := repos.LookupCommit(oid); !m.Warn(e, ice.ErrNotFound, oid.String()) { - if cb == nil { - m.Push(mdb.TIME, ci.Author.When.Format(ice.MOD_TIME)).Push(COMMIT, ci.Oid.Short()).Push(AUTHOR, ci.Author.Name).Push(MESSAGE, ci.Message) - } else if cb(ci, repos) { - break - } - if p := ci.ParentCommit(0); p != nil { - oid = p.Oid - continue - } - } - break + limit := 30 + defer m.StatusTimeCount() + m.Push(mdb.TIME, m.Time()) + m.Push(COMMIT, INDEX) + m.Push(aaa.USERNAME, m.Option(ice.MSG_USERNAME)) + m.Push(mdb.TEXT, "add some") + m.Push("files", 0).Push("adds", 0).Push("dels", 0) + return iter.ForEach(func(commit *object.Commit) error { + if m.Length() > limit { + return nil + } + m.Push(mdb.TIME, commit.Author.When) + m.Push(COMMIT, commit.Hash.String()) + m.Push(aaa.USERNAME, commit.Author.Name) + m.Push(mdb.TEXT, commit.Message) + files, adds, dels := 0, 0, 0 + if stats, err := commit.Stats(); err == nil { + for _, stat := range stats { + files, adds, dels = files+1, adds+stat.Addition, dels+stat.Deletion } } - } -} -func _repos_cid(m *ice.Message, dir, branch, commit string) string { - if repos, e := gogit.OpenRepository(dir); !m.Warn(e, ice.ErrNotFound, dir) { - if refer, e := repos.LookupReference(REFS_TAGS + commit); e == nil { - m.Logs(nfs.FIND, "tags", commit, "commit", refer.Oid.String()) - commit = refer.Oid.String() - } - } - return commit -} -func _repos_dir(m *ice.Message, dir, branch, commit, file string, cb func(*gogit.TreeEntry, *gogit.Repository) bool) { - if commit == cli.PWD { - nfs.DirDeepAll(m, path.Dir(dir), file, nil, "time,line,path") - m.Options(cli.CMD_DIR, path.Dir(dir)).Echo(_git_cmds(m, DIFF)) - return - } - commit = _repos_cid(m, dir, branch, commit) - _repos_commit(m, dir, branch, func(ci *gogit.Commit, repos *gogit.Repository) bool { - if !strings.HasPrefix(ci.Oid.String(), commit) { - return false - } - prev := ice.Maps{} - if p := ci.ParentCommit(0); p != nil { - if ci, e := repos.LookupCommit(p.Oid); !m.Warn(e, ice.ErrNotFound, p.Oid.String()) { - if tree, e := repos.LookupTree(ci.TreeId()); !m.Warn(e, ice.ErrNotFound, ci.TreeId().String) { - tree.Walk(func(p string, v *gogit.TreeEntry) bool { - kit.If(v.Type == gogit.ObjectBlob, func() { prev[path.Join(p, v.Name)] = v.Oid.String() }) - return false - }) - } - } - } - if tree, e := repos.LookupTree(ci.TreeId()); !m.Warn(e, ice.ErrNotFound, ci.TreeId().String) { - m.Logs(nfs.FIND, REPOS, dir, BRANCH, branch, COMMIT, commit, TREE, tree.Oid.Short()) - tree.Walk(func(p string, v *gogit.TreeEntry) bool { - if pp := path.Join(p, v.Name) + kit.Select("", ice.PS, v.Type == gogit.ObjectTree); strings.HasPrefix(pp, file) { - if v.Type == gogit.ObjectTree { - return false - } else if cb == nil { - if id, ok := prev[pp]; ok && id == v.Oid.String() { - if m.Option(ice.MSG_INDEX) == web.CODE_INNER { - m.Push(mdb.HASH, v.Oid.Short()).Push(nfs.PATH, pp).Push(mdb.STATUS, "") - } - } else if ok { - m.Push(mdb.HASH, v.Oid.Short()).Push(nfs.PATH, pp).Push(mdb.STATUS, "~~~") - } else { - m.Push(mdb.HASH, v.Oid.Short()).Push(nfs.PATH, pp).Push(mdb.STATUS, "+++") - } - delete(prev, pp) - } else if cb(v, repos) { - return true - } - } - return false - }) - } - kit.For(prev, func(pp, id string) { m.Push(mdb.HASH, id[:6]).Push(nfs.PATH, pp).Push(mdb.STATUS, "---") }) - if m.Sort(kit.Fields(mdb.STATUS, nfs.PATH), ice.STR_R, ice.STR); cb == nil { - m.Options(cli.CMD_DIR, dir).Echo(_git_cmds(m, DIFF, ci.Oid.String()+"^", ci.Oid.String())) - m.Status(mdb.TIME, ci.Author.When.Format(ice.MOD_TIME), DIFF, _git_cmds(m, DIFF, "--shortstat", ci.Oid.String()+"^", ci.Oid.String()), MESSAGE, ci.Message) - } - return true + m.Push("files", files).Push("adds", adds).Push("dels", adds) + return nil }) } -func _repos_cat(m *ice.Message, dir, branch, commit, file string) { - if commit == cli.PWD { - m.Cmdy(nfs.CAT, path.Join(path.Dir(dir), file)) +func _repos_stats(m *ice.Message, repos *git.Repository, h string) error { + commit, err := repos.CommitObject(plumbing.NewHash(h)) + if err != nil { + return err + } + stats, err := commit.Stats() + if err != nil { + return err + } + defer m.StatusTimeCount() + for _, stat := range stats { + m.Push(nfs.FILE, stat.Name).Push("add", stat.Addition).Push("del", stat.Deletion) + } + return nil +} +func _repos_status(m *ice.Message, repos *git.Repository) error { + work, err := repos.Worktree() + if err != nil { + return err + } + status, err := work.Status() + if err != nil { + return err + } + defer m.StatusTimeCount() + for k, v := range status { + switch kit.Ext(k) { + case "swp", "swo": + continue + } + m.Push(nfs.FILE, k).Push(STATUS, string(v.Worktree)+string(v.Staging)) + switch v.Worktree { + case git.Untracked: + m.PushButton(ADD, nfs.TRASH) + case git.Modified: + m.PushButton(ADD) + default: + m.PushButton(COMMIT) + } + } + return nil +} +func _repos_vimer(m *ice.Message, _repos_path func(m *ice.Message, p string, arg ...string) string, arg ...string) { + if len(arg) == 0 || arg[0] != ice.RUN { + arg = []string{path.Join(arg[:2]...), kit.Select("README.md", arg, 2)} + } else if kit.Select("", arg, 1) != ctx.ACTION { + ls := kit.Split(kit.Select(arg[1], m.Option(nfs.DIR_ROOT)), nfs.PS) + if ls[1] == INDEX { + if len(arg) < 3 { + m.Cmdy(nfs.DIR, nfs.PWD, kit.Dict(nfs.DIR_ROOT, _repos_path(m, ls[0]))) + } else { + m.Cmdy(nfs.CAT, _repos_path(m, ls[0], arg[2])) + } + } else if commit, err := _repos_open(m, ls[0]).CommitObject(plumbing.NewHash(ls[1])); m.Warn(err) { + return + } else if len(arg) < 3 { + if iter, err := commit.Files(); !m.Warn(err) { + iter.ForEach(func(file *object.File) error { + m.Push(nfs.PATH, file.Name) + return nil + }) + } + } else { + if file, err := commit.File(arg[2]); !m.Warn(err) { + if content, err := file.Contents(); !m.Warn(err) { + m.Echo(content) + } + } + } + ctx.DisplayLocal(m, "code/vimer.js") return } - commit = _repos_cid(m, dir, branch, commit) - _repos_dir(m, dir, branch, commit, file, func(v *gogit.TreeEntry, repos *gogit.Repository) bool { - if blob, e := repos.LookupBlob(v.Oid); e == nil { - m.Logs(nfs.LOAD, REPOS, dir, BRANCH, branch, COMMIT, commit, BLOB, v.Oid.Short()).Echo(string(blob.Contents())) - } else { - m.Options(cli.CMD_DIR, dir).Echo(_git_cmds(m, "cat-file", "-p", v.Oid.String())) - } - return true - }) + ctx.ProcessField(m, "", arg, arg...) } const ( - OBJECTS_INFO = "objects/info/" - REFS_HEADS = "refs/heads/" - REFS_TAGS = "refs/tags/" - TREE = "tree" - BLOB = "blob" + CLONE = "clone" + PULL = "pull" + PUSH = "push" + LOG = "log" + ADD = "add" + TAG = "tag" + STASH = "stash" + COMMIT = "commit" - INIT = "init" - CONFIG = "config" - ORIGIN = "origin" - BRANCH = "branch" - MASTER = "master" - AUTHOR = "author" - MESSAGE = "message" + ORIGIN = "origin" + BRANCH = "branch" + MASTER = "master" + INDEX = "index" ) const REPOS = "repos" @@ -175,90 +201,114 @@ func init() { web.PP(ice.REQUIRE): {Name: "/require/shylinux.com/x/volcanos/proto.js", Help: "代码库", Hand: func(m *ice.Message, arg ...string) { if len(arg) < 4 { m.RenderStatusBadRequest() - return } else if path.Join(arg[:3]...) == ice.Info.Make.Module && nfs.Exists(m, path.Join(arg[3:]...)) { m.RenderDownload(path.Join(arg[3:]...)) - return - } - p := path.Join(kit.Select(ice.USR_REQUIRE, m.Cmdx(cli.SYSTEM, "go", "env", "GOMODCACHE")), path.Join(arg...)) - if !nfs.Exists(m, p) { - if p = path.Join(ice.USR_REQUIRE, path.Join(arg...)); !nfs.Exists(m, p) { - ls := strings.SplitN(path.Join(arg[:3]...), ice.AT, 2) - if v := kit.Select(ice.Info.Gomod[ls[0]], ls, 1); v == "" { - _git_cmd(m, "clone", "https://"+ls[0], path.Join(ice.USR_REQUIRE, path.Join(arg[:3]...))) - } else { - _git_cmd(m, "clone", "-b", v, "https://"+ls[0], path.Join(ice.USR_REQUIRE, path.Join(arg[:3]...))) + } else { + p := path.Join(kit.Select(ice.USR_REQUIRE, m.Cmdx(cli.SYSTEM, "go", "env", "GOMODCACHE")), path.Join(arg...)) + if !nfs.Exists(m, p) { + if p = path.Join(ice.USR_REQUIRE, path.Join(arg...)); !nfs.Exists(m, p) { + ls := strings.SplitN(path.Join(arg[:3]...), ice.AT, 2) + to := path.Join(ice.USR_REQUIRE, path.Join(arg[:3]...)) + _, err := git.PlainClone(to, false, &git.CloneOptions{URL: "https://" + ls[0], ReferenceName: plumbing.NewBranchReferenceName(kit.Select(ice.Info.Gomod[ls[0]], ls, 1))}) + m.Warn(err) } } + m.RenderDownload(p) } - m.RenderDownload(p) }}, }) Index.MergeCommands(ice.Commands{ - REPOS: {Name: "repos repos@key branch@key commit@key path@key auto", Help: "代码库", Actions: ice.MergeActions(ice.Actions{ + REPOS: {Name: "repos repos commit:text file:text auto", Help: "仓库", Actions: ice.MergeActions(ice.Actions{ 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.IsSystem(m, GIT) + m.Cmd(nfs.DIR, nfs.USR, func(value ice.Maps) { _repos_insert(m, value[nfs.PATH]) }) + _repos_insert(m, kit.Path("")) }}, - mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { - switch arg[0] { - case REPOS: - mdb.HashSelect(m).Cut(REPOS) - case BRANCH: - m.Cmdy("", m.Option(REPOS)).Cut(BRANCH) - case COMMIT: - m.Cmdy("", m.Option(REPOS), m.Option(BRANCH)).Cut("commit,author,message,time") - case nfs.PATH: - m.Cmdy("", m.Option(REPOS), m.Option(BRANCH), m.Option(COMMIT)).Cut("path,hash,status") - default: - mdb.HashInputs(m, arg) - } + CLONE: {Name: "clone origin* branch name path", Hand: func(m *ice.Message, arg ...string) { + m.OptionDefault(mdb.NAME, path.Base(m.Option(ORIGIN))) + m.OptionDefault(nfs.PATH, path.Join(path.Join(nfs.USR, m.Option(mdb.NAME)))) + _, err := git.PlainClone(m.Option(nfs.PATH), false, &git.CloneOptions{URL: m.Option(ORIGIN)}) + m.Warn(err) + _repos_insert(m, m.Option(nfs.PATH)) }}, - mdb.CREATE: {Name: "create origin branch name path", Hand: func(m *ice.Message, arg ...string) { - m.OptionDefault(mdb.NAME, kit.TrimExt(m.Option(ORIGIN), GIT)) - m.OptionDefault(nfs.PATH, path.Join(nfs.USR, m.Option(mdb.NAME))) - if _repos_insert(m, m.Option(mdb.NAME), m.Option(nfs.PATH)) { - return - } - m.Cmd("", INIT, kit.Dict(cli.CMD_DIR, m.Option(nfs.PATH))) - _repos_insert(m, m.Option(mdb.NAME), m.Option(nfs.PATH)) - }}, - 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(nfs.TemplateText(m, CONFIG), m.Option(ORIGIN))) - _git_cmd(m, PULL, ORIGIN, m.OptionDefault(BRANCH, MASTER)) - } - }}, - DIFF: {Hand: func(m *ice.Message, arg ...string) { - if len(arg) == 0 || arg[0] != ice.RUN { - arg = []string{path.Join(arg[:3]...), kit.Select("README.md", arg, 3)} - } else if kit.Select("", arg, 1) != ctx.ACTION { - ls := kit.Split(kit.Select(arg[1], m.Option(nfs.DIR_ROOT)), nfs.PS) - if dir := _git_dir(_repos_path(ls[0])); len(arg) < 3 { - _repos_dir(m, dir, ls[1], ls[2], kit.Select("", arg, 1), nil) + PULL: {Hand: func(m *ice.Message, arg ...string) { + _repos_each(m, "repos pull", func(repos *git.Repository, value ice.Maps) error { + if value[ORIGIN] == "" { + return nil + } else if work, err := repos.Worktree(); err != nil { + return err } else { - _repos_cat(m, dir, ls[1], ls[2], arg[2]) - ctx.DisplayLocal(m, "code/inner.js") + return work.Pull(&git.PullOptions{}) } - return + }) + }}, + PUSH: {Hand: func(m *ice.Message, arg ...string) { + list := map[string]*url.URL{} + m.Cmd(nfs.CAT, kit.HomePath(".git-credentials"), func(line string) { + u := kit.ParseURL(line) + list[u.Host] = u + }) + _repos_each(m, "repos push", func(repos *git.Repository, value ice.Maps) error { + if value[ORIGIN] == "" { + return nil + } + u := list[kit.ParseURL(value[ORIGIN]).Host] + if password, ok := u.User.Password(); !ok { + return errors.New("not found password") + } else { + return repos.Push(&git.PushOptions{Auth: &http.BasicAuth{Username: u.User.Username(), Password: password}}) + } + }) + }}, + LOG: {Hand: func(m *ice.Message, arg ...string) { + _repos_log(m, _repos_open(m, kit.Select(m.Option(REPOS), arg, 0))) + }}, + ADD: {Hand: func(m *ice.Message, arg ...string) { + if work, err := _repos_open(m, m.Option(REPOS)).Worktree(); !m.Warn(err) { + _, err := work.Add(m.Option(nfs.FILE)) + m.Warn(err) } - ctx.ProcessField(m, web.CODE_INNER, arg, arg...) + }}, + COMMIT: {Name: "commit actions=add,opt,fix comment*=some", Hand: func(m *ice.Message, arg ...string) { + if work, err := _repos_open(m, m.Option(REPOS)).Worktree(); !m.Warn(err) { + _, err := work.Commit(m.Option("actions")+ice.SP+m.Option("comment"), &git.CommitOptions{}) + m.Warn(err) + } + }}, + STATUS: {Hand: func(m *ice.Message, arg ...string) { + _repos_each(m, "repos status", func(repos *git.Repository, value ice.Maps) error { return _repos_status(m, repos) }) + }}, + STASH: {Help: "缓存", Hand: func(m *ice.Message, arg ...string) { _repos_cmd(m, kit.Select(m.Option(REPOS), arg, 0), STASH) }}, + TAG: {Name: "tag version", Help: "标签", Hand: func(m *ice.Message, arg ...string) { + kit.If(m.Option(VERSION) == "", func() { 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") + ctx.ProcessRefresh(m) + }}, + code.VIMER: {Hand: func(m *ice.Message, arg ...string) { _repos_vimer(m, _repos_path, arg...) }}, + nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { + m.Assert(m.Option(REPOS) != "") + mdb.HashRemove(m, m.Option(REPOS)) + nfs.Trash(m, _repos_path(m, m.Option(REPOS), m.Option(nfs.FILE))) + }}, + web.DREAM_CREATE: {Hand: func(m *ice.Message, arg ...string) { + kit.If(m.Option(REPOS), func(p string) { + m.Cmd("", CLONE, ORIGIN, p, nfs.PATH, m.Option(cli.CMD_DIR), ice.Maps{cli.CMD_DIR: ""}) + }) }}, }, mdb.HashAction(mdb.SHORT, REPOS, mdb.FIELD, "time,repos,branch,commit,origin"), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) { - if len(arg) == 0 || arg[0] == "" { - mdb.HashSelect(m, arg...).Action(mdb.CREATE) - } else if dir := _git_dir(_repos_path(arg[0])); len(arg) == 1 || arg[1] == "" { - _repos_branch(m, dir) - } else if len(arg) == 2 || arg[2] == "" { - _repos_commit(m, dir, arg[1], nil) - } else if len(arg) == 3 || arg[3] == "" || strings.HasSuffix(arg[3], ice.PS) { - _repos_dir(m, dir, arg[1], arg[2], kit.Select("", arg, 3), nil) - return + if len(arg) == 0 { + mdb.HashSelect(m, arg...).Action(CLONE, PULL, PUSH, STATUS) + } else if len(arg) == 1 { + _repos_log(m, _repos_open(m, arg[0])) + } else if len(arg) == 2 { + if repos := _repos_open(m, arg[0]); arg[1] == INDEX { + _repos_status(m, repos) + } else { + _repos_stats(m, repos, arg[1]) + } } else { - m.Cmdy("", DIFF, arg) + m.Cmdy("", code.VIMER, arg) } - m.StatusTimeCount() }}, }) } diff --git a/misc/git/server.go b/misc/git/server.go deleted file mode 100644 index 00a2452e..00000000 --- a/misc/git/server.go +++ /dev/null @@ -1,215 +0,0 @@ -package git - -import ( - "compress/flate" - "compress/gzip" - "encoding/base64" - "fmt" - "io" - "path" - "strconv" - "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/gdb" - "shylinux.com/x/icebergs/base/mdb" - "shylinux.com/x/icebergs/base/nfs" - "shylinux.com/x/icebergs/base/tcp" - "shylinux.com/x/icebergs/base/web" - kit "shylinux.com/x/toolkits" -) - -func _server_login(m *ice.Message) error { - if tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) && ice.Info.Localhost { - 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]) - } - data, err := base64.StdEncoding.DecodeString(ls[1]) - if err != nil { - return err - } - if ls = strings.SplitN(string(data), ice.DF, 2); m.Cmd("web.code.git.token", ls[0]).Append(TOKEN) != ls[1] { - return fmt.Errorf("username or password error") - } - if aaa.UserRole(m, ls[0]) == aaa.VOID { - return fmt.Errorf("userrole has no right") - } - return nil -} -func _server_param(m *ice.Message, arg ...string) (string, string) { - repos, service := path.Join(kit.Slice(arg, 0, 1)...), kit.Select(arg[len(arg)-1], m.Option("service")) - switch { - case strings.HasSuffix(repos, INFO_REFS): - repos = strings.TrimSuffix(repos, INFO_REFS) - default: - repos = strings.TrimSuffix(repos, service) - } - m.Debug("what %v", repos) - 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) { - web.RenderType(m.W, "", kit.Format("application/x-git-%s-advertisement", service)) - // _server_writer(m, "# service=git-"+service+ice.NL, m.Cmd(cli.SYSTEM, "ice.bin", "web.git.repos", service, repos).Results()) - // return nil - _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.Options(cli.CMD_INPUT, reader, cli.CMD_OUTPUT, m.W) - web.RenderType(m.W, "", kit.Format("application/x-git-%s-result", service)) - - // m.Cmd(cli.SYSTEM, "ice.bin", "web.git.repos", service, repos) - // return nil - // - _git_cmd(m, service, "--stateless-rpc", ice.PT) - return nil -} -func _server_writer(m *ice.Message, cmd string, str ...string) { - s := strconv.FormatInt(int64(len(cmd)+4), 16) - if len(s)%4 != 0 { - s = strings.Repeat("0", 4-len(s)%4) + s - } - m.W.Write([]byte(s + cmd + "0000" + strings.Join(str, ""))) -} -func _server_reader(m *ice.Message) (io.ReadCloser, error) { - switch m.R.Header.Get("content-encoding") { - case "deflate": - return flate.NewReader(m.R.Body), nil - case "gzip": - return gzip.NewReader(m.R.Body) - } - return m.R.Body, nil -} - -const ( - INFO_REFS = "info/refs" -) -const SERVER = "server" - -func init() { - web.Index.MergeCommands(ice.Commands{"/x/": {Actions: ice.MergeActions(ctx.CmdAction(), aaa.WhiteAction(ctx.COMMAND, ice.RUN)), Hand: func(m *ice.Message, arg ...string) { - if arg[0] == ice.LIST { - m.Cmd("web.code.git.server", func(value ice.Maps) { m.Push(nfs.REPOS, web.MergeLink(m, "/x/"+value[nfs.REPOS]+".git")) }) - m.Sort(nfs.REPOS) - return - } - if !m.IsCliUA() || len(arg) > 0 && strings.Contains(arg[0], ice.AT) || len(arg) > 1 && arg[1] == ice.SRC { - if len(arg) > 0 && strings.Contains(arg[0], ice.AT) { - ls := strings.Split(arg[0], ice.AT) - _repos_cat(m, path.Join(ice.USR_LOCAL_REPOS, ls[0]), "master", ls[1], path.Join(arg[1:]...)) - m.RenderResult() - } else if len(arg) > 1 && strings.HasPrefix(arg[1], "v") && strings.Contains(arg[1], ice.PT) { - _repos_cat(m, path.Join(ice.USR_LOCAL_REPOS, arg[0]), "master", arg[1], path.Join(arg[2:]...)) - m.RenderResult() - } else if len(arg) > 1 && arg[1] == ice.SRC { - _repos_cat(m, path.Join(ice.USR_LOCAL_REPOS, arg[0]), "master", "", path.Join(arg[1:]...)) - m.RenderResult() - } else { - web.RenderCmds(m, kit.Dict(ctx.DISPLAY, "/plugin/local/code/repos.js", ctx.INDEX, "web.code.git.inner", - ctx.ARGS, kit.List(strings.TrimSuffix(arg[0], ".git"), arg[1], "pwd", kit.Select("README.md", path.Join(kit.Slice(arg, 2)...))))) - } - return - } - if m.RenderVoid(); m.Option("go-get") == "1" { - p := _git_url(m, path.Join(arg...)) - m.RenderResult(kit.Format(``, kit.Format(`%s git %s`, strings.TrimSuffix(strings.Split(p, "://")[1], ".git"), p))) - return - } - switch repos, service := _server_param(m, arg...); service { - case "receive-pack": - if err := _server_login(m); m.Warn(err, ice.ErrNotLogin) { - web.RenderHeader(m.W, "WWW-Authenticate", `Basic realm="git server"`) - return - } else if !nfs.Exists(m, repos) { - m.Logs(mdb.CREATE, REPOS, repos) - _repos_init(m, repos) - } - case "upload-pack": - if m.Warn(!nfs.Exists(m, repos), ice.ErrNotFound, arg[0]) { - return - } - } - m.Warn(_server_repos(m, arg...), ice.ErrNotValid) - }}}) - Index.MergeCommands(ice.Commands{ - "inner": {Name: "inner repos branch commit path auto token", Help: "服务器", Actions: ice.MergeActions(ice.Actions{}, aaa.RoleAction()), Hand: func(m *ice.Message, arg ...string) { - if m.Option(nfs.DIR_ROOT, ice.USR_LOCAL_REPOS); len(arg) == 0 { - } else if dir := path.Join(m.Option(nfs.DIR_ROOT), arg[0]); len(arg) == 1 { - } else if len(arg) == 2 { - } else if len(arg) == 3 || strings.HasSuffix(arg[3], nfs.PS) { - _repos_dir(m, dir, arg[1], arg[2], kit.Select("", arg, 3), nil) - } else { - m.Option(nfs.FILE, kit.Select("", arg, 3)) - _repos_cat(m, dir, arg[1], arg[2], kit.Select("", arg, 3)) - } - }}, - SERVER: {Name: "server repos branch commit path auto create import token", Help: "代码源", Actions: ice.MergeActions(ice.Actions{ - mdb.CREATE: {Name: "create name*=demo", Hand: func(m *ice.Message, arg ...string) { - _repos_init(m, path.Join(ice.USR_LOCAL_REPOS, m.Option(mdb.NAME))) - }}, - mdb.IMPORT: {Hand: func(m *ice.Message, arg ...string) { - ReposList(m).Table(func(value ice.Maps) { - m.Option(cli.CMD_DIR, value[nfs.PATH]) - remote := _git_url(m, value[REPOS]) - _git_cmd(m, PUSH, remote, MASTER) - _git_cmd(m, PUSH, "--tags", remote, MASTER) - }) - }}, - nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { - m.Assert(m.Option(nfs.REPOS) != "") - nfs.Trash(m, path.Join(ice.USR_LOCAL_REPOS, m.Option(nfs.REPOS))) - }}, - web.DREAM_INPUTS: {Hand: func(m *ice.Message, arg ...string) { - switch arg[0] { - case nfs.REPOS: - m.Cmd("", func(value ice.Maps) { m.Push(nfs.PATH, _git_url(m, value[nfs.PATH])) }) - } - }}, - "inner": {Help: "编辑器", Hand: func(m *ice.Message, arg ...string) { - if len(arg) == 0 || arg[0] != ice.RUN { - arg = []string{path.Join(ice.USR_LOCAL_REPOS, arg[0]), kit.Select("README.md", arg, 3)} - } else if kit.Select("", arg, 1) != ctx.ACTION { - if dir := path.Join(ice.USR_LOCAL_REPOS, m.Option(REPOS)); len(arg) < 3 { - _repos_dir(m, dir, m.Option(BRANCH), m.Option(COMMIT), kit.Select("", arg, 1), nil) - } else { - _repos_cat(m, dir, m.Option(BRANCH), m.Option(COMMIT), arg[2]) - ctx.DisplayLocal(m, "code/inner.js") - } - return - } - ctx.ProcessField(m, "", arg, arg...) - }}, - TOKEN: {Help: "令牌", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(TOKEN, cli.MAKE) }}, - }, 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.Option(ice.MSG_USERROLE, aaa.TECH) - m.Cmdy(nfs.DIR, nfs.PWD, "time,name,size,action", kit.Dict(nfs.DIR_TYPE, nfs.TYPE_DIR), func(value ice.Maps) { - m.PushScript("git clone " + _git_url(m, value[mdb.NAME])) - }).Cut("time,name,size,script,action").RenameAppend(mdb.NAME, nfs.REPOS).SortStrR(mdb.TIME) - m.Echo(strings.ReplaceAll(m.Cmdx("web.code.publish", ice.CONTEXTS), "app username", "dev username")) - m.Echo(m.Cmdx(TOKEN, m.Option(ice.MSG_USERNAME))) - } else if dir := path.Join(m.Option(nfs.DIR_ROOT), arg[0]); len(arg) == 1 { - _repos_branch(m, dir) - } else if len(arg) == 2 { - _repos_commit(m, dir, arg[1], nil) - } else if len(arg) == 3 || arg[3] == "" || strings.HasSuffix(arg[3], ice.PS) { - _repos_dir(m, dir, arg[1], arg[2], kit.Select("", arg, 3), nil) - } else { - m.Cmdy("", "inner", arg) - } - m.StatusTimeCount() - }}, - }) -} diff --git a/misc/git/spide.go b/misc/git/spide.go index 1a464dac..2f71e9d8 100644 --- a/misc/git/spide.go +++ b/misc/git/spide.go @@ -53,11 +53,11 @@ func init() { } else if len(arg) == 1 { color := []string{cli.YELLOW, cli.BLUE, cli.CYAN, cli.RED} ctx.DisplayStory(m, "", mdb.FIELD, nfs.PATH, aaa.ROOT, arg[0]) - nfs.DirDeepAll(m, _repos_path(arg[0]), "", func(value ice.Maps) { + nfs.DirDeepAll(m, _repos_path(m, arg[0]), "", func(value ice.Maps) { m.Push(cli.COLOR, color[strings.Count(value[nfs.PATH], ice.PS)%len(color)]) m.Push("", value, []string{nfs.PATH}) }, nfs.PATH) - m.Option(nfs.DIR_ROOT, _repos_path(arg[0])) + m.Option(nfs.DIR_ROOT, _repos_path(m, arg[0])) m.StatusTimeCount() } else if len(arg) == 2 { diff --git a/misc/git/status.go b/misc/git/status.go index 2b40f9cd..5b06ce4c 100644 --- a/misc/git/status.go +++ b/misc/git/status.go @@ -1,7 +1,6 @@ package git import ( - "path" "strings" "time" @@ -113,15 +112,9 @@ func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) { const ( INSTEADOF = "insteadof" OAUTH = "oauth" - PULL = "pull" - PUSH = "push" DIFF = "diff" - ADD = "add" OPT = "opt" FIX = "fix" - COMMIT = "commit" - STASH = "stash" - TAG = "tag" TAGS = "tags" VERSION = "version" @@ -172,32 +165,6 @@ func init() { OAUTH: {Help: "授权", Hand: func(m *ice.Message, arg ...string) { m.ProcessOpen(kit.MergeURL2(kit.Select(ice.Info.Make.Remote, _git_remote(m)), "/chat/cmd/web.code.git.token", aaa.USERNAME, m.Option(ice.MSG_USERNAME), tcp.HOST, web.UserHost(m))) }}, - PULL: {Help: "下载", Hand: func(m *ice.Message, arg ...string) { - _status_each(m, "", cli.SYSTEM, GIT, PULL) - _status_each(m, "", cli.SYSTEM, GIT, PULL, "--tags") - m.Sleep3s() - }}, - PUSH: {Help: "上传", Hand: func(m *ice.Message, arg ...string) { - _status_each(m, "", cli.SYSTEM, GIT, PUSH) - _status_each(m, "", cli.SYSTEM, GIT, PUSH, "--tags") - m.Sleep3s() - }}, - ADD: {Help: "添加", Hand: func(m *ice.Message, arg ...string) { _repos_cmd(m, m.Option(REPOS), ADD, m.Option(nfs.FILE)) }}, OPT: {Help: "优化"}, FIX: {Help: "修复"}, - COMMIT: {Name: "commit action=add,opt,fix comment=some", Help: "提交", Hand: func(m *ice.Message, arg ...string) { - _repos_cmd(m, m.Option(REPOS), COMMIT, "-am", m.Option(ctx.ACTION)+ice.SP+m.Option(COMMENT)) - m.ProcessBack() - }}, - STASH: {Help: "缓存", Hand: func(m *ice.Message, arg ...string) { _repos_cmd(m, kit.Select(m.Option(REPOS), arg, 0), STASH) }}, - TAG: {Name: "tag version", Help: "标签", Hand: func(m *ice.Message, arg ...string) { - kit.If(m.Option(VERSION) == "", func() { 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") - ctx.ProcessRefresh(m) - }}, - nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { - m.Assert(m.Option(REPOS) != "" && m.Option(nfs.FILE) != "") - nfs.Trash(m, path.Join(_repos_path(m.Option(REPOS)), m.Option(nfs.FILE))) - }}, web.DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) { if m.Option(mdb.TYPE) != web.WORKER { return @@ -215,6 +182,10 @@ func init() { m.Push(mdb.TEXT, strings.Join(text, ", ")) }}, }, gdb.EventAction(web.DREAM_TABLES), aaa.RoleAction()), Hand: func(m *ice.Message, arg ...string) { + if len(arg) > 0 && arg[0] == ctx.ACTION { + m.Cmdy(REPOS, arg) + return + } if _configs_get(m, USER_EMAIL) == "" { m.Echo("please config user.email").Action(CONFIGS) } else if len(arg) == 0 { diff --git a/misc/git/total.go b/misc/git/total.go index 6c23650c..62fb5535 100644 --- a/misc/git/total.go +++ b/misc/git/total.go @@ -68,7 +68,7 @@ func init() { }}, "_sum": {Name: "_sum [path] [total] [count|date] args...", Help: "统计量", Hand: func(m *ice.Message, arg ...string) { if len(arg) > 0 { - if nfs.Exists(m, _git_dir(arg[0])) || nfs.Exists(m, path.Join(arg[0], REFS_HEADS)) { + if nfs.Exists(m, _git_dir(arg[0])) || nfs.Exists(m, path.Join(arg[0], "refs/heads/")) { m.Option(cli.CMD_DIR, arg[0]) arg = arg[1:] } diff --git a/misc/repos/repos.go b/misc/repos/repos.go index cc6d44aa..2b0d3a93 100644 --- a/misc/repos/repos.go +++ b/misc/repos/repos.go @@ -1,310 +1 @@ package repos - -import ( - "errors" - "fmt" - "io" - "net/url" - "os" - "path" - "strings" - - git "shylinux.com/x/go-git/v5" - "shylinux.com/x/go-git/v5/plumbing" - "shylinux.com/x/go-git/v5/plumbing/object" - "shylinux.com/x/go-git/v5/plumbing/transport/file" - "shylinux.com/x/go-git/v5/plumbing/transport/http" - - 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 _repos_path(m *ice.Message, p string, arg ...string) string { - if p == path.Base(kit.Path("")) { - return kit.Path("", arg...) - } - return path.Join(nfs.USR, p, path.Join(arg...)) -} -func _repos_open(m *ice.Message, p string) *git.Repository { - return mdb.HashSelectTarget(m, p, nil).(*git.Repository) -} -func _repos_insert(m *ice.Message, p string) { - if repos, err := git.PlainOpen(p); err == nil { - args := []string{REPOS, path.Base(p), nfs.PATH, p} - if refer, err := repos.Head(); err == nil { - args = append(args, BRANCH, refer.Name().String()) - if commit, err := repos.CommitObject(refer.Hash()); err == nil { - args = append(args, mdb.TIME, commit.Author.When.Format(ice.MOD_TIME), COMMIT, commit.Message) - } - } - if remote, err := repos.Remotes(); err == nil && len(remote) > 0 { - args = append(args, ORIGIN, remote[0].Config().URLs[0]) - } - mdb.HashCreate(m.Options(mdb.TARGET, repos), args) - } -} -func _repos_each(m *ice.Message, title string, cb func(*git.Repository, ice.Maps) error) { - msg := m.Cmd("") - web.GoToast(m, title, func(toast func(string, int, int)) { - list, count, total := []string{}, 0, msg.Length() - msg.Table(func(value ice.Maps) { - toast(value[REPOS], count, total) - if err := cb(_repos_open(m, value[REPOS]), value); err != nil && err != git.NoErrAlreadyUpToDate { - web.Toast(m, err.Error(), "error: "+value[REPOS], "", "3s") - list = append(list, value[REPOS]) - m.Sleep3s() - } - count++ - }) - if len(list) > 0 { - web.Toast(m, strings.Join(list, ice.NL), ice.FAILURE, "30s") - } else { - toast(ice.SUCCESS, count, total) - } - }) - -} -func _repos_log(m *ice.Message, repos *git.Repository) error { - iter, err := repos.Log(&git.LogOptions{}) - if err != nil { - return err - } - limit := 30 - defer m.StatusTimeCount() - m.Push(mdb.TIME, m.Time()) - m.Push(COMMIT, INDEX) - m.Push(aaa.USERNAME, m.Option(ice.MSG_USERNAME)) - m.Push(mdb.TEXT, "add some") - m.Push("files", 0).Push("adds", 0).Push("dels", 0) - return iter.ForEach(func(commit *object.Commit) error { - if m.Length() > limit { - return nil - } - m.Push(mdb.TIME, commit.Author.When) - m.Push(COMMIT, commit.Hash.String()) - m.Push(aaa.USERNAME, commit.Author.Name) - m.Push(mdb.TEXT, commit.Message) - files, adds, dels := 0, 0, 0 - if stats, err := commit.Stats(); err == nil { - for _, stat := range stats { - files, adds, dels = files+1, adds+stat.Addition, dels+stat.Deletion - } - } - m.Push("files", files).Push("adds", adds).Push("dels", adds) - return nil - }) -} -func _repos_stats(m *ice.Message, repos *git.Repository, h string) error { - commit, err := repos.CommitObject(plumbing.NewHash(h)) - if err != nil { - return err - } - stats, err := commit.Stats() - if err != nil { - return err - } - defer m.StatusTimeCount() - for _, stat := range stats { - m.Push(nfs.FILE, stat.Name).Push("add", stat.Addition).Push("del", stat.Deletion) - } - return nil -} -func _repos_status(m *ice.Message, repos *git.Repository) error { - work, err := repos.Worktree() - if err != nil { - return err - } - status, err := work.Status() - if err != nil { - return err - } - defer m.StatusTimeCount() - for k, v := range status { - switch kit.Ext(k) { - case "swp", "swo": - continue - } - m.Push(nfs.FILE, k).Push(STATUS, string(v.Worktree)+string(v.Staging)) - switch v.Worktree { - case git.Untracked: - m.PushButton(ADD, nfs.TRASH) - case git.Modified: - m.PushButton(ADD) - default: - m.PushButton(COMMIT) - } - } - return nil -} - -const ( - CLONE = "clone" - PULL = "pull" - PUSH = "push" - STATUS = "status" - ADD = "add" - COMMIT = "commit" - LOG = "log" - - ORIGIN = "origin" - BRANCH = "branch" - INDEX = "index" -) -const ( - REPOS = "repos" -) -const GIT = "git" - -func init() { - web.Index.MergeCommands(ice.Commands{ - web.PP(ice.REQUIRE): {Name: "/require/shylinux.com/x/volcanos/proto.js", Help: "代码库", Hand: func(m *ice.Message, arg ...string) { - if len(arg) < 4 { - m.RenderStatusBadRequest() - } else if path.Join(arg[:3]...) == ice.Info.Make.Module && nfs.Exists(m, path.Join(arg[3:]...)) { - m.RenderDownload(path.Join(arg[3:]...)) - } else { - p := path.Join(kit.Select(ice.USR_REQUIRE, m.Cmdx(cli.SYSTEM, "go", "env", "GOMODCACHE")), path.Join(arg...)) - if !nfs.Exists(m, p) { - if p = path.Join(ice.USR_REQUIRE, path.Join(arg...)); !nfs.Exists(m, p) { - ls := strings.SplitN(path.Join(arg[:3]...), ice.AT, 2) - to := path.Join(ice.USR_REQUIRE, path.Join(arg[:3]...)) - _, err := git.PlainClone(to, false, &git.CloneOptions{URL: "https://" + ls[0], ReferenceName: plumbing.NewBranchReferenceName(kit.Select(ice.Info.Gomod[ls[0]], ls, 1))}) - m.Warn(err) - } - } - m.RenderDownload(p) - } - }}, - }) - code.Index.MergeCommands(ice.Commands{ - REPOS: {Name: "repos repos commit:text file:text auto", Help: "仓库", Actions: ice.MergeActions(ice.Actions{ - ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { - m.Cmd(nfs.DIR, nfs.USR, func(value ice.Maps) { _repos_insert(m, value[nfs.PATH]) }) - _repos_insert(m, kit.Path("")) - }}, - "upload-pack": {Hand: func(m *ice.Message, arg ...string) { - if err := file.ServeUploadPack(arg[0]); err != nil && err != io.EOF { - fmt.Fprintln(os.Stderr, "ERR:", err) - os.Exit(128) - } - }}, - "receive-pack": {Hand: func(m *ice.Message, arg ...string) { - if err := file.ServeReceivePack(arg[0]); err != nil && err != io.EOF { - fmt.Fprintln(os.Stderr, "ERR:", err) - fmt.Fprintln(os.Stderr, arg[0]) - os.Exit(128) - } - }}, - CLONE: {Name: "clone origin* branch name path", Hand: func(m *ice.Message, arg ...string) { - m.OptionDefault(mdb.NAME, path.Base(m.Option(ORIGIN))) - m.OptionDefault(nfs.PATH, path.Join(path.Join(nfs.USR, m.Option(mdb.NAME)))) - _, err := git.PlainClone(m.Option(nfs.PATH), false, &git.CloneOptions{URL: m.Option(ORIGIN)}) - m.Warn(err) - }}, - PULL: {Hand: func(m *ice.Message, arg ...string) { - _repos_each(m, "repos pull", func(repos *git.Repository, value ice.Maps) error { - if value[ORIGIN] == "" { - return nil - } else if work, err := repos.Worktree(); err != nil { - return err - } else { - return work.Pull(&git.PullOptions{}) - } - }) - }}, - PUSH: {Hand: func(m *ice.Message, arg ...string) { - list := map[string]*url.URL{} - m.Cmd(nfs.CAT, kit.HomePath(".git-credentials"), func(line string) { - u := kit.ParseURL(line) - list[u.Host] = u - }) - _repos_each(m, "repos push", func(repos *git.Repository, value ice.Maps) error { - if value[ORIGIN] == "" { - return nil - } - u := list[kit.ParseURL(value[ORIGIN]).Host] - if password, ok := u.User.Password(); !ok { - return errors.New("not found password") - } else { - return repos.Push(&git.PushOptions{Auth: &http.BasicAuth{Username: u.User.Username(), Password: password}}) - } - }) - }}, - STATUS: {Hand: func(m *ice.Message, arg ...string) { - _repos_each(m, "repos status", func(repos *git.Repository, value ice.Maps) error { return _repos_status(m, repos) }) - }}, - ADD: {Hand: func(m *ice.Message, arg ...string) { - if work, err := _repos_open(m, m.Option(REPOS)).Worktree(); !m.Warn(err) { - _, err := work.Add(m.Option(nfs.FILE)) - m.Warn(err) - } - }}, - COMMIT: {Name: "commit actions=add,opt,fix comment*=some", Hand: func(m *ice.Message, arg ...string) { - if work, err := _repos_open(m, m.Option(REPOS)).Worktree(); !m.Warn(err) { - _, err := work.Commit(m.Option("actions")+ice.SP+m.Option("comment"), &git.CommitOptions{}) - m.Warn(err) - } - }}, - LOG: {Hand: func(m *ice.Message, arg ...string) { - _repos_log(m, _repos_open(m, kit.Select(m.Option(REPOS), arg, 0))) - }}, - code.VIMER: {Hand: func(m *ice.Message, arg ...string) { - if len(arg) == 0 || arg[0] != ice.RUN { - arg = []string{path.Join(arg[:2]...), kit.Select("README.md", arg, 2)} - } else if kit.Select("", arg, 1) != ctx.ACTION { - ls := kit.Split(kit.Select(arg[1], m.Option(nfs.DIR_ROOT)), nfs.PS) - if ls[1] == INDEX { - if len(arg) < 3 { - m.Cmdy(nfs.DIR, nfs.PWD, kit.Dict(nfs.DIR_ROOT, _repos_path(m, ls[0]))) - } else { - m.Cmdy(nfs.CAT, _repos_path(m, ls[0], arg[2])) - } - } else if commit, err := _repos_open(m, ls[0]).CommitObject(plumbing.NewHash(ls[1])); m.Warn(err) { - return - } else if len(arg) < 3 { - if iter, err := commit.Files(); !m.Warn(err) { - iter.ForEach(func(file *object.File) error { - m.Push(nfs.PATH, file.Name) - return nil - }) - } - } else { - if file, err := commit.File(arg[2]); !m.Warn(err) { - if content, err := file.Contents(); !m.Warn(err) { - m.Echo(content) - } - } - } - ctx.DisplayLocal(m, "code/vimer.js") - return - } - ctx.ProcessField(m, "", arg, arg...) - }}, - nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { - kit.If(!m.Warn(m.Option(REPOS) == ""), func() { m.Cmdy(nfs.TRASH, _repos_path(m, m.Option(REPOS), m.Option(nfs.FILE))) }) - }}, - }, mdb.HashAction(mdb.SHORT, REPOS, mdb.FIELD, "time,repos,branch,commit,origin"), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) { - if len(arg) == 0 { - mdb.HashSelect(m, arg...).Action(CLONE, PULL, PUSH, STATUS) - } else if len(arg) == 1 { - _repos_log(m, _repos_open(m, arg[0])) - // _repos_status(m, _repos_open(m, arg[0])) - } else if len(arg) == 2 { - if repos := _repos_open(m, arg[0]); arg[1] == INDEX { - _repos_status(m, repos) - } else { - _repos_stats(m, repos, arg[1]) - } - } else { - m.Cmdy("", code.VIMER, arg) - } - }}, - }) -}