web frontend for git (tangled's grandpa)
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

git: pure go git clone

+118 -35
+1 -3
go.mod
··· 6 6 github.com/alexedwards/flow v0.0.0-20220806114457-cf11be9e0e03 7 7 github.com/bluekeyes/go-gitdiff v0.7.0 8 8 github.com/dustin/go-humanize v1.0.0 9 + github.com/go-git/go-billy/v5 v5.3.1 9 10 github.com/go-git/go-git/v5 v5.5.1 10 - github.com/sosedoff/gitkit v0.3.0 11 11 golang.org/x/sys v0.3.0 12 12 gopkg.in/yaml.v3 v3.0.0 13 13 ) ··· 19 19 github.com/cloudflare/circl v1.3.0 // indirect 20 20 github.com/emirpasic/gods v1.18.1 // indirect 21 21 github.com/go-git/gcfg v1.5.0 // indirect 22 - github.com/go-git/go-billy/v5 v5.3.1 // indirect 23 - github.com/gofrs/uuid v4.0.0+incompatible // indirect 24 22 github.com/imdario/mergo v0.3.13 // indirect 25 23 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 26 24 github.com/kevinburke/ssh_config v1.2.0 // indirect
-5
go.sum
··· 35 35 github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= 36 36 github.com/go-git/go-git/v5 v5.5.1 h1:5vtv2TB5PM/gPM+EvsHJ16hJh4uAkdGcKilcwY7FYwo= 37 37 github.com/go-git/go-git/v5 v5.5.1/go.mod h1:uz5PQ3d0gz7mSgzZhSJToM6ALPaKCdSnl58/Xb5hzr8= 38 - github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= 39 - github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 40 38 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 41 39 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 42 40 github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= ··· 67 65 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 68 66 github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= 69 67 github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= 70 - github.com/sosedoff/gitkit v0.3.0 h1:TfINVRNUM+GcFa+LGhZ3RcWN86Im1M6i8qs0IsgMy90= 71 - github.com/sosedoff/gitkit v0.3.0/go.mod h1:V3EpGZ0nvCBhXerPsbDeqtyReNb48cwP9KtkUYTKT5I= 72 68 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 73 69 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 74 70 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= ··· 78 74 github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 79 75 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 80 76 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 81 - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 82 77 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 83 78 golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 84 79 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+108
routes/git.go
··· 1 + package routes 2 + 3 + import ( 4 + "errors" 5 + "log" 6 + "net/http" 7 + "path/filepath" 8 + 9 + "github.com/alexedwards/flow" 10 + "github.com/go-git/go-billy/v5/osfs" 11 + "github.com/go-git/go-git/v5/plumbing/format/pktline" 12 + "github.com/go-git/go-git/v5/plumbing/protocol/packp" 13 + "github.com/go-git/go-git/v5/plumbing/transport" 14 + "github.com/go-git/go-git/v5/plumbing/transport/server" 15 + ) 16 + 17 + func (d *deps) InfoRefs(w http.ResponseWriter, r *http.Request) { 18 + name := flow.Param(r.Context(), "name") 19 + name = filepath.Clean(name) 20 + 21 + repo := filepath.Join(d.c.Repo.ScanPath, name) 22 + 23 + w.Header().Set("content-type", "application/x-git-upload-pack-advertisement") 24 + 25 + ep, err := transport.NewEndpoint("/") 26 + if err != nil { 27 + http.Error(w, err.Error(), 500) 28 + log.Printf("git: %s", err) 29 + return 30 + } 31 + 32 + billyfs := osfs.New(repo) 33 + loader := server.NewFilesystemLoader(billyfs) 34 + srv := server.NewServer(loader) 35 + session, err := srv.NewUploadPackSession(ep, nil) 36 + if err != nil { 37 + http.Error(w, err.Error(), 500) 38 + log.Printf("git: %s", err) 39 + return 40 + } 41 + 42 + ar, err := session.AdvertisedReferencesContext(r.Context()) 43 + if errors.Is(err, transport.ErrRepositoryNotFound) { 44 + http.Error(w, err.Error(), 404) 45 + return 46 + } else if err != nil { 47 + http.Error(w, err.Error(), 500) 48 + return 49 + } 50 + 51 + ar.Prefix = [][]byte{ 52 + []byte("# service=git-upload-pack"), 53 + pktline.Flush, 54 + } 55 + 56 + if err = ar.Encode(w); err != nil { 57 + http.Error(w, err.Error(), 500) 58 + log.Printf("git: %s", err) 59 + return 60 + } 61 + } 62 + 63 + func (d *deps) UploadPack(w http.ResponseWriter, r *http.Request) { 64 + name := flow.Param(r.Context(), "name") 65 + name = filepath.Clean(name) 66 + 67 + repo := filepath.Join(d.c.Repo.ScanPath, name) 68 + 69 + w.Header().Set("content-type", "application/x-git-upload-pack-result") 70 + 71 + upr := packp.NewUploadPackRequest() 72 + err := upr.Decode(r.Body) 73 + if err != nil { 74 + http.Error(w, err.Error(), 400) 75 + log.Printf("git: %s", err) 76 + return 77 + } 78 + 79 + ep, err := transport.NewEndpoint("/") 80 + if err != nil { 81 + http.Error(w, err.Error(), 500) 82 + log.Printf("git: %s", err) 83 + return 84 + } 85 + 86 + billyfs := osfs.New(repo) 87 + loader := server.NewFilesystemLoader(billyfs) 88 + svr := server.NewServer(loader) 89 + session, err := svr.NewUploadPackSession(ep, nil) 90 + if err != nil { 91 + http.Error(w, err.Error(), 500) 92 + log.Printf("git: %s", err) 93 + return 94 + } 95 + 96 + res, err := session.UploadPack(r.Context(), upr) 97 + if err != nil { 98 + http.Error(w, err.Error(), 500) 99 + log.Printf("git: %s", err) 100 + return 101 + } 102 + 103 + if err = res.Encode(w); err != nil { 104 + http.Error(w, err.Error(), 500) 105 + log.Printf("git: %s", err) 106 + return 107 + } 108 + }
+9 -27
routes/handler.go
··· 1 1 package routes 2 2 3 3 import ( 4 - "log" 5 4 "net/http" 6 - "path/filepath" 7 5 8 6 "git.icyphox.sh/legit/config" 9 7 "github.com/alexedwards/flow" 10 - "github.com/sosedoff/gitkit" 11 8 ) 12 9 13 - type depsWrapper struct { 14 - actualDeps deps 15 - gitsvc *gitkit.Server 16 - } 17 - 18 10 // Checks for gitprotocol-http(5) specific smells; if found, passes 19 11 // the request on to the git http service, else render the web frontend. 20 - func (dw *depsWrapper) Multiplex(w http.ResponseWriter, r *http.Request) { 12 + func (d *deps) Multiplex(w http.ResponseWriter, r *http.Request) { 21 13 path := flow.Param(r.Context(), "...") 22 - name := flow.Param(r.Context(), "name") 23 - name = filepath.Clean(name) 24 14 25 15 if r.URL.RawQuery == "service=git-receive-pack" { 26 16 w.WriteHeader(http.StatusBadRequest) ··· 28 18 return 29 19 } 30 20 31 - if path == "info/refs" && r.URL.RawQuery == "service=git-upload-pack" && r.Method == "GET" { 32 - dw.gitsvc.ServeHTTP(w, r) 21 + if path == "info/refs" && 22 + r.URL.RawQuery == "service=git-upload-pack" && 23 + r.Method == "GET" { 24 + d.InfoRefs(w, r) 33 25 } else if path == "git-upload-pack" && r.Method == "POST" { 34 - dw.gitsvc.ServeHTTP(w, r) 26 + d.UploadPack(w, r) 35 27 } else if r.Method == "GET" { 36 - dw.actualDeps.RepoIndex(w, r) 28 + d.RepoIndex(w, r) 37 29 } 38 30 } 39 31 ··· 41 33 mux := flow.New() 42 34 d := deps{c} 43 35 44 - gitsvc := gitkit.New(gitkit.Config{ 45 - Dir: c.Repo.ScanPath, 46 - AutoCreate: false, 47 - }) 48 - if err := gitsvc.Setup(); err != nil { 49 - log.Fatalf("git server: %s", err) 50 - } 51 - 52 - dw := depsWrapper{actualDeps: d, gitsvc: gitsvc} 53 - 54 36 mux.NotFound = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { 55 37 d.Write404(w) 56 38 }) 57 39 58 40 mux.HandleFunc("/", d.Index, "GET") 59 41 mux.HandleFunc("/static/:file", d.ServeStatic, "GET") 60 - mux.HandleFunc("/:name", dw.Multiplex, "GET", "POST") 42 + mux.HandleFunc("/:name", d.Multiplex, "GET", "POST") 61 43 mux.HandleFunc("/:name/tree/:ref/...", d.RepoTree, "GET") 62 44 mux.HandleFunc("/:name/blob/:ref/...", d.FileContent, "GET") 63 45 mux.HandleFunc("/:name/log/:ref", d.Log, "GET") 64 46 mux.HandleFunc("/:name/commit/:ref", d.Diff, "GET") 65 47 mux.HandleFunc("/:name/refs", d.Refs, "GET") 66 - mux.HandleFunc("/:name/...", dw.Multiplex, "GET", "POST") 48 + mux.HandleFunc("/:name/...", d.Multiplex, "GET", "POST") 67 49 68 50 return mux 69 51 }