remove gogit (#887)

This commit is contained in:
Marko Gacesa 2023-12-11 10:15:15 +00:00 committed by Harness
parent 4d550a78bd
commit a7f11126fa
17 changed files with 265 additions and 337 deletions

View File

@ -47,7 +47,7 @@ func (c *Controller) CodeOwners(
}
ownerEvaluation, err := c.codeOwners.Evaluate(ctx, repo, pr, reviewers)
if errors.Is(codeowners.ErrNotFound, err) {
if errors.Is(err, codeowners.ErrNotFound) {
return types.CodeOwnerEvaluation{}, usererror.ErrNotFound
}
if codeowners.IsTooLargeError(err) {

View File

@ -26,6 +26,8 @@ import (
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
const (
@ -186,6 +188,12 @@ func (c *Controller) getFileContent(ctx context.Context,
return nil, fmt.Errorf("failed to get file content: %w", err)
}
defer func() {
if err := output.Content.Close(); err != nil {
log.Ctx(ctx).Warn().Err(err).Msgf("failed to close blob content reader.")
}
}()
content, err := io.ReadAll(output.Content)
if err != nil {
return nil, fmt.Errorf("failed to read blob content: %w", err)
@ -213,6 +221,12 @@ func (c *Controller) getSymlinkContent(ctx context.Context,
return nil, fmt.Errorf("failed to get symlink: %w", err)
}
defer func() {
if err := output.Content.Close(); err != nil {
log.Ctx(ctx).Warn().Err(err).Msgf("failed to close blob content reader.")
}
}()
content, err := io.ReadAll(output.Content)
if err != nil {
return nil, fmt.Errorf("failed to read blob content: %w", err)

View File

@ -32,7 +32,7 @@ func (c *Controller) Raw(ctx context.Context,
repoRef string,
gitRef string,
repoPath string,
) (io.Reader, int64, error) {
) (io.ReadCloser, int64, error) {
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
if err != nil {
return nil, 0, err

View File

@ -21,6 +21,8 @@ import (
"github.com/harness/gitness/app/api/controller/repo"
"github.com/harness/gitness/app/api/render"
"github.com/harness/gitness/app/api/request"
"github.com/rs/zerolog/log"
)
// HandleRaw returns the raw content of a file.
@ -45,6 +47,12 @@ func HandleRaw(repoCtrl *repo.Controller) http.HandlerFunc {
return
}
defer func() {
if err := dataReader.Close(); err != nil {
log.Ctx(ctx).Warn().Err(err).Msgf("failed to close blob content reader.")
}
}()
w.Header().Add("Content-Length", fmt.Sprint(dataLength))
render.Reader(ctx, w, http.StatusOK, dataReader)

View File

@ -21,6 +21,8 @@ import (
"github.com/harness/gitness/git"
"github.com/harness/gitness/types"
"github.com/rs/zerolog/log"
)
type service struct {
@ -63,6 +65,12 @@ func (f *service) Get(
return nil, fmt.Errorf("failed to read blob: %w", err)
}
defer func() {
if err := blobReader.Content.Close(); err != nil {
log.Ctx(ctx).Warn().Err(err).Msgf("failed to close blob content reader.")
}
}()
buf, err := io.ReadAll(blobReader.Content)
if err != nil {
return nil, fmt.Errorf("could not read blob content from file: %w", err)

View File

@ -223,6 +223,12 @@ func (s *Service) getCodeOwnerFile(
return nil, fmt.Errorf("failed to get file content: %w", err)
}
defer func() {
if err := output.Content.Close(); err != nil {
log.Ctx(ctx).Warn().Err(err).Msgf("failed to close blob content reader.")
}
}()
content, err := io.ReadAll(output.Content)
if err != nil {
return nil, fmt.Errorf("failed to read blob content: %w", err)

View File

@ -127,7 +127,6 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
return nil, err
}
typesConfig := server.ProvideGitConfig(config)
goGitRepoProvider := adapter.ProvideGoGitRepoProvider()
universalClient, err := server.ProvideRedis(config)
if err != nil {
return nil, err
@ -136,7 +135,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
if err != nil {
return nil, err
}
gitAdapter, err := git.ProvideGITAdapter(typesConfig, goGitRepoProvider, cacheCache)
gitAdapter, err := git.ProvideGITAdapter(typesConfig, cacheCache)
if err != nil {
return nil, err
}

View File

@ -26,13 +26,11 @@ import (
type Adapter struct {
traceGit bool
repoProvider *GoGitRepoProvider
lastCommitCache cache.Cache[CommitEntryKey, *types.Commit]
}
func New(
config types.Config,
repoProvider *GoGitRepoProvider,
lastCommitCache cache.Cache[CommitEntryKey, *types.Commit],
) (Adapter, error) {
// TODO: should be subdir of gitRoot? What is it being used for?
@ -45,7 +43,6 @@ func New(
return Adapter{
traceGit: config.Trace,
repoProvider: repoProvider,
lastCommitCache: lastCommitCache,
}, nil
}

View File

@ -16,12 +16,13 @@ package adapter
import (
"context"
"fmt"
"io"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git/types"
gogitplumbing "github.com/go-git/go-git/v5/plumbing"
"code.gitea.io/gitea/modules/git"
)
// GetBlob returns the blob for the given object sha.
@ -31,58 +32,60 @@ func (a Adapter) GetBlob(
sha string,
sizeLimit int64,
) (*types.BlobReader, error) {
if repoPath == "" {
return nil, ErrRepositoryPathEmpty
}
repo, err := a.repoProvider.Get(ctx, repoPath)
stdIn, stdOut, cancel := git.CatFileBatch(ctx, repoPath)
_, err := stdIn.Write([]byte(sha + "\n"))
if err != nil {
return nil, errors.Internal("failed to open repository", err)
cancel()
return nil, fmt.Errorf("failed to write blob sha to git stdin: %w", err)
}
blob, err := repo.BlobObject(gogitplumbing.NewHash(sha))
objectSHA, objectType, objectSize, err := git.ReadBatchLine(stdOut)
if err != nil {
if errors.Is(err, gogitplumbing.ErrObjectNotFound) {
return nil, errors.NotFound("blob sha %s not found", sha)
}
return nil, errors.Internal("failed to get blob object for sha '%s'", sha, err)
cancel()
return nil, processGiteaErrorf(err, "failed to read cat-file batch line")
}
if string(objectSHA) != sha {
cancel()
return nil, fmt.Errorf("cat-file returned object sha '%s' but expected '%s'", objectSHA, sha)
}
if objectType != string(git.ObjectBlob) {
cancel()
return nil, errors.InvalidArgument(
"cat-file returned object type '%s' but expected '%s'", objectType, git.ObjectBlob)
}
objectSize := blob.Size
contentSize := objectSize
if sizeLimit > 0 && contentSize > sizeLimit {
if sizeLimit > 0 && sizeLimit < contentSize {
contentSize = sizeLimit
}
reader, err := blob.Reader()
if err != nil {
return nil, errors.Internal("failed to open blob object for sha '%s'", sha, err)
}
return &types.BlobReader{
SHA: sha,
Size: objectSize,
ContentSize: contentSize,
Content: LimitReadCloser(reader, contentSize),
Content: newLimitReaderCloser(stdOut, contentSize, cancel),
}, nil
}
func LimitReadCloser(r io.ReadCloser, n int64) io.ReadCloser {
return limitReadCloser{
r: io.LimitReader(r, n),
c: r,
func newLimitReaderCloser(reader io.Reader, limit int64, stop func()) limitReaderCloser {
return limitReaderCloser{
reader: io.LimitReader(reader, limit),
stop: stop,
}
}
// limitReadCloser implements io.ReadCloser interface.
type limitReadCloser struct {
r io.Reader
c io.Closer
type limitReaderCloser struct {
reader io.Reader
stop func()
}
func (l limitReadCloser) Read(p []byte) (n int, err error) {
return l.r.Read(p)
func (l limitReaderCloser) Read(p []byte) (n int, err error) {
return l.reader.Read(p)
}
func (l limitReadCloser) Close() error {
return l.c.Close()
func (l limitReaderCloser) Close() error {
l.stop()
return nil
}

View File

@ -1,132 +0,0 @@
// 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 adapter
import (
"context"
"fmt"
"os"
"time"
"github.com/harness/gitness/cache"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git/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 (a Adapter) getGoGitCommit(
ctx context.Context,
repoPath string,
rev string,
) (*gogit.Repository, *gogitobject.Commit, error) {
if repoPath == "" {
return nil, nil, ErrRepositoryPathEmpty
}
repo, err := a.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, errors.Internal("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, errors.NotFound("reference not found '%s'", rev)
} else if err != nil {
return nil, nil, errors.Internal("failed to resolve revision '%s'", 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
}

View File

@ -82,24 +82,6 @@ func mapGiteaCommit(giteaCommit *gitea.Commit) (*types.Commit, error) {
}, nil
}
func mapGiteaNodeToTreeNodeModeAndType(giteaMode gitea.EntryMode) (types.TreeNodeType, types.TreeNodeMode, error) {
switch giteaMode {
case gitea.EntryModeBlob:
return types.TreeNodeTypeBlob, types.TreeNodeModeFile, nil
case gitea.EntryModeSymlink:
return types.TreeNodeTypeBlob, types.TreeNodeModeSymlink, nil
case gitea.EntryModeExec:
return types.TreeNodeTypeBlob, types.TreeNodeModeExec, nil
case gitea.EntryModeCommit:
return types.TreeNodeTypeCommit, types.TreeNodeModeCommit, nil
case gitea.EntryModeTree:
return types.TreeNodeTypeTree, types.TreeNodeModeTree, nil
default:
return types.TreeNodeTypeBlob, types.TreeNodeModeFile,
fmt.Errorf("received unknown tree node mode from gitea: '%s'", giteaMode.String())
}
}
func mapGiteaSignature(
giteaSignature *gitea.Signature,
) (types.Signature, error) {

View File

@ -16,93 +16,86 @@ package adapter
import (
"context"
"errors"
"fmt"
"io"
"path"
"github.com/harness/gitness/git/types"
gogitobject "github.com/go-git/go-git/v5/plumbing/object"
gitea "code.gitea.io/gitea/modules/git"
)
// nolint:gocognit
//nolint:gocognit
func (a Adapter) MatchFiles(
ctx context.Context,
repoPath string,
ref string,
dirPath string,
rev string,
treePath string,
pattern string,
maxSize int,
) ([]types.FileContent, error) {
if repoPath == "" {
return nil, ErrRepositoryPathEmpty
}
_, refCommit, err := a.getGoGitCommit(ctx, repoPath, ref)
nodes, err := lsDirectory(ctx, repoPath, rev, treePath)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to list files in match files: %w", err)
}
tree, err := refCommit.Tree()
if err != nil {
return nil, fmt.Errorf("failed to get tree for the commit: %w", err)
}
if dirPath != "" {
tree, err = tree.Tree(dirPath)
if errors.Is(err, gogitobject.ErrDirectoryNotFound) {
return nil, &types.PathNotFoundError{Path: dirPath}
}
if err != nil {
return nil, fmt.Errorf("failed to navigate to %s directory: %w", dirPath, err)
}
}
catFileWriter, catFileReader, catFileStop := gitea.CatFileBatch(ctx, repoPath)
defer catFileStop()
var files []types.FileContent
for i := range tree.Entries {
fileEntry := tree.Entries[i]
ok, err := path.Match(pattern, fileEntry.Name)
for i := range nodes {
if nodes[i].NodeType != types.TreeNodeTypeBlob {
continue
}
fileName := nodes[i].Name
ok, err := path.Match(pattern, fileName)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to match file name against pattern: %w", err)
}
if !ok {
continue
}
name := fileEntry.Name
f, err := tree.TreeEntryFile(&fileEntry)
_, err = catFileWriter.Write([]byte(nodes[i].Sha + "\n"))
if err != nil {
return nil, fmt.Errorf("failed to get tree entry file %s: %w", name, err)
return nil, fmt.Errorf("failed to ask for file content from cat file batch: %w", err)
}
reader, err := f.Reader()
_, _, size, err := gitea.ReadBatchLine(catFileReader)
if err != nil {
return nil, fmt.Errorf("failed to open tree entry file %s: %w", name, err)
return nil, fmt.Errorf("failed to read cat-file batch header: %w", err)
}
filePath := path.Join(dirPath, name)
reader := io.LimitReader(catFileReader, size+1) // plus eol
content, err := func(r io.ReadCloser) ([]byte, error) {
defer func() {
_ = r.Close()
}()
return io.ReadAll(io.LimitReader(reader, int64(maxSize)))
}(reader)
if err != nil {
return nil, fmt.Errorf("failed to read file content %s: %w", name, err)
if size > int64(maxSize) {
_, err = io.Copy(io.Discard, reader)
if err != nil {
return nil, fmt.Errorf("failed to discard a large file: %w", err)
}
}
if len(content) == maxSize {
// skip truncated files
data, err := io.ReadAll(reader)
if err != nil {
return nil, fmt.Errorf("failed to read cat-file content: %w", err)
}
if len(data) > 0 {
data = data[:len(data)-1]
}
if len(data) == 0 {
continue
}
files = append(files, types.FileContent{
Path: filePath,
Content: content,
Path: nodes[i].Path,
Content: data,
})
}
_ = catFileWriter.Close()
return files, nil
}

View File

@ -44,10 +44,8 @@ var (
func setupGit(t *testing.T) adapter.Adapter {
t.Helper()
gogitProvider := adapter.ProvideGoGitRepoProvider()
git, err := adapter.New(
types.Config{Trace: true},
gogitProvider,
adapter.NewInMemoryLastCommitCache(5*time.Minute),
)
if err != nil {

View File

@ -15,14 +15,16 @@
package adapter
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"path"
"path/filepath"
"regexp"
"strings"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git/types"
gitea "code.gitea.io/gitea/modules/git"
@ -32,108 +34,173 @@ func cleanTreePath(treePath string) string {
return strings.Trim(path.Clean("/"+treePath), "/")
}
// GetTreeNode returns the tree node at the given path as found for the provided reference.
// Note: ref can be Branch / Tag / CommitSHA.
func (a Adapter) GetTreeNode(
ctx context.Context,
repoPath string,
ref string,
treePath string,
) (*types.TreeNode, error) {
treePath = cleanTreePath(treePath)
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
if err != nil {
return nil, processGiteaErrorf(err, "failed to open repository")
func parseTreeNodeMode(s string) (types.TreeNodeType, types.TreeNodeMode, error) {
switch s {
case "100644":
return types.TreeNodeTypeBlob, types.TreeNodeModeFile, nil
case "120000":
return types.TreeNodeTypeBlob, types.TreeNodeModeSymlink, nil
case "100775":
return types.TreeNodeTypeBlob, types.TreeNodeModeExec, nil
case "160000":
return types.TreeNodeTypeCommit, types.TreeNodeModeCommit, nil
case "040000":
return types.TreeNodeTypeTree, types.TreeNodeModeTree, nil
default:
return types.TreeNodeTypeBlob, types.TreeNodeModeFile,
fmt.Errorf("unknown git tree node mode: '%s'", s)
}
defer giteaRepo.Close()
// Get the giteaCommit object for the ref
giteaCommit, err := giteaRepo.GetCommit(ref)
if err != nil {
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
}
// TODO: handle ErrNotExist :)
giteaTreeEntry, err := giteaCommit.GetTreeEntryByPath(treePath)
if err != nil {
return nil, processGiteaErrorf(err, "failed to get tree entry for commit '%s' at path '%s'",
giteaCommit.ID.String(), treePath)
}
nodeType, mode, err := mapGiteaNodeToTreeNodeModeAndType(giteaTreeEntry.Mode())
if err != nil {
return nil, err
}
return &types.TreeNode{
Mode: mode,
NodeType: nodeType,
Sha: giteaTreeEntry.ID.String(),
Name: giteaTreeEntry.Name(),
Path: treePath,
}, nil
}
// ListTreeNodes lists the child nodes of a tree reachable from ref via the specified path
// and includes the latest commit for all nodes if requested.
// Note: ref can be Branch / Tag / CommitSHA.
func (a Adapter) ListTreeNodes(
func scanZeroSeparated(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil // Return nothing if at end of file and no data passed
}
if i := strings.IndexByte(string(data), 0); i >= 0 {
return i + 1, data[0:i], nil // Split at zero byte
}
if atEOF {
return len(data), data, nil // at the end of file return the data
}
return
}
var regexpLsTreeLongColumns = regexp.MustCompile(`^(\d{6})\s+(\w+)\s+(\w+)\t(.+)$`)
func lsTree(
ctx context.Context,
repoPath string,
ref string,
rev string,
treePath string,
) ([]types.TreeNode, error) {
if repoPath == "" {
return nil, ErrRepositoryPathEmpty
}
args := []string{"ls-tree", "-z", rev, treePath}
output, stderr, err := gitea.NewCommand(ctx, args...).RunStdString(&gitea.RunOpts{Dir: repoPath})
if strings.Contains(stderr, "fatal: Not a valid object name") {
return nil, errors.InvalidArgument("revision %q not found", rev)
}
if err != nil {
return nil, fmt.Errorf("failed to run git ls-tree: %w", err)
}
if output == "" {
return nil, errors.Format(errors.StatusPathNotFound, "path %q not found", treePath)
}
n := strings.Count(output, "\x00")
list := make([]types.TreeNode, 0, n)
scan := bufio.NewScanner(strings.NewReader(output))
scan.Split(scanZeroSeparated)
for scan.Scan() {
columns := regexpLsTreeLongColumns.FindStringSubmatch(scan.Text())
if columns == nil {
return nil, errors.New("unrecognized format of git directory listing")
}
nodeType, nodeMode, err := parseTreeNodeMode(columns[1])
if err != nil {
return nil, fmt.Errorf("failed to parse git mode: %w", err)
}
nodeSha := columns[3]
nodePath := columns[4]
nodeName := path.Base(nodePath)
list = append(list, types.TreeNode{
NodeType: nodeType,
Mode: nodeMode,
Sha: nodeSha,
Name: nodeName,
Path: nodePath,
})
}
return list, nil
}
// lsFile returns all tree node entries in the requested directory.
func lsDirectory(
ctx context.Context,
repoPath string,
rev string,
treePath string,
) ([]types.TreeNode, error) {
treePath = path.Clean(treePath)
if treePath == "" {
treePath = "."
} else {
treePath += "/"
}
return lsTree(ctx, repoPath, rev, treePath)
}
// lsFile returns one tree node entry.
func lsFile(
ctx context.Context,
repoPath string,
rev string,
treePath string,
) (types.TreeNode, error) {
treePath = cleanTreePath(treePath)
giteaRepo, err := gitea.OpenRepository(ctx, repoPath)
list, err := lsTree(ctx, repoPath, rev, treePath)
if err != nil {
return nil, processGiteaErrorf(err, "failed to open repository")
return types.TreeNode{}, fmt.Errorf("failed to ls file: %w", err)
}
defer giteaRepo.Close()
// Get the giteaCommit object for the ref
giteaCommit, err := giteaRepo.GetCommit(ref)
if err != nil {
return nil, processGiteaErrorf(err, "error getting commit for ref '%s'", ref)
if len(list) != 1 {
return types.TreeNode{}, fmt.Errorf("ls file list contains more than one element, len=%d", len(list))
}
// Get the giteaTree object for the ref
giteaTree, err := giteaCommit.SubTree(treePath)
if err != nil {
return nil, processGiteaErrorf(err, "error getting tree for '%s'", treePath)
}
return list[0], nil
}
giteaEntries, err := giteaTree.ListEntries()
if err != nil {
return nil, processGiteaErrorf(err, "failed to list entries for tree '%s'", treePath)
}
// GetTreeNode returns the tree node at the given path as found for the provided reference.
func (a Adapter) GetTreeNode(ctx context.Context, repoPath, rev, treePath string) (*types.TreeNode, error) {
// root path (empty path) is a special case
if treePath == "" {
if repoPath == "" {
return nil, ErrRepositoryPathEmpty
}
nodes := make([]types.TreeNode, len(giteaEntries))
for i := range giteaEntries {
giteaEntry := giteaEntries[i]
var nodeType types.TreeNodeType
var mode types.TreeNodeMode
nodeType, mode, err = mapGiteaNodeToTreeNodeModeAndType(giteaEntry.Mode())
args := []string{"show", "--no-patch", "--format=" + fmtTreeHash, rev}
treeSHA, stderr, err := gitea.NewCommand(ctx, args...).RunStdString(&gitea.RunOpts{Dir: repoPath})
if strings.Contains(stderr, "ambiguous argument") {
return nil, errors.InvalidArgument("could not resolve git revision: %s", rev)
}
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get root tree node: %w", err)
}
// giteaNode.Name() returns the path of the node relative to the tree.
relPath := giteaEntry.Name()
name := filepath.Base(relPath)
nodes[i] = types.TreeNode{
NodeType: nodeType,
Mode: mode,
Sha: giteaEntry.ID.String(),
Name: name,
Path: filepath.Join(treePath, relPath),
}
return &types.TreeNode{
NodeType: types.TreeNodeTypeTree,
Mode: types.TreeNodeModeTree,
Sha: treeSHA,
Name: "",
Path: "",
}, err
}
return nodes, nil
treeNode, err := lsFile(ctx, repoPath, rev, treePath)
if err != nil {
return nil, fmt.Errorf("failed to get tree node: %w", err)
}
return &treeNode, nil
}
// ListTreeNodes lists the child nodes of a tree reachable from ref via the specified path.
func (a Adapter) ListTreeNodes(ctx context.Context, repoPath, rev, treePath string) ([]types.TreeNode, error) {
list, err := lsDirectory(ctx, repoPath, rev, treePath)
if err != nil {
return nil, fmt.Errorf("failed to list tree nodes: %w", err)
}
return list, nil
}
func (a Adapter) ReadTree(

View File

@ -27,15 +27,9 @@ import (
)
var WireSet = wire.NewSet(
ProvideGoGitRepoProvider,
ProvideLastCommitCache,
)
func ProvideGoGitRepoProvider() *GoGitRepoProvider {
const objectCacheSize = 16 << 20 // 16MiB
return NewGoGitRepoProvider(objectCacheSize, 15*time.Minute)
}
func ProvideLastCommitCache(
config types.Config,
redisClient redis.UniversalClient,

View File

@ -17,8 +17,6 @@ package git
import (
"context"
"io"
"github.com/rs/zerolog/log"
)
type GetBlobParams struct {
@ -34,7 +32,7 @@ type GetBlobOutput struct {
// ContentSize is the total number of bytes returned by the Content Reader.
ContentSize int64
// Content contains the (partial) content of the blob.
Content io.Reader
Content io.ReadCloser
}
func (s *Service) GetBlob(ctx context.Context, params *GetBlobParams) (*GetBlobOutput, error) {
@ -49,12 +47,6 @@ func (s *Service) GetBlob(ctx context.Context, params *GetBlobParams) (*GetBlobO
if err != nil {
return nil, err
}
defer func() {
dErr := reader.Content.Close()
if dErr != nil {
log.Ctx(ctx).Warn().Err(err).Msgf("failed to close blob content reader.")
}
}()
return &GetBlobOutput{
SHA: reader.SHA,

View File

@ -31,10 +31,9 @@ var WireSet = wire.NewSet(
func ProvideGITAdapter(
config types.Config,
repoProvider *adapter.GoGitRepoProvider,
lastCommitCache cache.Cache[adapter.CommitEntryKey, *types.Commit],
) (Adapter, error) {
return adapter.New(config, repoProvider, lastCommitCache)
return adapter.New(config, lastCommitCache)
}
func ProvideService(config types.Config, adapter Adapter, storage storage.Store) (Interface, error) {