1
0
forked from x/icebergs
This commit is contained in:
IT 老营长 @云轩领航-创始人 2023-04-16 16:01:33 +08:00
parent 8fa1b390e5
commit 83c959a14e
10 changed files with 264 additions and 770 deletions

View File

@ -2,10 +2,7 @@ package code
import ( import (
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web"
kit "shylinux.com/x/toolkits"
) )
const ( const (
@ -15,9 +12,6 @@ const REPOS = nfs.REPOS
func init() { func init() {
Index.MergeCommands(ice.Commands{REPOS: {Name: "repos name auto", Actions: ice.Actions{ 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) }}, "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) }}}) }, Hand: func(m *ice.Message, arg ...string) { m.Cmdy("web.code.git.repos", arg) }}})
} }

2
go.mod
View File

@ -3,8 +3,8 @@ module shylinux.com/x/icebergs
go 1.11 go 1.11
require ( require (
shylinux.com/x/go-git/v5 v5.6.2
shylinux.com/x/go-qrcode v0.0.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/ice v1.3.0
shylinux.com/x/toolkits v0.7.5 shylinux.com/x/toolkits v0.7.5
shylinux.com/x/websocket v0.0.2 shylinux.com/x/websocket v0.0.2

View File

@ -31,6 +31,7 @@ func _configs_read(m *ice.Message, p string) ice.Maps {
} }
const ( const (
CONFIG = "config"
USER_NAME = "user.name" USER_NAME = "user.name"
USER_EMAIL = "user.email" USER_EMAIL = "user.email"
) )

View File

@ -40,3 +40,5 @@ var Index = &ice.Context{Name: GIT, Help: "代码库", Commands: ice.Commands{
}} }}
func init() { code.Index.Register(Index, &web.Frame{}, REPOS) } func init() { code.Index.Register(Index, &web.Frame{}, REPOS) }
func Prefix(arg ...string) string { return code.Prefix(GIT, kit.Keys(arg)) }

View File

@ -1,172 +1,198 @@
package git package git
import ( import (
"os" "errors"
"net/url"
"path" "path"
"strings" "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" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web" "shylinux.com/x/icebergs/base/web"
"shylinux.com/x/icebergs/core/code"
kit "shylinux.com/x/toolkits" 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 { 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 { func _repos_path(m *ice.Message, p string, arg ...string) string {
os.MkdirAll(path.Join(dir, REFS_HEADS), ice.MOD_DIR) if p == path.Base(kit.Path("")) {
os.MkdirAll(path.Join(dir, OBJECTS_INFO), ice.MOD_DIR) return kit.Path("", arg...)
return m.Cmdx(nfs.SAVE, path.Join(dir, "HEAD"), "ref: refs/heads/master") }
return path.Join(nfs.USR, p, path.Join(arg...))
} }
func _repos_insert(m *ice.Message, name string, path string) bool { func _repos_open(m *ice.Message, p string) *git.Repository {
if repos, e := gogit.OpenRepository(_git_dir(path)); e == nil { return mdb.HashSelectTarget(m, p, nil).(*git.Repository)
origin := kit.Select("", kit.Split(repos.GetOrigin()), -1) }
kit.If(origin == "", func() { origin = _configs_read(m, _git_dir(path, CONFIG))["remote.origin.url"] }) func _repos_init(m *ice.Message, p string) {
if ci, e := repos.GetCommit(); e == nil { m.Debug("what %v", p)
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) 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 { } 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) { func _repos_log(m *ice.Message, repos *git.Repository) error {
if repos, e := gogit.OpenRepository(dir); !m.Warn(e, ice.ErrNotFound, dir) { iter, err := repos.Log(&git.LogOptions{})
nfs.DirDeepAll(m, path.Join(dir, REFS_HEADS), "", func(value ice.Maps) { if err != nil {
if refer, e := repos.LookupReference(REFS_HEADS + value[nfs.PATH]); !m.Warn(e, ice.ErrNotValid, value[nfs.PATH]) { return err
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)
} }
} limit := 30
func _repos_commit(m *ice.Message, dir, branch string, cb func(*gogit.Commit, *gogit.Repository) bool) { defer m.StatusTimeCount()
if repos, e := gogit.OpenRepository(dir); !m.Warn(e, ice.ErrNotFound, dir) { m.Push(mdb.TIME, m.Time())
if refer, e := repos.LookupReference(REFS_HEADS + branch); !m.Warn(e, ice.ErrNotFound, branch) { m.Push(COMMIT, INDEX)
if cb == nil { m.Push(aaa.USERNAME, m.Option(ice.MSG_USERNAME))
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") m.Push(mdb.TEXT, "add some")
} m.Push("files", 0).Push("adds", 0).Push("dels", 0)
for oid := refer.Oid; oid != nil; { return iter.ForEach(func(commit *object.Commit) error {
if ci, e := repos.LookupCommit(oid); !m.Warn(e, ice.ErrNotFound, oid.String()) { if m.Length() > limit {
if cb == nil { return 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) { m.Push(mdb.TIME, commit.Author.When)
break m.Push(COMMIT, commit.Hash.String())
} m.Push(aaa.USERNAME, commit.Author.Name)
if p := ci.ParentCommit(0); p != nil { m.Push(mdb.TEXT, commit.Message)
oid = p.Oid files, adds, dels := 0, 0, 0
continue if stats, err := commit.Stats(); err == nil {
} for _, stat := range stats {
} files, adds, dels = files+1, adds+stat.Addition, dels+stat.Deletion
break
} }
} }
} m.Push("files", files).Push("adds", adds).Push("dels", adds)
} return nil
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
}) })
} }
func _repos_cat(m *ice.Message, dir, branch, commit, file string) { func _repos_stats(m *ice.Message, repos *git.Repository, h string) error {
if commit == cli.PWD { commit, err := repos.CommitObject(plumbing.NewHash(h))
m.Cmdy(nfs.CAT, path.Join(path.Dir(dir), file)) 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 return
} }
commit = _repos_cid(m, dir, branch, commit) ctx.ProcessField(m, "", arg, arg...)
_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
})
} }
const ( const (
OBJECTS_INFO = "objects/info/" CLONE = "clone"
REFS_HEADS = "refs/heads/" PULL = "pull"
REFS_TAGS = "refs/tags/" PUSH = "push"
TREE = "tree" LOG = "log"
BLOB = "blob" ADD = "add"
TAG = "tag"
STASH = "stash"
COMMIT = "commit"
INIT = "init" ORIGIN = "origin"
CONFIG = "config" BRANCH = "branch"
ORIGIN = "origin" MASTER = "master"
BRANCH = "branch" INDEX = "index"
MASTER = "master"
AUTHOR = "author"
MESSAGE = "message"
) )
const REPOS = "repos" 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) { web.PP(ice.REQUIRE): {Name: "/require/shylinux.com/x/volcanos/proto.js", Help: "代码库", Hand: func(m *ice.Message, arg ...string) {
if len(arg) < 4 { if len(arg) < 4 {
m.RenderStatusBadRequest() m.RenderStatusBadRequest()
return
} else if path.Join(arg[:3]...) == ice.Info.Make.Module && nfs.Exists(m, path.Join(arg[3:]...)) { } else if path.Join(arg[:3]...) == ice.Info.Make.Module && nfs.Exists(m, path.Join(arg[3:]...)) {
m.RenderDownload(path.Join(arg[3:]...)) m.RenderDownload(path.Join(arg[3:]...))
return } else {
} p := path.Join(kit.Select(ice.USR_REQUIRE, m.Cmdx(cli.SYSTEM, "go", "env", "GOMODCACHE")), path.Join(arg...))
p := path.Join(kit.Select(ice.USR_REQUIRE, m.Cmdx(cli.SYSTEM, "go", "env", "GOMODCACHE")), path.Join(arg...)) if !nfs.Exists(m, p) {
if !nfs.Exists(m, p) { if p = path.Join(ice.USR_REQUIRE, path.Join(arg...)); !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)
ls := strings.SplitN(path.Join(arg[:3]...), ice.AT, 2) to := path.Join(ice.USR_REQUIRE, path.Join(arg[:3]...))
if v := kit.Select(ice.Info.Gomod[ls[0]], ls, 1); v == "" { _, err := git.PlainClone(to, false, &git.CloneOptions{URL: "https://" + ls[0], ReferenceName: plumbing.NewBranchReferenceName(kit.Select(ice.Info.Gomod[ls[0]], ls, 1))})
_git_cmd(m, "clone", "https://"+ls[0], path.Join(ice.USR_REQUIRE, path.Join(arg[:3]...))) m.Warn(err)
} else {
_git_cmd(m, "clone", "-b", v, "https://"+ls[0], path.Join(ice.USR_REQUIRE, path.Join(arg[:3]...)))
} }
} }
m.RenderDownload(p)
} }
m.RenderDownload(p)
}}, }},
}) })
Index.MergeCommands(ice.Commands{ 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) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.DIR, ice.USR, "name,path", func(value ice.Maps) { _repos_insert(m, value[mdb.NAME], value[nfs.PATH]) }) m.Cmd(nfs.DIR, nfs.USR, func(value ice.Maps) { _repos_insert(m, value[nfs.PATH]) })
_repos_insert(m, path.Base(kit.Pwd()), kit.Pwd()) _repos_insert(m, kit.Path(""))
cli.IsSystem(m, GIT)
}}, }},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { CLONE: {Name: "clone origin* branch name path", Hand: func(m *ice.Message, arg ...string) {
switch arg[0] { m.OptionDefault(mdb.NAME, path.Base(m.Option(ORIGIN)))
case REPOS: m.OptionDefault(nfs.PATH, path.Join(path.Join(nfs.USR, m.Option(mdb.NAME))))
mdb.HashSelect(m).Cut(REPOS) _, err := git.PlainClone(m.Option(nfs.PATH), false, &git.CloneOptions{URL: m.Option(ORIGIN)})
case BRANCH: m.Warn(err)
m.Cmdy("", m.Option(REPOS)).Cut(BRANCH) _repos_insert(m, m.Option(nfs.PATH))
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)
}
}}, }},
mdb.CREATE: {Name: "create origin branch name path", Hand: func(m *ice.Message, arg ...string) { PULL: {Hand: func(m *ice.Message, arg ...string) {
m.OptionDefault(mdb.NAME, kit.TrimExt(m.Option(ORIGIN), GIT)) _repos_each(m, "repos pull", func(repos *git.Repository, value ice.Maps) error {
m.OptionDefault(nfs.PATH, path.Join(nfs.USR, m.Option(mdb.NAME))) if value[ORIGIN] == "" {
if _repos_insert(m, m.Option(mdb.NAME), m.Option(nfs.PATH)) { return nil
return } else if work, err := repos.Worktree(); err != nil {
} return err
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)
} else { } else {
_repos_cat(m, dir, ls[1], ls[2], arg[2]) return work.Pull(&git.PullOptions{})
ctx.DisplayLocal(m, "code/inner.js")
} }
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) { }, 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] == "" { if len(arg) == 0 {
mdb.HashSelect(m, arg...).Action(mdb.CREATE) mdb.HashSelect(m, arg...).Action(CLONE, PULL, PUSH, STATUS)
} else if dir := _git_dir(_repos_path(arg[0])); len(arg) == 1 || arg[1] == "" { } else if len(arg) == 1 {
_repos_branch(m, dir) _repos_log(m, _repos_open(m, arg[0]))
} else if len(arg) == 2 || arg[2] == "" { } else if len(arg) == 2 {
_repos_commit(m, dir, arg[1], nil) if repos := _repos_open(m, arg[0]); arg[1] == INDEX {
} else if len(arg) == 3 || arg[3] == "" || strings.HasSuffix(arg[3], ice.PS) { _repos_status(m, repos)
_repos_dir(m, dir, arg[1], arg[2], kit.Select("", arg, 3), nil) } else {
return _repos_stats(m, repos, arg[1])
}
} else { } else {
m.Cmdy("", DIFF, arg) m.Cmdy("", code.VIMER, arg)
} }
m.StatusTimeCount()
}}, }},
}) })
} }

View File

@ -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(`<meta name="go-import" content="%s">`, 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()
}},
})
}

View File

@ -53,11 +53,11 @@ func init() {
} else if len(arg) == 1 { } else if len(arg) == 1 {
color := []string{cli.YELLOW, cli.BLUE, cli.CYAN, cli.RED} color := []string{cli.YELLOW, cli.BLUE, cli.CYAN, cli.RED}
ctx.DisplayStory(m, "", mdb.FIELD, nfs.PATH, aaa.ROOT, arg[0]) 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(cli.COLOR, color[strings.Count(value[nfs.PATH], ice.PS)%len(color)])
m.Push("", value, []string{nfs.PATH}) m.Push("", value, []string{nfs.PATH})
}, 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() m.StatusTimeCount()
} else if len(arg) == 2 { } else if len(arg) == 2 {

View File

@ -1,7 +1,6 @@
package git package git
import ( import (
"path"
"strings" "strings"
"time" "time"
@ -113,15 +112,9 @@ func _status_list(m *ice.Message) (files, adds, dels int, last time.Time) {
const ( const (
INSTEADOF = "insteadof" INSTEADOF = "insteadof"
OAUTH = "oauth" OAUTH = "oauth"
PULL = "pull"
PUSH = "push"
DIFF = "diff" DIFF = "diff"
ADD = "add"
OPT = "opt" OPT = "opt"
FIX = "fix" FIX = "fix"
COMMIT = "commit"
STASH = "stash"
TAG = "tag"
TAGS = "tags" TAGS = "tags"
VERSION = "version" VERSION = "version"
@ -172,32 +165,6 @@ func init() {
OAUTH: {Help: "授权", Hand: func(m *ice.Message, arg ...string) { 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))) 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) { web.DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) {
if m.Option(mdb.TYPE) != web.WORKER { if m.Option(mdb.TYPE) != web.WORKER {
return return
@ -215,6 +182,10 @@ func init() {
m.Push(mdb.TEXT, strings.Join(text, ", ")) m.Push(mdb.TEXT, strings.Join(text, ", "))
}}, }},
}, gdb.EventAction(web.DREAM_TABLES), aaa.RoleAction()), Hand: func(m *ice.Message, arg ...string) { }, 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) == "" { if _configs_get(m, USER_EMAIL) == "" {
m.Echo("please config user.email").Action(CONFIGS) m.Echo("please config user.email").Action(CONFIGS)
} else if len(arg) == 0 { } else if len(arg) == 0 {

View File

@ -68,7 +68,7 @@ func init() {
}}, }},
"_sum": {Name: "_sum [path] [total] [count|date] args...", Help: "统计量", Hand: func(m *ice.Message, arg ...string) { "_sum": {Name: "_sum [path] [total] [count|date] args...", Help: "统计量", Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 { if len(arg) > 0 {
if 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]) m.Option(cli.CMD_DIR, arg[0])
arg = arg[1:] arg = arg[1:]
} }

View File

@ -1,310 +1 @@
package repos 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)
}
}},
})
}