mirror of
https://github.com/harness/drone.git
synced 2025-05-12 23:20:10 +08:00
use gogit for get blob implementation
This commit is contained in:
parent
548f446575
commit
acf4a68a4f
@ -5,89 +5,66 @@
|
|||||||
package gitea
|
package gitea
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/harness/gitness/gitrpc/internal/types"
|
"github.com/harness/gitness/gitrpc/internal/types"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
gogitplumbing "github.com/go-git/go-git/v5/plumbing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetBlob returns the blob for the given object sha.
|
// GetBlob returns the blob for the given object sha.
|
||||||
func (g Adapter) GetBlob(ctx context.Context, repoPath string, sha string, sizeLimit int64) (*types.BlobReader, error) {
|
func (g Adapter) GetBlob(ctx context.Context, repoPath string, sha string, sizeLimit int64) (*types.BlobReader, error) {
|
||||||
// Note: We are avoiding gitea blob implementation, as that is tied to the lifetime of the repository object.
|
repo, err := g.repoProvider.Get(ctx, repoPath)
|
||||||
// Instead, we just use the gitea helper methods ourselves.
|
|
||||||
stdIn, stdOut, cancel := git.CatFileBatch(ctx, repoPath)
|
|
||||||
|
|
||||||
_, err := stdIn.Write([]byte(sha + "\n"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
return nil, fmt.Errorf("failed to open repository: %w", err)
|
||||||
return nil, fmt.Errorf("failed to write blob sha to git stdin: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
objectSHA, objectType, objectSize, err := git.ReadBatchLine(stdOut)
|
blob, err := repo.BlobObject(gogitplumbing.NewHash(sha))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
if err == gogitplumbing.ErrObjectNotFound {
|
||||||
return nil, processGiteaErrorf(err, "failed to read cat-file batch line")
|
return nil, types.ErrNotFound
|
||||||
}
|
}
|
||||||
|
return nil, fmt.Errorf("failed to get blob object: %w", err)
|
||||||
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, fmt.Errorf("cat-file returned object type '%s' but expected '%s'", objectType, git.ObjectBlob)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
objectSize := blob.Size
|
||||||
contentSize := objectSize
|
contentSize := objectSize
|
||||||
if sizeLimit > 0 && sizeLimit < contentSize {
|
if sizeLimit > 0 && contentSize > sizeLimit {
|
||||||
contentSize = sizeLimit
|
contentSize = sizeLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader, err := blob.Reader()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to open blob object: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &types.BlobReader{
|
return &types.BlobReader{
|
||||||
SHA: sha,
|
SHA: sha,
|
||||||
Size: objectSize,
|
Size: objectSize,
|
||||||
ContentSize: contentSize,
|
ContentSize: contentSize,
|
||||||
Content: &exactLimitReader{
|
Content: LimitReadCloser(reader, contentSize),
|
||||||
reader: stdOut,
|
|
||||||
remainingBytes: contentSize,
|
|
||||||
close: func() error {
|
|
||||||
// TODO: is there a better (but short) way to clear the buffer?
|
|
||||||
// gitea is .Discard()'ing elements here until it's empty.
|
|
||||||
stdOut.Reset(bytes.NewBuffer([]byte{}))
|
|
||||||
cancel()
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactLimitReader reads the content of a reader and ensures no more than the specified bytes will be requested from
|
func LimitReadCloser(r io.ReadCloser, n int64) io.ReadCloser {
|
||||||
// the underlaying reader. This is required for readers that don't ensure completion after reading all remaining bytes.
|
return limitReadCloser{
|
||||||
// io.LimitReader doesn't work as it waits for bytes that never come, io.SectionReader would requrie an io.ReaderAt.
|
r: io.LimitReader(r, n),
|
||||||
type exactLimitReader struct {
|
c: r,
|
||||||
reader io.Reader
|
|
||||||
remainingBytes int64
|
|
||||||
close func() error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *exactLimitReader) Read(p []byte) (int, error) {
|
|
||||||
if r.remainingBytes <= 0 {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if int64(len(p)) > r.remainingBytes {
|
|
||||||
p = p[0:r.remainingBytes]
|
|
||||||
}
|
|
||||||
n, err := r.reader.Read(p)
|
|
||||||
r.remainingBytes -= int64(n)
|
|
||||||
|
|
||||||
return n, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *exactLimitReader) Close() error {
|
// limitReadCloser implements io.ReadCloser interface.
|
||||||
return r.close()
|
type limitReadCloser struct {
|
||||||
|
r io.Reader
|
||||||
|
c io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l limitReadCloser) Read(p []byte) (n int, err error) {
|
||||||
|
return l.r.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l limitReadCloser) Close() error {
|
||||||
|
return l.c.Close()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user