knotserver: use local clones if repo is hosted on the same knot #850

merged
opened by oppi.li targeting master from op/mozkrnmzvkru

detect the host to clone from and use a local clone if possible.

Signed-off-by: oppiliappan me@oppi.li

Changed files
+39 -3
knotserver
+38 -2
knotserver/git/fork.go
···
import (
"errors"
"fmt"
"os/exec"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
)
-
func Fork(repoPath, source string) error {
-
cloneCmd := exec.Command("git", "clone", "--bare", source, repoPath)
if err := cloneCmd.Run(); err != nil {
return fmt.Errorf("failed to bare clone repository: %w", err)
}
···
return nil
}
func (g *GitRepo) Sync() error {
branch := g.h.String()
···
import (
"errors"
"fmt"
+
"log/slog"
+
"net/url"
"os/exec"
+
"path/filepath"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
+
knotconfig "tangled.org/core/knotserver/config"
)
+
func Fork(repoPath, source string, cfg *knotconfig.Config) error {
+
u, err := url.Parse(source)
+
if err != nil {
+
return fmt.Errorf("failed to parse source URL: %w", err)
+
}
+
+
if o := optimizeClone(u, cfg); o != nil {
+
u = o
+
}
+
+
cloneCmd := exec.Command("git", "clone", "--bare", u.String(), repoPath)
if err := cloneCmd.Run(); err != nil {
return fmt.Errorf("failed to bare clone repository: %w", err)
}
···
return nil
}
+
func optimizeClone(u *url.URL, cfg *knotconfig.Config) *url.URL {
+
// only optimize if it's the same host
+
if u.Host != cfg.Server.Hostname {
+
return nil
+
}
+
+
local := filepath.Join(cfg.Repo.ScanPath, u.Path)
+
+
// sanity check: is there a git repo there?
+
if _, err := PlainOpen(local); err != nil {
+
return nil
+
}
+
+
// create optimized file:// URL
+
optimized := &url.URL{
+
Scheme: "file",
+
Path: local,
+
}
+
+
slog.Debug("performing local clone", "url", optimized.String())
+
return optimized
+
}
+
func (g *GitRepo) Sync() error {
branch := g.h.String()
+1 -1
knotserver/xrpc/create_repo.go
···
repoPath, _ := securejoin.SecureJoin(h.Config.Repo.ScanPath, relativeRepoPath)
if data.Source != nil && *data.Source != "" {
-
err = git.Fork(repoPath, *data.Source)
if err != nil {
l.Error("forking repo", "error", err.Error())
writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError)
···
repoPath, _ := securejoin.SecureJoin(h.Config.Repo.ScanPath, relativeRepoPath)
if data.Source != nil && *data.Source != "" {
+
err = git.Fork(repoPath, *data.Source, h.Config)
if err != nil {
l.Error("forking repo", "error", err.Error())
writeError(w, xrpcerr.GenericError(err), http.StatusInternalServerError)