s
This commit is contained in:
+33
-1
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@@ -20,6 +21,7 @@ type Config struct {
|
||||
DBUri string
|
||||
SkipAuth bool
|
||||
|
||||
preparedDbUri string
|
||||
prepared atomic.Bool
|
||||
driver string
|
||||
dsn string
|
||||
@@ -31,6 +33,9 @@ func (c *Config) RepoRoot() string {
|
||||
|
||||
// Prepare checks that the config is valid and creates the repo root if needed.
|
||||
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)")
|
||||
@@ -38,7 +43,7 @@ func (c *Config) Prepare() error {
|
||||
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.DBUri, err = ParseDBURI(c.Root, c.DBUri)
|
||||
c.driver, c.dsn, c.preparedDbUri, err = ParseDBURI(c.Root, c.DBUri)
|
||||
if err != nil {
|
||||
return errors.New("simplegit: ParseDBURI failed")
|
||||
}
|
||||
@@ -65,3 +70,30 @@ func (c *Config) DSN() string {
|
||||
}
|
||||
return c.dsn
|
||||
}
|
||||
|
||||
func (c *Config) DBURI() string {
|
||||
if !c.prepared.Load() {
|
||||
panic("Config.PreparedDBUri called before Prepare")
|
||||
}
|
||||
return c.preparedDbUri
|
||||
}
|
||||
|
||||
// normalizeName strips one trailing ".git" so both "myrepo" and "myrepo.git"
|
||||
// refer to the same repo.
|
||||
func normalizeName(name string) string {
|
||||
return strings.TrimSuffix(name, ".git")
|
||||
}
|
||||
|
||||
// relPath returns the repo path relative to root: "owner/name.git".
|
||||
func relPath(owner, name string) string {
|
||||
return owner + "/" + normalizeName(name) + ".git"
|
||||
}
|
||||
|
||||
// RepoPath returns the absolute on-disk path for owner/name, but only if the
|
||||
// repo is registered in the DB -- the DB is the authority, not the filesystem.
|
||||
// In skip-auth mode the DB check is skipped (any path under root resolves).
|
||||
func (s *Config) RepoPath(owner, name string) (string, error) {
|
||||
name = normalizeName(name)
|
||||
rel := relPath(owner, name)
|
||||
return Resolve(s.RepoRoot(), rel)
|
||||
}
|
||||
|
||||
+4
-3
@@ -21,7 +21,6 @@ import (
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
gitRepoRoot string
|
||||
cfg *common.Config
|
||||
startedAt time.Time
|
||||
middleware *MiddlewareClient
|
||||
@@ -29,8 +28,10 @@ type Server struct {
|
||||
}
|
||||
|
||||
func NewServer(cfg *common.Config, middleware *MiddlewareClient, mut state.IStateMut) *Server {
|
||||
if err := cfg.Prepare(); err != nil {
|
||||
return nil
|
||||
}
|
||||
return &Server{
|
||||
gitRepoRoot: cfg.Root,
|
||||
cfg: cfg,
|
||||
startedAt: time.Now(),
|
||||
middleware: middleware,
|
||||
@@ -168,7 +169,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (s *Server) open(ctx context.Context, repo string) (*gitcmd.Repository, error) {
|
||||
p, err := common.Resolve(s.gitRepoRoot, repo)
|
||||
p, err := common.Resolve(s.cfg.RepoRoot(), repo)
|
||||
if err != nil {
|
||||
return nil, newError(codeInvalidParams, "invalid repo name: "+err.Error())
|
||||
}
|
||||
|
||||
+2
-21
@@ -185,22 +185,11 @@ func fingerprint(key ssh.PublicKey) string {
|
||||
return "SHA256:" + hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// normalizeName strips one trailing ".git" so both "myrepo" and "myrepo.git"
|
||||
// refer to the same repo.
|
||||
func normalizeName(name string) string {
|
||||
return strings.TrimSuffix(name, ".git")
|
||||
}
|
||||
|
||||
// relPath returns the repo path relative to root: "owner/name.git".
|
||||
func relPath(owner, name string) string {
|
||||
return owner + "/" + normalizeName(name) + ".git"
|
||||
}
|
||||
|
||||
// findRepo looks up a repo by (owner, name). name may include ".git". A missing
|
||||
// row yields ErrRepoNotFound.
|
||||
func (s *LocalState) findRepo(owner, name string) (*Repo, error) {
|
||||
var r Repo
|
||||
has, err := s.engine.Where("namespace = ? AND name = ?", owner, normalizeName(name)).Get(&r)
|
||||
has, err := s.engine.Where("namespace = ? AND name = ?", owner, strings.TrimSuffix(name, ".git")).Get(&r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("lookup repo: %w", err)
|
||||
}
|
||||
@@ -210,16 +199,8 @@ func (s *LocalState) findRepo(owner, name string) (*Repo, error) {
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
// RepoPath returns the absolute on-disk path for owner/name, but only if the
|
||||
// repo is registered in the DB -- the DB is the authority, not the filesystem.
|
||||
// In skip-auth mode the DB check is skipped (any path under root resolves).
|
||||
func (s *LocalState) RepoPath(owner, name string) (string, error) {
|
||||
name = normalizeName(name)
|
||||
rel := relPath(owner, name)
|
||||
if _, err := s.findRepo(owner, name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return common.Resolve(s.cfg.RepoRoot(), rel)
|
||||
return s.cfg.RepoPath(owner, name)
|
||||
}
|
||||
|
||||
// Open returns a gitcmd.Repository for owner/name. The repo must be registered
|
||||
|
||||
+5
-5
@@ -106,7 +106,7 @@ func (s *LocalState) nextNamespaceID() (int64, error) {
|
||||
// namespace must already exist (have at least one repo) so NamespaceID can be
|
||||
// resolved; NameID is freshly assigned. skip-auth: disk-only (git init, no DB).
|
||||
func (s *LocalState) CreateRepo(ns, name string) error {
|
||||
path, err := s.RepoPath(ns, name)
|
||||
path, err := s.cfg.RepoPath(ns, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func (s *LocalState) ExistRepo(ns, name string) error {
|
||||
// DeleteRepo removes the repo row, its repo-targeted ACL grants, and the
|
||||
// on-disk bare directory. Hard-deletes. skip-auth: disk-only.
|
||||
func (s *LocalState) DeleteRepo(ns, name string) error {
|
||||
path, _ := s.RepoPath(ns, name)
|
||||
path, _ := s.cfg.RepoPath(ns, name)
|
||||
r, err := s.findRepo(ns, name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -186,11 +186,11 @@ func (s *LocalState) MoveRepo(old, new string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldPath, err := s.RepoPath(oldNs, oldName)
|
||||
oldPath, err := s.cfg.RepoPath(oldNs, oldName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newPath, err := s.RepoPath(newNs, newName)
|
||||
newPath, err := s.cfg.RepoPath(newNs, newName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -207,7 +207,7 @@ func (s *LocalState) MoveRepo(old, new string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
upd := Repo{Namespace: newNs, Name: normalizeName(newName)}
|
||||
upd := Repo{Namespace: newNs, Name: strings.TrimSuffix(newName, ".git")}
|
||||
cols := []string{"namespace", "name"}
|
||||
if newNs != oldNs {
|
||||
nsID, err := s.resolveNamespaceID(newNs)
|
||||
|
||||
Reference in New Issue
Block a user