|  | 
|  | 1 | +package backend | 
|  | 2 | + | 
|  | 3 | +import ( | 
|  | 4 | +	"fmt" | 
|  | 5 | +	"io" | 
|  | 6 | + | 
|  | 7 | +	"code.gitea.io/gitea/modules/lfs" | 
|  | 8 | +	"code.gitea.io/gitea/modules/lfs_ssh/transfer" | 
|  | 9 | +) | 
|  | 10 | + | 
|  | 11 | +// Version is the git-lfs-transfer protocol version number. | 
|  | 12 | +const Version = "1" | 
|  | 13 | + | 
|  | 14 | +// Capabilities is a list of Git LFS capabilities supported by this package. | 
|  | 15 | +var Capabilities = []string{ | 
|  | 16 | +	"version=" + Version, | 
|  | 17 | +	// "locking", // no support yet in gitea backend | 
|  | 18 | +} | 
|  | 19 | + | 
|  | 20 | +// GiteaBackend is an adapter between git-lfs-transfer library and Gitea's internal LFS API | 
|  | 21 | +type GiteaBackend struct { | 
|  | 22 | +	store *lfs.ContentStore | 
|  | 23 | +} | 
|  | 24 | + | 
|  | 25 | +var _ transfer.Backend = &GiteaBackend{} | 
|  | 26 | + | 
|  | 27 | +// Batch implements transfer.Backend | 
|  | 28 | +func (g *GiteaBackend) Batch(_ string, pointers []transfer.BatchItem, _ transfer.Args) ([]transfer.BatchItem, error) { | 
|  | 29 | +	for i := range pointers { | 
|  | 30 | +		pointers[i].Present = false | 
|  | 31 | +		pointer := lfs.Pointer{Oid: pointers[i].Oid, Size: pointers[i].Size} | 
|  | 32 | +		exists, err := g.store.Verify(pointer) | 
|  | 33 | +		if err == nil && exists { | 
|  | 34 | +			pointers[i].Present = true | 
|  | 35 | +		} | 
|  | 36 | +	} | 
|  | 37 | +	return pointers, nil | 
|  | 38 | +} | 
|  | 39 | + | 
|  | 40 | +// Download implements main.Backend. The returned reader must be closed by the | 
|  | 41 | +// caller. | 
|  | 42 | +func (g *GiteaBackend) Download(oid string, _ transfer.Args) (io.ReadCloser, int64, error) { | 
|  | 43 | +	pointer := lfs.Pointer{Oid: oid} | 
|  | 44 | +	pointer, err := g.store.GetMeta(pointer) | 
|  | 45 | +	if err != nil { | 
|  | 46 | +		return nil, 0, err | 
|  | 47 | +	} | 
|  | 48 | +	obj, err := g.store.Get(pointer) | 
|  | 49 | +	if err != nil { | 
|  | 50 | +		return nil, 0, err | 
|  | 51 | +	} | 
|  | 52 | +	return obj, pointer.Size, nil | 
|  | 53 | +} | 
|  | 54 | + | 
|  | 55 | +// StartUpload implements main.Backend. The returned temp file should be closed. | 
|  | 56 | +func (g *GiteaBackend) Upload(oid string, size int64, r io.Reader, _ transfer.Args) error { | 
|  | 57 | +	if r == nil { | 
|  | 58 | +		return fmt.Errorf("%w: received null data", transfer.ErrMissingData) | 
|  | 59 | +	} | 
|  | 60 | +	pointer := lfs.Pointer{Oid: oid, Size: size} | 
|  | 61 | +	err := g.store.Put(pointer, r) | 
|  | 62 | +	return err | 
|  | 63 | +} | 
|  | 64 | + | 
|  | 65 | +// Verify implements main.Backend. | 
|  | 66 | +func (g *GiteaBackend) Verify(oid string, size int64, args transfer.Args) (transfer.Status, error) { | 
|  | 67 | +	pointer := lfs.Pointer{Oid: oid, Size: size} | 
|  | 68 | +	exists, err := g.store.Exists(pointer) | 
|  | 69 | +	if err != nil { | 
|  | 70 | +		return transfer.NewStatus(transfer.StatusNotFound, err.Error()), err | 
|  | 71 | +	} | 
|  | 72 | +	if !exists { | 
|  | 73 | +		return transfer.NewStatus(transfer.StatusNotFound, "not found"), nil | 
|  | 74 | +	} | 
|  | 75 | +	return transfer.SuccessStatus(), nil | 
|  | 76 | +} | 
|  | 77 | + | 
|  | 78 | +// LockBackend implements main.Backend. | 
|  | 79 | +func (g *GiteaBackend) LockBackend(_ transfer.Args) transfer.LockBackend { | 
|  | 80 | +	// Gitea doesn't support the locking API | 
|  | 81 | +	// this should never be called as we don't advertise the capability | 
|  | 82 | +	return (transfer.LockBackend)(nil) | 
|  | 83 | +} | 
|  | 84 | + | 
|  | 85 | +func New() transfer.Backend { | 
|  | 86 | +	return &GiteaBackend{lfs.NewContentStore()} | 
|  | 87 | +} | 
0 commit comments