caddy-git-server
Caddy module that provides a git server.
<!DOCTYPE html>
<html class="h-full bg-gray-100">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
<title>caddy-git-server - blob</title>
</head>
<body class="bg-gray-100">
<!-- full-width container with bg -->
<div class="bg-white shadow-sm">
<!-- Header -->
<div class="px-8 pt-2 mb-4 2xl:px-0 max-w-7xl mx-auto">
<div class="flex flex-wrap justify-between items-center">
<p class="text-2xl">caddy-git-server</p>
<p class="font-mono text-xs bg-gray-200 px-2 hidden sm:block rounded-xl"><span class="">git clone </span><span class="font-bold">https://localhost/git/caddy-git-server.git</span></p>
</div>
<div class="flex flex-wrap justify-between items-center">
<p class="font-xs text-gray-500">Provides a `git_server` caddy module for serving git repositories.</p>
<select class="px-4">
<option>main</option>
<option>master</option>
<option>trunk</option>
<option>reallylongbranchname</option>
</select>
</div>
<div class="flex flex-row flex-nowrap justify-start">
<a href="tree.html"><div class="cursor-pointer px-2 pt-1 hover:border-b-2">Tree</div></a>
<a href="log.html"><div class="cursor-pointer px-2 pt-1 hover:border-b-2">Log</div></a>
<div class="cursor-pointer px-2 pt-1 hover:border-b-2">Diff</div>
<div class="cursor-pointer px-2 pt-1 border-b-2 border-orange-400">Blob</div>
</div>
</div>
</div>
<!-- max-width content container -->
<div class="max-w-7xl mx-auto">
<div class="max-w-full bg-white shadow-sm rounded-sm">
<p class="mx-4 px-2 py-2 border-b-2 font-medium text-lg">
caddy_git_server.go
</p>
<div class="px-0 py-2 overflow-x-auto">
<pre><code>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 (<repo>.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
}</code></pre>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css">
<!-- <link rel="stylesheet" href="/assets/highlight/default.min.css"> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<!-- <script src="/assets/highlight/highlight.min.js"></script> -->
<script src="//cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.9.0/highlightjs-line-numbers.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/go.min.js"></script> -->
<script>hljs.highlightAll(); hljs.initLineNumbersOnLoad()</script>
</div>
</div>
</div>
<!-- Footer -->
<div class="mt-4 sticky top-[100vh]">
<div class="px-3 py-2 text-md text-center">
Served with
<img src="cgs-icon.png" class="size-6 inline mx-1">
<a href="https://git.mckinnon.ninja/caddy-git-server" class="font-medium underline">
caddy-git-server
</a>
</div>
</div>
</div>
</body>
</html>