caddy_git_server.go
package gitserver
import (
"fmt"
"io/fs"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"github.com/caddyserver/caddy/v2/modules/caddyhttp/fileserver"
"go.uber.org/zap"
)
func init() {
caddy.RegisterModule(GitServer{})
httpcaddyfile.RegisterHandlerDirective("git_server", parseCaddyfile)
}
type GitServer struct {
// Git http protocol to use: 'dumb' or 'smart' or 'both' (default)
// Note this doesn't actually do anything currently, only the dumb protocol is implemented.
Protocol string `json:"protocol,omitempty"`
// Path to directory containing bare git repos (.git)
Root string `json:"root,omitempty"`
// How far to search in root
Depth int `json:"depth,omitempty"`
// Enable repo browser
Browse bool `json:"browse,omitempty"`
TemplateDir string `json:"template_dir,omitempty"`
AssetDir string `json:"asset_dir,omitempty"`
ListedDefault bool `json:"listed_default,omitemty"`
// If IgnorePrefix is defined we strip it from the URL path
IgnorePrefix string `json:"ignore_prefix,omitempty"`
// Mirror a git repo
// Mirror bool `json:"mirror,omitempty"`
// MirrorRemotes []string
// File server module that serves static git files
// FileServerRaw json.RawMessage `json:"file_server,omitempty" caddy:"namespace=http.handlers inline_key=handler"`
FileServer *fileserver.FileServer `json:"-"`
// This is a list of relative paths to repositories in the root directory.
// If set, the IgnorePrefix is stripped
repositories []string
repositoriesLastModified time.Time
logger *zap.Logger
}
// CaddyModule returns the Caddy module information.
func (GitServer) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.handlers.git_server",
New: func() caddy.Module { return new(GitServer) },
}
}
// Unmarshal caddyfile directive into a GitServer
func (gsrv *GitServer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// println("init:", d.Val())
for d.Next() {
// println("for:", d.Val(), strings.Join(d.RemainingArgs(), " "))
// Check if we have optional "browse" on the end of 'git_server' directive
args := d.RemainingArgs()
switch len(args) {
case 0:
case 1:
if args[0] != "browse" {
return d.ArgErr()
}
gsrv.Browse = true
default:
return d.ArgErr()
}
// Loop over remaining options
for d.NextBlock(0) {
// println("next:", d.Val())
switch d.Val() {
case "protocol":
if d.NextArg() {
if d.Val() == "dumb" || d.Val() == "smart" || d.Val() == "both" {
gsrv.Protocol = d.Val()
} else {
return d.ArgErr()
}
} else {
return d.ArgErr()
}
case "root":
if !d.AllArgs(&gsrv.Root) {
return d.ArgErr()
}
case "depth":
var depth_arg string
if !d.AllArgs(&depth_arg) {
return d.ArgErr()
}
depth, err := strconv.Atoi(depth_arg)
if err != nil {
return d.SyntaxErr("expected number")
}
gsrv.Depth = depth
case "browse":
gsrv.Browse = true
case "template_dir":
if !d.AllArgs(&gsrv.TemplateDir) {
return d.ArgErr()
}
// case "mirror":
// gsrv.Mirror = true
// if d.NextArg() {
// gsrv.MirrorRemotes = append(gsrv.MirrorRemotes, d.Val())
// } else {
// return d.ArgErr()
// }
case "asset_dir":
if !d.AllArgs(&gsrv.AssetDir) {
return d.ArgErr()
}
// case "ignore_prefix":
// if !d.AllArgs(&gsrv.IgnorePrefix) {
// return d.ArgErr()
// }
case "listed_default":
var listed string
if !d.AllArgs(&listed) {
return d.ArgErr()
}
listedBool, err := strconv.ParseBool(listed)
if err != nil {
return d.SyntaxErr("expected boolean")
}
gsrv.ListedDefault = listedBool
}
}
}
return nil
}