/go-git-http-xfer

Implements Git HTTP Transport.

Primary LanguageGo

go-git-http-xfer Build Status Coverage Status

Implements Git HTTP Transport.

Support Protocol

  • The Smart Protocol
  • The Dumb Protocol

Requires

  • Go 1.7+

Quickly Trial

Let's clone this repository and execute the following commands.

# docker build
$ docker build -t go-git-http-xfer .

# test
$ docker run --rm -v $PWD:/go/src/github.com/nulab/go-git-http-xfer go-git-http-xfer \
    bash -c "gotestcover -v -covermode=count -coverprofile=coverage.out ./..."

# run server
$ docker run -it --rm -v $PWD:/go/src/github.com/nulab/go-git-http-xfer -p 5050:5050 go-git-http-xfer \
    bash -c "go run ./example/main.go -p 5050"

# in your local machine
$ git clone http://localhost:5050/example.git

Installation

This package can be installed with the go get command:

$ go get github.com/nulab/go-git-http-xfer

Usage

Basic

package main

import (
	"log"
	"net/http"

	"github.com/nulab/go-git-http-xfer/githttpxfer"
)

func main() {
	
	ghx, err := githttpxfer.New("/data/git", "/usr/bin/git")
	if err != nil {
		log.Fatalf("GitHTTPXfer instance could not be created. %s", err.Error())
		return
	}
	
	if err := http.ListenAndServe(":5050", ghx); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

You can add optional parameters to constructor function.

  • DisableUploadPack : Disable git upload-pack command.
  • DisableReceivePack: Disable git receive-pack command.
  • WithoutDumbProto : Without dumb protocol handling.
  • WithoutDumbProtoExceptHead : Without dumb protocol except head handling.
	ghx, err := githttpxfer.New(
		"/data/git",
		"/usr/bin/git",
		githttpxfer.DisableUploadPack(),
		githttpxfer.DisableReceivePack(),
		githttpxfer.WithoutDumbProto(),
	)

You can add some custom route.

func main() {

	ghx, err := githttpxfer.New("/data/git", "/usr/bin/git")
	if err != nil {
		log.Fatalf("GitHTTPXfer instance could not be created. %s", err.Error())
		return
	}

	// You can add some custom route.
	ghx.Router.Add(githttpxfer.NewRoute(
		http.MethodGet,
		func (u *url.URL) *Match {
			suffix := "/hello"
			if !strings.HasSuffix(u.Path, suffix) {
				return nil
			}
			repoPath := strings.Replace(u.Path, suffix, "", 1)
			filePath := strings.Replace(u.Path, repoPath+"/", "", 1)
			return &Match{repoPath, filePath}
		},
		func(ctx githttpxfer.Context) {
			resp, req := ctx.Response(), ctx.Request()
			rp, fp := ctx.RepoPath(), ctx.FilePath()
			fmt.Fprintf(resp.Writer,
				"Hi there. URI: %s, RepoPath: %s, FilePath: %s",
				req.URL.RequestURI(), rp, fp)
		},
	))
	
	if err := http.ListenAndServe(":5050", ghx); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

You can add some middleware.

func main() {
	
	ghx, err := githttpxfer.New("/data/git", "/usr/bin/git")
	if err != nil {
		log.Fatalf("GitHTTPXfer instance could not be created. %s", err.Error())
		return
	}
	
	handler := Logging(ghx)
	
	if err := http.ListenAndServe(":5050", ghx); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func Logging(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t1 := time.Now()
		next.ServeHTTP(w, r)
		t2 := time.Now()
		log.Printf("[%s] %q %v\n", r.Method, r.URL.String(), t2.Sub(t1))
	})
}

You can add some addon handler. (git archive)

import (
	"github.com/nulab/go-git-http-xfer/addon/handler/archive"
)

func main() {
	ghx, err := githttpxfer.New("/data/git", "/usr/bin/git")
	if err != nil {
		log.Fatalf("GitHTTPXfer instance could not be created. %s", err.Error())
		return
	}
	
	ghx.Router.Add(githttpxfer.NewRoute(
		archive.Method,
		archive.Pattern,
		archive.New(ghx).Archive,
	))
	
	if err := http.ListenAndServe(":5050", ghx); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

Reference

Bugs and Feedback

For bugs, questions and discussions please use the Github Issues.

License

MIT License