Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions githttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ type GitHttp struct {
// Root directory to serve repos from
ProjectRoot string

// Git service path prefix
UrlPrefix string

// Path to git binary
GitBinPath string

Expand All @@ -32,9 +35,10 @@ func (g *GitHttp) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}

// Shorthand constructor for most common scenario
func New(root string) *GitHttp {
func New(root, urlPrefix string) *GitHttp {
return &GitHttp{
ProjectRoot: root,
UrlPrefix: urlPrefix,
GitBinPath: "/usr/bin/git",
UploadPack: true,
ReceivePack: true,
Expand Down Expand Up @@ -231,7 +235,7 @@ func (g *GitHttp) getGitDir(file_path string) (string, error) {

f := path.Join(root, file_path)
if _, err := os.Stat(f); os.IsNotExist(err) {
return "", err
return f, err
}

return f, nil
Expand Down
18 changes: 12 additions & 6 deletions routing.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package githttp

import (
"log"
"net/http"
"os"
"path/filepath"
"regexp"
"strings"
)
Expand Down Expand Up @@ -68,12 +70,14 @@ func (g *GitHttp) getService(path string) (string, *Service) {

// Request handling function
func (g *GitHttp) requestHandler(w http.ResponseWriter, r *http.Request) {
realPath := r.URL.Path[len(g.UrlPrefix):]

// Get service for URL
repo, service := g.getService(r.URL.Path)
repo, service := g.getService(realPath)

// No url match
if service == nil {
renderNotFound(w)
renderNotFoundText(w, "service not found")
return
}

Expand All @@ -87,15 +91,17 @@ func (g *GitHttp) requestHandler(w http.ResponseWriter, r *http.Request) {
rpc := service.Rpc

// Get specific file
file := strings.Replace(r.URL.Path, repo+"/", "", 1)
file := strings.Replace(realPath, repo+"/", "", 1)

// Resolve directory
dir, err := g.getGitDir(repo)

// Repo not found on disk
if err != nil {
renderNotFound(w)
return
if !filepath.IsAbs(dir) {
log.Fatalf("%v is not absolute path", dir)
}
RunCommandMust("git", "init", "--bare", dir)
}

// Build request info for handler
Expand All @@ -104,7 +110,7 @@ func (g *GitHttp) requestHandler(w http.ResponseWriter, r *http.Request) {
// Call handler
if err := service.Handler(hr); err != nil {
if os.IsNotExist(err) {
renderNotFound(w)
renderNotFoundText(w, "file not found on disk")
return
}
switch err.(type) {
Expand Down
52 changes: 52 additions & 0 deletions shell.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package githttp

import (
"bytes"
"errors"
"fmt"
"log"
"os"
"os/exec"
)

func RunCommandMust(command string, args ...string) (string, string) {
stdout, stderr, err := RunCommand(command, args...)

if err != nil {
errText := fmt.Sprintf("error: %v\nstdout: %v\nstderr: %v\n", err, stdout, stderr)
log.Fatal(errors.New(errText))
}
return stdout, stderr
}

func RunCommand(command string, args ...string) (string, string, error) {
cmd := exec.Command(command, args...)

var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

err := cmd.Run()
return stdout.String(), stderr.String(), err
}

func RunCommandWithWd(dir, command string, args ...string) (string, string, error) {
wd, err := os.Getwd()
fatalError(err)

err = os.Chdir(dir)
fatalError(err)

stdout, stderr, err := RunCommand(command, args...)

err = os.Chdir(wd)
fatalError(err)
return stdout, stderr, err
}

func fatalError(err error) {
if err != nil {
log.Fatal(err)
}
}
8 changes: 7 additions & 1 deletion utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,15 @@ func renderMethodNotAllowed(w http.ResponseWriter, r *http.Request) {
}
}

func renderNotFoundText(w http.ResponseWriter, text string) {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(text))
}

func renderNotFound(w http.ResponseWriter) {
const defaultNotFoundString = "Not Found"
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("Not Found"))
w.Write([]byte(defaultNotFoundString))
}

func renderNoAccess(w http.ResponseWriter) {
Expand Down