105 lines
2.9 KiB
Go
105 lines
2.9 KiB
Go
package common
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync/atomic"
|
|
)
|
|
|
|
type Config struct {
|
|
Root string
|
|
// SSHAddr: git SSH listen (clone/push over SSH, keyed auth).
|
|
SSHAddr string
|
|
// HTTPAddr: plain HTTP listen for git smart-HTTP clone/push
|
|
// (/:owner/:name.git/*) + the index page. This is the user-facing git
|
|
// transport (nginx routes .git/* here). Empty = no HTTP listener.
|
|
HTTPAddr string
|
|
// GitRPCAddrs: Connect-RPC listen addresses (GitService + ManageService)
|
|
// PLUS the binary /raw, /archive, /patch content endpoints. Others dial
|
|
// these to read/write/modify repo content and drive repo lifecycle. May be
|
|
// multiple (e.g. a unix socket for a local TUI and a tcp addr for the
|
|
// console). Empty = no gitrpc listener.
|
|
GitRPCAddrs []string
|
|
// HookScript is an operator-provided executable invoked by every Git hook.
|
|
// The hook name is its first argument; Git's original args, stdin and
|
|
// environment are preserved. Empty disables hook effects.
|
|
HookScript string
|
|
// HookArgs are fixed CLI arguments placed before the hook type and repo.
|
|
HookArgs []string
|
|
DBUri string
|
|
|
|
preparedDbUri string
|
|
prepared atomic.Bool
|
|
driver string
|
|
dsn string
|
|
}
|
|
|
|
func (c *Config) RepoRoot() string {
|
|
return filepath.Join(c.Root, "repos")
|
|
}
|
|
|
|
func (c *Config) TemplateDir() string {
|
|
return filepath.Join(c.Root, "template")
|
|
}
|
|
|
|
func (c *Config) Prepare() error {
|
|
if c.prepared.Load() {
|
|
return nil
|
|
}
|
|
var err error
|
|
if c.DBUri == "" {
|
|
return errors.New("simplegit: -db is required (e.g. sqlite://state.db)")
|
|
}
|
|
if err := os.MkdirAll(c.RepoRoot(), 0o755); err != nil {
|
|
return fmt.Errorf("simplegit: Failed to create data root: %s (%v)", c.RepoRoot(), err)
|
|
}
|
|
c.driver, c.dsn, c.preparedDbUri, err = ParseDBURI(c.Root, c.DBUri)
|
|
if err != nil {
|
|
return errors.New("simplegit: ParseDBURI failed")
|
|
}
|
|
// Listeners are all optional: a daemon with only -ssh, only -http, only
|
|
// -gitrpc, or any combination is valid (empty = that surface is disabled).
|
|
// At least one of -http/-ssh/-gitrpc should be set for the daemon to do
|
|
// anything useful, but that is the operator's choice, not a hard error.
|
|
c.prepared.Store(true)
|
|
return nil
|
|
}
|
|
|
|
func (c *Config) Driver() string {
|
|
if !c.prepared.Load() {
|
|
panic("Config.Driver called before Prepare")
|
|
}
|
|
return c.driver
|
|
}
|
|
|
|
func (c *Config) DSN() string {
|
|
if !c.prepared.Load() {
|
|
panic("Config.DSN called before Prepare")
|
|
}
|
|
return c.dsn
|
|
}
|
|
|
|
func (c *Config) DBURI() string {
|
|
if !c.prepared.Load() {
|
|
panic("Config.PreparedDBUri called before Prepare")
|
|
}
|
|
return c.preparedDbUri
|
|
}
|
|
|
|
func normalizeName(name string) string {
|
|
return strings.TrimSuffix(name, ".git")
|
|
}
|
|
|
|
func relPath(owner, name string) string {
|
|
return owner + "/" + normalizeName(name) + ".git"
|
|
}
|
|
|
|
func (s *Config) RepoPath(owner, name string) (string, error) {
|
|
name = normalizeName(name)
|
|
rel := relPath(owner, name)
|
|
return Resolve(s.RepoRoot(), rel)
|
|
}
|