Skip to content

Commit 61599e8

Browse files
committed
Fix circular dependencies
1 parent cd1dfbb commit 61599e8

File tree

11 files changed

+141
-113
lines changed

11 files changed

+141
-113
lines changed

models/lfs.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ import (
1111
"fmt"
1212
"io"
1313
"path"
14+
"time"
15+
"strings"
16+
"strconv"
1417

1518
"code.gitea.io/gitea/modules/timeutil"
19+
"code.gitea.io/gitea/modules/setting"
20+
"code.gitea.io/gitea/modules/storage"
1621

1722
"xorm.io/builder"
1823
)
@@ -33,6 +38,38 @@ type LFSMetaObjectBasic struct {
3338
Size int64 `xorm:"NOT NULL"`
3439
}
3540

41+
// IsPointerFile will return a partially filled LFSMetaObject if the provided byte slice is a pointer file
42+
func IsPointerFile(buf *[]byte) *LFSMetaObject {
43+
if !setting.LFS.StartServer {
44+
return nil
45+
}
46+
47+
headString := string(*buf)
48+
if !strings.HasPrefix(headString, LFSMetaFileIdentifier) {
49+
return nil
50+
}
51+
52+
splitLines := strings.Split(headString, "\n")
53+
if len(splitLines) < 3 {
54+
return nil
55+
}
56+
57+
oid := strings.TrimPrefix(splitLines[1], LFSMetaFileOidPrefix)
58+
size, err := strconv.ParseInt(strings.TrimPrefix(splitLines[2], "size "), 10, 64)
59+
if len(oid) != 64 || err != nil {
60+
return nil
61+
}
62+
63+
contentStore := &ContentStore{ObjectStorage: storage.LFS}
64+
meta := &LFSMetaObject{Oid: oid, Size: size}
65+
exist, err := contentStore.Exists(meta)
66+
if err != nil || !exist {
67+
return nil
68+
}
69+
70+
return meta
71+
}
72+
3673
// RelativePath returns the relative path of the lfs object
3774
func (m *LFSMetaObject) RelativePath() string {
3875
if len(m.Oid) < 5 {
@@ -240,3 +277,31 @@ func IterateLFS(f func(mo *LFSMetaObject) error) error {
240277
}
241278
}
242279
}
280+
281+
// BatchResponse contains multiple object metadata Representation structures
282+
// for use with the batch API.
283+
type BatchResponse struct {
284+
Transfer string `json:"transfer,omitempty"`
285+
Objects []*Representation `json:"objects"`
286+
}
287+
288+
// Representation is object metadata as seen by clients of the lfs server.
289+
type Representation struct {
290+
Oid string `json:"oid"`
291+
Size int64 `json:"size"`
292+
Actions map[string]*Link `json:"actions"`
293+
Error *ObjectError `json:"error,omitempty"`
294+
}
295+
296+
// ObjectError defines the JSON structure returned to the client in case of an error
297+
type ObjectError struct {
298+
Code int `json:"code"`
299+
Message string `json:"message"`
300+
}
301+
302+
// Link provides a structure used to build a hypermedia representation of an HTTP link.
303+
type Link struct {
304+
Href string `json:"href"`
305+
Header map[string]string `json:"header,omitempty"`
306+
ExpiresAt time.Time `json:"expires_at,omitempty"`
307+
}

modules/lfs/content_store.go renamed to models/lfs_content_store.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a MIT-style
33
// license that can be found in the LICENSE file.
44

5-
package lfs
5+
package models
66

77
import (
88
"crypto/sha256"
@@ -12,7 +12,6 @@ import (
1212
"io"
1313
"os"
1414

15-
"code.gitea.io/gitea/models"
1615
"code.gitea.io/gitea/modules/log"
1716
"code.gitea.io/gitea/modules/storage"
1817
)
@@ -44,7 +43,7 @@ type ContentStore struct {
4443

4544
// Get takes a Meta object and retrieves the content from the store, returning
4645
// it as an io.Reader. If fromByte > 0, the reader starts from that byte
47-
func (s *ContentStore) Get(meta *models.LFSMetaObject, fromByte int64) (io.ReadCloser, error) {
46+
func (s *ContentStore) Get(meta *LFSMetaObject, fromByte int64) (io.ReadCloser, error) {
4847
f, err := s.Open(meta.RelativePath())
4948
if err != nil {
5049
log.Error("Whilst trying to read LFS OID[%s]: Unable to open Error: %v", meta.Oid, err)
@@ -65,7 +64,7 @@ func (s *ContentStore) Get(meta *models.LFSMetaObject, fromByte int64) (io.ReadC
6564
}
6665

6766
// Put takes a Meta object and an io.Reader and writes the content to the store.
68-
func (s *ContentStore) Put(meta *models.LFSMetaObject, r io.Reader) error {
67+
func (s *ContentStore) Put(meta *LFSMetaObject, r io.Reader) error {
6968
hash := sha256.New()
7069
rd := io.TeeReader(r, hash)
7170
p := meta.RelativePath()
@@ -94,7 +93,7 @@ func (s *ContentStore) Put(meta *models.LFSMetaObject, r io.Reader) error {
9493
}
9594

9695
// Exists returns true if the object exists in the content store.
97-
func (s *ContentStore) Exists(meta *models.LFSMetaObject) (bool, error) {
96+
func (s *ContentStore) Exists(meta *LFSMetaObject) (bool, error) {
9897
_, err := s.ObjectStorage.Stat(meta.RelativePath())
9998
if err != nil {
10099
if os.IsNotExist(err) {
@@ -106,7 +105,7 @@ func (s *ContentStore) Exists(meta *models.LFSMetaObject) (bool, error) {
106105
}
107106

108107
// Verify returns true if the object exists in the content store and size is correct.
109-
func (s *ContentStore) Verify(meta *models.LFSMetaObject) (bool, error) {
108+
func (s *ContentStore) Verify(meta *LFSMetaObject) (bool, error) {
110109
p := meta.RelativePath()
111110
fi, err := s.ObjectStorage.Stat(p)
112111
if os.IsNotExist(err) || (err == nil && fi.Size() != meta.Size) {

modules/git/blob.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ func (b *Blob) GetBlobContent() (string, error) {
3232
return string(buf), nil
3333
}
3434

35+
// GetBlobFirstBytes gets limited content of the blob as bytes
36+
func (b *Blob) GetBlobFirstBytes(limit int) ([]byte, error) {
37+
dataRc, err := b.DataAsync()
38+
buf := make([]byte, limit)
39+
if err != nil {
40+
return buf, err
41+
}
42+
defer dataRc.Close()
43+
n, _ := dataRc.Read(buf)
44+
buf = buf[:n]
45+
return buf, nil
46+
}
47+
3548
// GetBlobLineCount gets line count of lob as raw text
3649
func (b *Blob) GetBlobLineCount() (int, error) {
3750
reader, err := b.DataAsync()

modules/lfs/pointers.go

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ package lfs
66

77
import (
88
"io"
9-
"strconv"
10-
"strings"
119

1210
"code.gitea.io/gitea/models"
1311
"code.gitea.io/gitea/modules/base"
@@ -29,43 +27,11 @@ func ReadPointerFile(reader io.Reader) (*models.LFSMetaObject, *[]byte) {
2927
return nil, nil
3028
}
3129

32-
return IsPointerFile(&buf), &buf
33-
}
34-
35-
// IsPointerFile will return a partially filled LFSMetaObject if the provided byte slice is a pointer file
36-
func IsPointerFile(buf *[]byte) *models.LFSMetaObject {
37-
if !setting.LFS.StartServer {
38-
return nil
39-
}
40-
41-
headString := string(*buf)
42-
if !strings.HasPrefix(headString, models.LFSMetaFileIdentifier) {
43-
return nil
44-
}
45-
46-
splitLines := strings.Split(headString, "\n")
47-
if len(splitLines) < 3 {
48-
return nil
49-
}
50-
51-
oid := strings.TrimPrefix(splitLines[1], models.LFSMetaFileOidPrefix)
52-
size, err := strconv.ParseInt(strings.TrimPrefix(splitLines[2], "size "), 10, 64)
53-
if len(oid) != 64 || err != nil {
54-
return nil
55-
}
56-
57-
contentStore := &ContentStore{ObjectStorage: storage.LFS}
58-
meta := &models.LFSMetaObject{Oid: oid, Size: size}
59-
exist, err := contentStore.Exists(meta)
60-
if err != nil || !exist {
61-
return nil
62-
}
63-
64-
return meta
30+
return models.IsPointerFile(&buf), &buf
6531
}
6632

6733
// ReadMetaObject will read a models.LFSMetaObject and return a reader
6834
func ReadMetaObject(meta *models.LFSMetaObject) (io.ReadCloser, error) {
69-
contentStore := &ContentStore{ObjectStorage: storage.LFS}
35+
contentStore := &models.ContentStore{ObjectStorage: storage.LFS}
7036
return contentStore.Get(meta, 0)
7137
}

modules/lfs/server.go

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
"regexp"
1515
"strconv"
1616
"strings"
17-
"time"
17+
"errors"
1818

1919
"code.gitea.io/gitea/models"
2020
"code.gitea.io/gitea/modules/context"
@@ -29,6 +29,11 @@ const (
2929
metaMediaType = "application/vnd.git-lfs+json"
3030
)
3131

32+
var (
33+
errHashMismatch = errors.New("Content hash does not match OID")
34+
errSizeMismatch = errors.New("Content size does not match")
35+
)
36+
3237
// RequestVars contain variables from the HTTP request. Variables from routing, json body decoding, and
3338
// some headers are stored.
3439
type RequestVars struct {
@@ -48,27 +53,6 @@ type BatchVars struct {
4853
Objects []*RequestVars `json:"objects"`
4954
}
5055

51-
// BatchResponse contains multiple object metadata Representation structures
52-
// for use with the batch API.
53-
type BatchResponse struct {
54-
Transfer string `json:"transfer,omitempty"`
55-
Objects []*Representation `json:"objects"`
56-
}
57-
58-
// Representation is object metadata as seen by clients of the lfs server.
59-
type Representation struct {
60-
Oid string `json:"oid"`
61-
Size int64 `json:"size"`
62-
Actions map[string]*link `json:"actions"`
63-
Error *ObjectError `json:"error,omitempty"`
64-
}
65-
66-
// ObjectError defines the JSON structure returned to the client in case of an error
67-
type ObjectError struct {
68-
Code int `json:"code"`
69-
Message string `json:"message"`
70-
}
71-
7256
// Claims is a JWT Token Claims
7357
type Claims struct {
7458
RepoID int64
@@ -87,13 +71,6 @@ func (v *RequestVars) VerifyLink() string {
8771
return setting.AppURL + path.Join(v.User, v.Repo+".git", "info/lfs/verify")
8872
}
8973

90-
// link provides a structure used to build a hypermedia representation of an HTTP link.
91-
type link struct {
92-
Href string `json:"href"`
93-
Header map[string]string `json:"header,omitempty"`
94-
ExpiresAt time.Time `json:"expires_at,omitempty"`
95-
}
96-
9774
var oidRegExp = regexp.MustCompile(`^[A-Fa-f0-9]+$`)
9875

9976
func isOidValid(oid string) bool {
@@ -187,10 +164,10 @@ func getContentHandler(ctx *context.Context) {
187164
}
188165
}
189166

190-
contentStore := &ContentStore{ObjectStorage: storage.LFS}
167+
contentStore := &models.ContentStore{ObjectStorage: storage.LFS}
191168
content, err := contentStore.Get(meta, fromByte)
192169
if err != nil {
193-
if IsErrRangeNotSatisfiable(err) {
170+
if models.IsErrRangeNotSatisfiable(err) {
194171
writeStatus(ctx, http.StatusRequestedRangeNotSatisfiable)
195172
} else {
196173
// Errors are logged in contentStore.Get
@@ -292,7 +269,7 @@ func PostHandler(ctx *context.Context) {
292269
ctx.Resp.Header().Set("Content-Type", metaMediaType)
293270

294271
sentStatus := 202
295-
contentStore := &ContentStore{ObjectStorage: storage.LFS}
272+
contentStore := &models.ContentStore{ObjectStorage: storage.LFS}
296273
exist, err := contentStore.Exists(meta)
297274
if err != nil {
298275
log.Error("Unable to check if LFS OID[%s] exist on %s / %s. Error: %v", rv.Oid, rv.User, rv.Repo, err)
@@ -327,7 +304,7 @@ func BatchHandler(ctx *context.Context) {
327304

328305
bv := unpackbatch(ctx)
329306

330-
var responseObjects []*Representation
307+
var responseObjects []*models.Representation
331308

332309
// Create a response object
333310
for _, object := range bv.Objects {
@@ -353,7 +330,7 @@ func BatchHandler(ctx *context.Context) {
353330
return
354331
}
355332

356-
contentStore := &ContentStore{ObjectStorage: storage.LFS}
333+
contentStore := &models.ContentStore{ObjectStorage: storage.LFS}
357334

358335
meta, err := repository.GetLFSMetaObjectByOid(object.Oid)
359336
if err == nil { // Object is found and exists
@@ -392,7 +369,7 @@ func BatchHandler(ctx *context.Context) {
392369

393370
ctx.Resp.Header().Set("Content-Type", metaMediaType)
394371

395-
respobj := &BatchResponse{Objects: responseObjects}
372+
respobj := &models.BatchResponse{Objects: responseObjects}
396373

397374
enc := json.NewEncoder(ctx.Resp)
398375
if err := enc.Encode(respobj); err != nil {
@@ -411,7 +388,7 @@ func PutHandler(ctx *context.Context) {
411388
return
412389
}
413390

414-
contentStore := &ContentStore{ObjectStorage: storage.LFS}
391+
contentStore := &models.ContentStore{ObjectStorage: storage.LFS}
415392
defer ctx.Req.Body.Close()
416393
if err := contentStore.Put(meta, ctx.Req.Body); err != nil {
417394
// Put will log the error itself
@@ -452,7 +429,7 @@ func VerifyHandler(ctx *context.Context) {
452429
return
453430
}
454431

455-
contentStore := &ContentStore{ObjectStorage: storage.LFS}
432+
contentStore := &models.ContentStore{ObjectStorage: storage.LFS}
456433
ok, err := contentStore.Verify(meta)
457434
if err != nil {
458435
// Error will be logged in Verify
@@ -470,11 +447,11 @@ func VerifyHandler(ctx *context.Context) {
470447

471448
// Represent takes a RequestVars and Meta and turns it into a Representation suitable
472449
// for json encoding
473-
func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload bool) *Representation {
474-
rep := &Representation{
450+
func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload bool) *models.Representation {
451+
rep := &models.Representation{
475452
Oid: meta.Oid,
476453
Size: meta.Size,
477-
Actions: make(map[string]*link),
454+
Actions: make(map[string]*models.Link),
478455
}
479456

480457
header := make(map[string]string)
@@ -487,11 +464,11 @@ func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload boo
487464
}
488465

489466
if download {
490-
rep.Actions["download"] = &link{Href: rv.ObjectLink(), Header: header}
467+
rep.Actions["download"] = &models.Link{Href: rv.ObjectLink(), Header: header}
491468
}
492469

493470
if upload {
494-
rep.Actions["upload"] = &link{Href: rv.ObjectLink(), Header: header}
471+
rep.Actions["upload"] = &models.Link{Href: rv.ObjectLink(), Header: header}
495472
}
496473

497474
if upload && !download {
@@ -504,7 +481,7 @@ func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload boo
504481
// This is only needed to workaround https://github.com/git-lfs/git-lfs/issues/3662
505482
verifyHeader["Accept"] = metaMediaType
506483

507-
rep.Actions["verify"] = &link{Href: rv.VerifyLink(), Header: verifyHeader}
484+
rep.Actions["verify"] = &models.Link{Href: rv.VerifyLink(), Header: verifyHeader}
508485
}
509486

510487
return rep

0 commit comments

Comments
 (0)