forked from x/icebergs
opt git
This commit is contained in:
parent
8fa1b390e5
commit
83c959a14e
@ -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) }}})
|
||||
}
|
||||
|
2
go.mod
2
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
|
||||
|
@ -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"
|
||||
)
|
||||
|
@ -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)) }
|
||||
|
@ -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)
|
||||
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
|
||||
}
|
||||
}
|
||||
}, nfs.PATH)
|
||||
}
|
||||
m.Push("files", files).Push("adds", adds).Push("dels", adds)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
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")
|
||||
func _repos_stats(m *ice.Message, repos *git.Repository, h string) error {
|
||||
commit, err := repos.CommitObject(plumbing.NewHash(h))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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
|
||||
stats, err := commit.Stats()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p := ci.ParentCommit(0); p != nil {
|
||||
oid = p.Oid
|
||||
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
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
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_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()
|
||||
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)
|
||||
}
|
||||
}
|
||||
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))
|
||||
}
|
||||
ctx.DisplayLocal(m, "code/vimer.js")
|
||||
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) {
|
||||
if commit == cli.PWD {
|
||||
m.Cmdy(nfs.CAT, path.Join(path.Dir(dir), file))
|
||||
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"
|
||||
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
|
||||
}
|
||||
} 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)
|
||||
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]...)))
|
||||
}
|
||||
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)
|
||||
}
|
||||
}},
|
||||
})
|
||||
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
|
||||
}
|
||||
ctx.ProcessField(m, web.CODE_INNER, arg, arg...)
|
||||
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)
|
||||
}
|
||||
}},
|
||||
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 {
|
||||
m.Cmdy("", DIFF, arg)
|
||||
_repos_stats(m, repos, arg[1])
|
||||
}
|
||||
} else {
|
||||
m.Cmdy("", code.VIMER, arg)
|
||||
}
|
||||
m.StatusTimeCount()
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
@ -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()
|
||||
}},
|
||||
})
|
||||
}
|
@ -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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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:]
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user