// Copyright 2023 Harness, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gitea import ( "context" "errors" "fmt" "os" "time" "github.com/harness/gitness/cache" "github.com/harness/gitness/gitrpc/internal/types" gogitosfs "github.com/go-git/go-billy/v5/osfs" gogit "github.com/go-git/go-git/v5" gogitplumbing "github.com/go-git/go-git/v5/plumbing" gogitcache "github.com/go-git/go-git/v5/plumbing/cache" gogitobject "github.com/go-git/go-git/v5/plumbing/object" gogitfilesystem "github.com/go-git/go-git/v5/storage/filesystem" ) type GoGitRepoProvider struct { gitObjectCache cache.Cache[string, *gogitcache.ObjectLRU] } func NewGoGitRepoProvider(objectCacheMax int, cacheDuration time.Duration) *GoGitRepoProvider { c := cache.New[string, *gogitcache.ObjectLRU](gitObjectCacheGetter{ maxSize: objectCacheMax, }, cacheDuration) return &GoGitRepoProvider{ gitObjectCache: c, } } func (gr *GoGitRepoProvider) Get(ctx context.Context, path string) (*gogit.Repository, error) { fs := gogitosfs.New(path) stat, err := fs.Stat("") if err != nil { if os.IsNotExist(err) { return nil, types.ErrRepositoryNotFound } return nil, fmt.Errorf("failed to check repository existence: %w", err) } if !stat.IsDir() { return nil, types.ErrRepositoryCorrupted } gitObjectCache, err := gr.gitObjectCache.Get(ctx, path) if err != nil { return nil, fmt.Errorf("failed to get repository cache: %w", err) } s := gogitfilesystem.NewStorage(fs, gitObjectCache) repo, err := gogit.Open(s, nil) if err != nil { return nil, err } return repo, nil } type gitObjectCacheGetter struct { maxSize int } func (r gitObjectCacheGetter) Find(_ context.Context, _ string) (*gogitcache.ObjectLRU, error) { return gogitcache.NewObjectLRU(gogitcache.FileSize(r.maxSize)), nil } func (g Adapter) getGoGitCommit(ctx context.Context, repoPath string, rev string, ) (*gogit.Repository, *gogitobject.Commit, error) { repo, err := g.repoProvider.Get(ctx, repoPath) if err != nil { return nil, nil, fmt.Errorf("failed to open repository: %w", err) } var refSHA *gogitplumbing.Hash if rev == "" { var head *gogitplumbing.Reference head, err = repo.Head() if err != nil { return nil, nil, fmt.Errorf("failed to get head: %w", err) } headHash := head.Hash() refSHA = &headHash } else { refSHA, err = repo.ResolveRevision(gogitplumbing.Revision(rev)) if errors.Is(err, gogitplumbing.ErrReferenceNotFound) { return nil, nil, types.ErrNotFound } else if err != nil { return nil, nil, fmt.Errorf("failed to resolve revision %s: %w", rev, err) } } refCommit, err := repo.CommitObject(*refSHA) if err != nil { return nil, nil, fmt.Errorf("failed to load commit data: %w", err) } return repo, refCommit, nil }