Compare commits

...

2 commits

Author SHA1 Message Date
Matthias Riße
977627fe6e fix: make p2phttp work for deleted and recreated repositories (#86)
Some checks failed
/ build-oci-image (rootful) (push) Failing after 2m18s
/ build-oci-image (rootless) (push) Failing after 1m29s
testing / backend-checks (push) Successful in 18m14s
testing / frontend-checks (push) Successful in 2m33s
testing / test-unit (push) Has been skipped
testing / test-e2e (push) Has been skipped
testing / test-mysql (push) Successful in 51m31s
testing / test-pgsql (push) Successful in 1h11m53s
testing / test-remote-cacher (redis) (push) Has been skipped
testing / test-remote-cacher (valkey) (push) Has been skipped
testing / test-remote-cacher (garnet) (push) Has been skipped
testing / test-remote-cacher (redict) (push) Has been skipped
testing / test-sqlite (push) Failing after 3h28m4s
/ release (push) Has been cancelled
testing / security-check (push) Has been cancelled
The issue was that the caching mechanism for the UUID to repository path
association tried to be too smart and ended up buggy. This removes the
parts that skip updating the UUIDs for already-in-cache repository
paths. This change makes updating the cache more expensive, but since
https://codeberg.org/forgejo-aneksajo/forgejo-aneksajo/pulls/65 is
merged it should be fast enough to be fine.

Fixes #83.

Reviewed-on: https://codeberg.org/forgejo-aneksajo/forgejo-aneksajo/pulls/86
Co-authored-by: Matthias Riße <m.risse@fz-juelich.de>
Co-committed-by: Matthias Riße <m.risse@fz-juelich.de>
2025-06-14 17:33:43 +02:00
Matthias Riße
85fb7bafd7 fix: improve p2phttp for not-yet-initialized repos (#84)
Previously pushing to a not-yet-initialized repository would not
properly initialize git-annex until the repository's page was visited. A
`git annex sync --content` also didn't immediately transfer data,
instead requiring a second invocation (after the workaround of visiting
the repo page).

Push-to-create was also broken with p2phttp because git-annex tried to
read the repositories config before pushing anything, got a 404, and set
`annex-ignore=true`. It then required a manual `git annex enableremote
origin` to get git-annex to use the remote.

This fixes these issues by:
1. making requests to a repository's config endpoint use the
   push-to-create logic
2. initializing the repository for git-annex if a git-annex client makes
   a request to the config endpoint

This brings the p2phttp behavior in line with ssh behavior, where `git
annex sync --content` issues a `git-annex-shell configlist` with
`autoinit=1`.

Fixes #85.

Reviewed-on: https://codeberg.org/forgejo-aneksajo/forgejo-aneksajo/pulls/84
Co-authored-by: Matthias Riße <m.risse@fz-juelich.de>
Co-committed-by: Matthias Riße <m.risse@fz-juelich.de>
2025-06-14 17:30:40 +02:00
3 changed files with 23 additions and 17 deletions

View file

@ -152,10 +152,7 @@ func IsAnnexRepo(repo *git.Repository) bool {
return err == nil
}
var (
uuid2repoPathCache = make(map[string]string)
repoPath2uuidCache = make(map[string]string)
)
var uuid2repoPathCache = make(map[string]string)
func Init() error {
if !setting.Annex.Enabled {
@ -179,10 +176,6 @@ func updateUUID2RepoPathCache() error {
}
for _, configFile := range configFiles {
repoPath := strings.TrimSuffix(configFile, "/config")
_, ok := repoPath2uuidCache[repoPath]
if ok {
continue
}
config, err := ini.Load(configFile)
if err != nil {
continue
@ -190,7 +183,6 @@ func updateUUID2RepoPathCache() error {
repoUUID := config.Section("annex").Key("uuid").Value()
if repoUUID != "" {
uuid2repoPathCache[repoUUID] = repoPath
repoPath2uuidCache[repoPath] = repoUUID
}
}
return nil
@ -219,11 +211,6 @@ func checkValidity(uuid, repoPath string) (bool, error) {
return uuid == repoUUID, nil
}
func removeCachedEntries(uuid, repoPath string) {
delete(uuid2repoPathCache, uuid)
delete(repoPath2uuidCache, repoPath)
}
func UUID2RepoPath(uuid string) (string, error) {
// Get the current cache entry for the UUID
repoPath, err := repoPathFromUUIDCache(uuid)
@ -237,7 +224,7 @@ func UUID2RepoPath(uuid string) (string, error) {
}
if !valid {
// If it isn't, remove the cache entry and try again
removeCachedEntries(uuid, repoPath)
delete(uuid2repoPathCache, uuid)
return UUID2RepoPath(uuid)
}
// Otherwise just return the cached entry

View file

@ -36,6 +36,7 @@ func AnnexP2PHTTP(ctx *services_context.Context) {
uuid := ctx.Params(":uuid")
repoPath, err := annex.UUID2RepoPath(uuid)
if err != nil {
log.Error("%v", err)
ctx.PlainText(http.StatusNotFound, "Repository not found")
return
}
@ -45,12 +46,14 @@ func AnnexP2PHTTP(ctx *services_context.Context) {
owner := parts[len(parts)-2]
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, owner, repoName)
if err != nil {
log.Error("%v", err)
ctx.PlainText(http.StatusNotFound, "Repository not found")
return
}
p, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
log.Error("%v", err)
ctx.ServerError("GetUserRepoPermission", err)
return
}

View file

@ -243,8 +243,9 @@ func httpBase(ctx *context.Context) *serviceHandler {
}
}
isRequestToConfig := strings.HasSuffix(ctx.Req.URL.Path, "/config")
if !repoExist {
if !receivePack {
if !receivePack && !isRequestToConfig {
ctx.PlainText(http.StatusNotFound, "Repository not found")
return nil
}
@ -264,7 +265,7 @@ func httpBase(ctx *context.Context) *serviceHandler {
}
// Return dummy payload if GET receive-pack
if ctx.Req.Method == http.MethodGet {
if ctx.Req.Method == http.MethodGet && !isRequestToConfig {
dummyInfoRefs(ctx)
return nil
}
@ -551,6 +552,21 @@ func GetConfig(ctx *context.Context) {
h := httpBase(ctx)
if h != nil {
setHeaderNoCache(ctx)
if setting.Annex.Enabled && strings.HasPrefix(ctx.Req.UserAgent(), "git-annex/") {
p, err := access_model.GetUserRepoPermission(ctx, h.repo, ctx.Doer)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return
}
if p.CanAccess(perm.AccessModeWrite, unit.TypeCode) {
_, _, err := git.NewCommand(ctx, "annex", "init").RunStdString(&git.RunOpts{Dir: h.getRepoDir()})
if err != nil {
ctx.Resp.WriteHeader(http.StatusInternalServerError)
return
}
}
}
config, err := os.ReadFile(filepath.Join(h.getRepoDir(), "config"))
if err != nil {
log.Error("Failed to read git config file: %v", err)