Skip to content

Commit fd98c11

Browse files
modules/lfs_ssh: add a backend and runner
1 parent 1568702 commit fd98c11

File tree

3 files changed

+129
-0
lines changed

3 files changed

+129
-0
lines changed

cmd/serv.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"code.gitea.io/gitea/models/perm"
2323
"code.gitea.io/gitea/modules/git"
2424
"code.gitea.io/gitea/modules/json"
25+
"code.gitea.io/gitea/modules/lfs_ssh"
2526
"code.gitea.io/gitea/modules/log"
2627
"code.gitea.io/gitea/modules/pprof"
2728
"code.gitea.io/gitea/modules/private"
@@ -279,6 +280,11 @@ func runServ(c *cli.Context) error {
279280
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
280281
}
281282

283+
// LFS SSH protocol
284+
if verb == verbLfsTransfer {
285+
return lfs_ssh.Main(repoPath, lfsVerb)
286+
}
287+
282288
// LFS token authentication
283289
if verb == verbLfsAuthenticate {
284290
url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))

modules/lfs_ssh/backend/backend.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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+
}

modules/lfs_ssh/main.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package lfs_ssh
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"code.gitea.io/gitea/modules/lfs_ssh/backend"
8+
"code.gitea.io/gitea/modules/lfs_ssh/transfer"
9+
"code.gitea.io/gitea/modules/log"
10+
)
11+
12+
func Main(repo string, verb string) error {
13+
//TODO
14+
var logger transfer.Logger = nil
15+
16+
pktline := transfer.NewPktline(os.Stdin, os.Stdout, logger)
17+
giteaBackend := backend.New()
18+
for _, cap := range backend.Capabilities {
19+
if err := pktline.WritePacketText(cap); err != nil {
20+
log.Error("error sending capability [%v] due to error: %v", cap, err)
21+
}
22+
}
23+
if err := pktline.WriteFlush(); err != nil {
24+
log.Error("error flushing capabilities: %v", err)
25+
}
26+
p := transfer.NewProcessor(pktline, giteaBackend, logger)
27+
defer log.Info("done processing commands")
28+
switch verb {
29+
case "upload":
30+
return p.ProcessCommands(transfer.UploadOperation)
31+
case "download":
32+
return p.ProcessCommands(transfer.DownloadOperation)
33+
default:
34+
return fmt.Errorf("unknown operation %q", verb)
35+
}
36+
}

0 commit comments

Comments
 (0)