From 50b58d97cfe033f436e7e333aeeea79b9ff81b15 Mon Sep 17 00:00:00 2001 From: shylinux Date: Thu, 19 Aug 2021 00:20:22 +0800 Subject: [PATCH] opt git.server --- core/code/autogen.go | 2 +- go.mod | 1 - go.sum | 2 - misc/git/server.go | 172 +++++++++++++++++++++++++++++++++---------- 4 files changed, 133 insertions(+), 44 deletions(-) diff --git a/core/code/autogen.go b/core/code/autogen.go index 55c9e2e7..5f753eb9 100644 --- a/core/code/autogen.go +++ b/core/code/autogen.go @@ -14,7 +14,7 @@ import ( func _autogen_script(m *ice.Message, dir string) { if b, e := kit.Render(`chapter "{{.Option "name"}}" -field "{{.Option "name"}}" web.code.{{.Option "name"}}.{{.Option "name"}} +field "{{.Option "name"}}" web.code.{{.Option "name"}} `, m); m.Assert(e) { m.Cmd(nfs.DEFS, dir, string(b)) } diff --git a/go.mod b/go.mod index 3745e787..96124d8b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module shylinux.com/x/icebergs go 1.11 require ( - github.com/AaronO/go-git-http v0.0.0-20161214145340-1d9485b3a98f github.com/gorilla/websocket v1.4.2 github.com/kr/pty v1.1.8 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e diff --git a/go.sum b/go.sum index 0f6033b9..3c4975a8 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/AaronO/go-git-http v0.0.0-20161214145340-1d9485b3a98f h1:x/RDwGRneK2/891S2o7KhZt3MhHMSCssoeDOfvolTMk= -github.com/AaronO/go-git-http v0.0.0-20161214145340-1d9485b3a98f/go.mod h1:+6Yuq73F9068Na+mSBNXCvyuxvgw4f/g5ii40e3U8Sc= github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= diff --git a/misc/git/server.go b/misc/git/server.go index e00042dd..b33c33cc 100644 --- a/misc/git/server.go +++ b/misc/git/server.go @@ -1,15 +1,19 @@ package git import ( + "compress/flate" + "compress/gzip" "encoding/base64" "fmt" + "io" "net/http" "os" + "os/exec" "path" "regexp" + "strconv" "strings" - githttp "github.com/AaronO/go-git-http" ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/cli" @@ -19,8 +23,38 @@ import ( kit "shylinux.com/x/toolkits" ) +func requestReader(req *http.Request) (io.ReadCloser, error) { + switch req.Header.Get("content-encoding") { + case "gzip": + return gzip.NewReader(req.Body) + case "deflate": + return flate.NewReader(req.Body), nil + } + return req.Body, nil +} +func packetWrite(str string) []byte { + s := strconv.FormatInt(int64(len(str)+4), 16) + if len(s)%4 != 0 { + s = strings.Repeat("0", 4-len(s)%4) + s + } + return []byte(s + str) +} +func packetFlush() []byte { + return []byte("0000") +} + var basicAuthRegex = regexp.MustCompile("^([^:]*):(.*)$") +func _server_param(m *ice.Message, arg ...string) (string, string) { + repos, service := path.Join(arg...), kit.Select(arg[len(arg)-1], m.Option("service")) + switch { + case strings.HasSuffix(repos, "info/refs"): + repos = strings.TrimSuffix(repos, "info/refs") + default: + repos = strings.TrimSuffix(repos, service) + } + return kit.Path(m.Conf(SERVER, kit.META_PATH), "repos", repos), strings.TrimPrefix(service, "git-") +} func _server_login(m *ice.Message) error { parts := strings.SplitN(m.R.Header.Get("Authorization"), " ", 2) if len(parts) < 2 { @@ -58,52 +92,110 @@ func _server_repos(m *ice.Message, arg ...string) { m.Cmd(cli.SYSTEM, GIT, INIT, "--bare", p) // 创建仓库 } } +func _server_cmd(m *ice.Message, arg ...string) error { + repos, service := _server_param(m, arg...) + + if strings.HasSuffix(path.Join(arg...), "info/refs") { + command := exec.Command("/usr/bin/git", service, "--stateless-rpc", "--advertise-refs", ".") + command.Dir = repos + out, err := command.Output() + if err != nil { + return err + } + + m.W.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT") + m.W.Header().Set("Pragma", "no-cache") + m.W.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate") + + m.W.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service)) + m.W.WriteHeader(http.StatusOK) + m.W.Write(packetWrite("# service=git-" + service + "\n")) + m.W.Write(packetFlush()) + m.W.Write(out) + return nil + } + + command := exec.Command("/usr/bin/git", service, "--stateless-rpc", ".") + command.Dir = repos + + stdin, err := command.StdinPipe() + if err != nil { + return err + } + stdout, err := command.StdoutPipe() + if err != nil { + return err + } + defer stdout.Close() + + if err = command.Start(); err != nil { + return err + } + + reader, err := requestReader(m.R) + if err != nil { + return err + } + defer reader.Close() + + io.Copy(stdin, reader) + stdin.Close() + + m.W.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service)) + io.Copy(m.W, stdout) + + if err = command.Wait(); err != nil { + return err + } + return nil +} const SERVER = "server" func init() { - Index.Merge(&ice.Context{ - Configs: map[string]*ice.Config{ - SERVER: {Name: SERVER, Help: "服务器", Value: kit.Data(kit.MDB_PATH, ice.USR_LOCAL)}, - }, - Commands: map[string]*ice.Command{ - web.WEB_LOGIN: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Render(ice.RENDER_VOID) - }}, - "/repos/": {Name: "/repos/", Help: "代码库", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if m.Option("go-get") == "1" { - p := m.Conf(web.SHARE, kit.Keym(kit.MDB_DOMAIN)) + "/x/" + path.Join(arg...) - m.RenderResult(``, strings.TrimPrefix(p, "https://"), p) - return + Index.Merge(&ice.Context{Configs: map[string]*ice.Config{ + SERVER: {Name: SERVER, Help: "服务器", Value: kit.Data(kit.MDB_PATH, ice.USR_LOCAL)}, + }, Commands: map[string]*ice.Command{ + web.WEB_LOGIN: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Render(ice.RENDER_VOID) + }}, + "/repos/": {Name: "/repos/", Help: "代码库", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if m.Option("go-get") == "1" { // 下载地址 + p := m.Conf(web.SHARE, kit.Keym(kit.MDB_DOMAIN)) + "/x/" + path.Join(arg...) + m.RenderResult(``, strings.TrimPrefix(p, "https://"), p) + return + } + + switch _, service := _server_param(m, arg...); service { + case "receive-pack": // 上传代码 + if err := _server_login(m); err != nil { + m.W.Header().Set("WWW-Authenticate", `Basic realm="git server"`) + http.Error(m.W, err.Error(), 401) + return // 认证失败 } - switch m.Option("service") { - case "git-receive-pack": // 上传代码 - if err := _server_login(m); err != nil { - m.W.Header().Set("WWW-Authenticate", `Basic realm="git server"`) - http.Error(m.W, err.Error(), 401) // 认证失败 - return - } - _server_repos(m, arg...) + _server_repos(m, arg...) - case "git-upload-pack": // 下载代码 + case "upload-pack": // 下载代码 - } + } - githttp.New(kit.Path(m.Conf(SERVER, kit.META_PATH))).ServeHTTP(m.W, m.R) + if err := _server_cmd(m, arg...); err != nil { + http.Error(m.W, err.Error(), 500) + return // 未知错误 + } + // githttp.New(kit.Path(m.Conf(SERVER, kit.META_PATH))).ServeHTTP(m.W, m.R) + }}, + SERVER: {Name: "server path auto create", Help: "服务器", Action: map[string]*ice.Action{ + mdb.CREATE: {Name: "create name", Help: "添加", Hand: func(m *ice.Message, arg ...string) { + m.Option(cli.CMD_DIR, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)) + m.Cmd(cli.SYSTEM, GIT, INIT, "--bare", m.Option(kit.MDB_NAME)) }}, - SERVER: {Name: "server path auto create", Help: "服务器", Action: map[string]*ice.Action{ - mdb.CREATE: {Name: "create name", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - m.Option(cli.CMD_DIR, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)) - m.Cmd(cli.SYSTEM, GIT, INIT, "--bare", m.Option(kit.MDB_NAME)) - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if m.Option(nfs.DIR_ROOT, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)); len(arg) == 0 { - m.Cmdy(nfs.DIR, "./") - return - } - - m.Cmdy("_sum", path.Join(m.Option(nfs.DIR_ROOT), arg[0])) - }}, - }, - }) + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if m.Option(nfs.DIR_ROOT, path.Join(m.Conf(SERVER, kit.META_PATH), REPOS)); len(arg) == 0 { + m.Cmdy(nfs.DIR, "./") + return + } + m.Cmdy("_sum", path.Join(m.Option(nfs.DIR_ROOT), arg[0])) + }}, + }}) }