Skip to content

Commit b67e7b2

Browse files
authored
Merge pull request #10 from aymanbagabas/http-server
feat: add gogit-http-server command
2 parents 07ef52e + 8406ae4 commit b67e7b2

File tree

4 files changed

+138
-29
lines changed

4 files changed

+138
-29
lines changed

cmd/gogit-http-server/logging.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"net/http"
6+
"strings"
7+
"time"
8+
)
9+
10+
type logWriter struct {
11+
http.ResponseWriter
12+
code, bytes int
13+
}
14+
15+
func (r *logWriter) Write(p []byte) (int, error) {
16+
written, err := r.ResponseWriter.Write(p)
17+
r.bytes += written
18+
return written, err
19+
}
20+
21+
// Note this is generally only called when sending an HTTP error, so it's
22+
// important to set the `code` value to 200 as a default
23+
func (r *logWriter) WriteHeader(code int) {
24+
r.code = code
25+
r.ResponseWriter.WriteHeader(code)
26+
}
27+
28+
// LoggingMiddleware is the logging middleware where we log incoming and
29+
// outgoing requests for a multiplexer. It should be the first middleware
30+
// called so it can log request times accurately.
31+
func LoggingMiddleware(logger *log.Logger, next http.Handler) http.HandlerFunc {
32+
return func(w http.ResponseWriter, r *http.Request) {
33+
addr := r.RemoteAddr
34+
if colon := strings.LastIndex(addr, ":"); colon != -1 {
35+
addr = addr[:colon]
36+
}
37+
38+
writer := &logWriter{
39+
ResponseWriter: w,
40+
code: http.StatusOK, // default. so important! see above.
41+
}
42+
43+
startTime := time.Now()
44+
45+
next.ServeHTTP(writer, r)
46+
47+
elapsedTime := time.Since(startTime)
48+
logger.Printf("%s %s %s %s %d %dB %v", addr, r.Method, r.RequestURI, r.Proto, writer.code, writer.bytes, elapsedTime)
49+
}
50+
}

cmd/gogit-http-server/main.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"log"
7+
"net/http"
8+
"path/filepath"
9+
10+
"github.com/go-git/go-billy/v5/osfs"
11+
githttp "github.com/go-git/go-git/v6/backend/http"
12+
"github.com/go-git/go-git/v6/plumbing/transport"
13+
"github.com/spf13/cobra"
14+
)
15+
16+
var (
17+
port int
18+
prefix string
19+
)
20+
21+
func init() {
22+
rootCmd.Flags().IntVarP(&port, "port", "p", 8080, "Port to run the HTTP server on")
23+
rootCmd.Flags().StringVarP(&prefix, "prefix", "", "", "Prefix for the HTTP server routes")
24+
}
25+
26+
var rootCmd = &cobra.Command{
27+
Use: "gogit-http-server [options] <directory>",
28+
Short: "Run a Go Git HTTP server",
29+
Args: cobra.ExactArgs(1),
30+
RunE: func(cmd *cobra.Command, args []string) error {
31+
directory := args[0]
32+
addr := fmt.Sprintf(":%d", port)
33+
abs, err := filepath.Abs(directory)
34+
if err != nil {
35+
return fmt.Errorf("failed to get absolute path: %w", err)
36+
}
37+
38+
log.Printf("Using absolute path: %q", abs)
39+
logger := log.Default()
40+
loader := transport.NewFilesystemLoader(osfs.New(abs, osfs.WithBoundOS()), false)
41+
gitmw := githttp.NewBackend(loader, &githttp.BackendOptions{
42+
ErrorLog: logger,
43+
Prefix: prefix,
44+
})
45+
46+
handler := LoggingMiddleware(logger, gitmw)
47+
log.Printf("Starting server on %q for directory %q", addr, directory)
48+
if err := http.ListenAndServe(addr, handler); !errors.Is(err, http.ErrServerClosed) {
49+
return err
50+
}
51+
return nil
52+
},
53+
}
54+
55+
func main() {
56+
if err := rootCmd.Execute(); err != nil {
57+
log.Fatal(err)
58+
}
59+
}

go.mod

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@ module github.com/go-git/cli
33
go 1.23.0
44

55
require (
6-
github.com/go-git/go-git/v6 v6.0.0-20250407095008-f3dca17d9094
6+
github.com/go-git/go-billy/v5 v5.6.2
7+
github.com/go-git/go-git/v6 v6.0.0-20250420095607-675edb808690
78
github.com/spf13/cobra v1.8.1
8-
golang.org/x/crypto v0.36.0
9-
golang.org/x/term v0.30.0
9+
golang.org/x/crypto v0.37.0
10+
golang.org/x/term v0.31.0
1011
)
1112

1213
require (
1314
dario.cat/mergo v1.0.1 // indirect
1415
github.com/Microsoft/go-winio v0.6.2 // indirect
15-
github.com/ProtonMail/go-crypto v1.1.6 // indirect
16-
github.com/cloudflare/circl v1.6.0 // indirect
16+
github.com/ProtonMail/go-crypto v1.2.0 // indirect
17+
github.com/cloudflare/circl v1.6.1 // indirect
1718
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
1819
github.com/emirpasic/gods v1.18.1 // indirect
1920
github.com/go-git/gcfg/v2 v2.0.1 // indirect
20-
github.com/go-git/go-billy/v5 v5.6.0 // indirect
2121
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
2222
github.com/inconshreveable/mousetrap v1.1.0 // indirect
2323
github.com/kevinburke/ssh_config v1.2.0 // indirect
2424
github.com/pjbgf/sha1cd v0.3.2 // indirect
2525
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
2626
github.com/spf13/pflag v1.0.5 // indirect
27-
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
28-
golang.org/x/net v0.37.0 // indirect
29-
golang.org/x/sys v0.31.0 // indirect
27+
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
28+
golang.org/x/net v0.39.0 // indirect
29+
golang.org/x/sys v0.32.0 // indirect
3030
)

go.sum

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
22
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
33
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
44
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
5-
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
6-
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
5+
github.com/ProtonMail/go-crypto v1.2.0 h1:+PhXXn4SPGd+qk76TlEePBfOfivE0zkWFenhGhFLzWs=
6+
github.com/ProtonMail/go-crypto v1.2.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
77
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
88
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
99
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
1010
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
11-
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
12-
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
11+
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
12+
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
1313
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
1414
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
1515
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
@@ -24,14 +24,14 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
2424
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
2525
github.com/go-git/gcfg/v2 v2.0.1 h1:vIDPEdcmkwmbMCHs/0Fv/HFA9SH9ZVVI/gglNeLztF0=
2626
github.com/go-git/gcfg/v2 v2.0.1/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs=
27-
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
28-
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
27+
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
28+
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
2929
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
3030
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
3131
github.com/go-git/go-git-fixtures/v5 v5.0.0-20241203230421-0753e18f8f03 h1:LumE+tQdnYW24a9RoO08w64LHTzkNkdUqBD/0QPtlEY=
3232
github.com/go-git/go-git-fixtures/v5 v5.0.0-20241203230421-0753e18f8f03/go.mod h1:hMKrMnUE4W0SJ7bFyM00dyz/HoknZoptGWzrj6M+dEM=
33-
github.com/go-git/go-git/v6 v6.0.0-20250407095008-f3dca17d9094 h1:uyCInlkC8j67Wq1k1YVZNeUv1dFBjTUZ9tUG/rAaJZk=
34-
github.com/go-git/go-git/v6 v6.0.0-20250407095008-f3dca17d9094/go.mod h1:1Sn9LRp6s8Vq92QPRvJoSl2qFySmiSk4PxcFGvqa6co=
33+
github.com/go-git/go-git/v6 v6.0.0-20250420095607-675edb808690 h1:kqVMX8PDpDEPVjJKvXzJhsTyNJ3BilX78PxggnoiDE8=
34+
github.com/go-git/go-git/v6 v6.0.0-20250420095607-675edb808690/go.mod h1:Mx1rh5v6buQtUC3bHowycdJnp4s3TrvP4xjpc3/NO7g=
3535
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
3636
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
3737
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -66,18 +66,18 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
6666
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
6767
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
6868
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
69-
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
70-
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
71-
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
72-
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
73-
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
74-
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
75-
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
76-
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
77-
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
78-
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
79-
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
80-
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
69+
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
70+
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
71+
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
72+
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
73+
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
74+
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
75+
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
76+
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
77+
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
78+
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
79+
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
80+
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
8181
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
8282
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
8383
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

0 commit comments

Comments
 (0)