You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lfs.go 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "errors"
  7. "code.gitea.io/gitea/modules/lfs"
  8. "code.gitea.io/gitea/modules/timeutil"
  9. "xorm.io/builder"
  10. )
  11. // LFSMetaObject stores metadata for LFS tracked files.
  12. type LFSMetaObject struct {
  13. ID int64 `xorm:"pk autoincr"`
  14. lfs.Pointer `xorm:"extends"`
  15. RepositoryID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
  16. Existing bool `xorm:"-"`
  17. CreatedUnix timeutil.TimeStamp `xorm:"created"`
  18. }
  19. // LFSTokenResponse defines the JSON structure in which the JWT token is stored.
  20. // This structure is fetched via SSH and passed by the Git LFS client to the server
  21. // endpoint for authorization.
  22. type LFSTokenResponse struct {
  23. Header map[string]string `json:"header"`
  24. Href string `json:"href"`
  25. }
  26. // ErrLFSObjectNotExist is returned from lfs models functions in order
  27. // to differentiate between database and missing object errors.
  28. var ErrLFSObjectNotExist = errors.New("LFS Meta object does not exist")
  29. // NewLFSMetaObject stores a given populated LFSMetaObject structure in the database
  30. // if it is not already present.
  31. func NewLFSMetaObject(m *LFSMetaObject) (*LFSMetaObject, error) {
  32. var err error
  33. sess := x.NewSession()
  34. defer sess.Close()
  35. if err = sess.Begin(); err != nil {
  36. return nil, err
  37. }
  38. has, err := sess.Get(m)
  39. if err != nil {
  40. return nil, err
  41. }
  42. if has {
  43. m.Existing = true
  44. return m, sess.Commit()
  45. }
  46. if _, err = sess.Insert(m); err != nil {
  47. return nil, err
  48. }
  49. return m, sess.Commit()
  50. }
  51. // GetLFSMetaObjectByOid selects a LFSMetaObject entry from database by its OID.
  52. // It may return ErrLFSObjectNotExist or a database error. If the error is nil,
  53. // the returned pointer is a valid LFSMetaObject.
  54. func (repo *Repository) GetLFSMetaObjectByOid(oid string) (*LFSMetaObject, error) {
  55. if len(oid) == 0 {
  56. return nil, ErrLFSObjectNotExist
  57. }
  58. m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repo.ID}
  59. has, err := x.Get(m)
  60. if err != nil {
  61. return nil, err
  62. } else if !has {
  63. return nil, ErrLFSObjectNotExist
  64. }
  65. return m, nil
  66. }
  67. // RemoveLFSMetaObjectByOid removes a LFSMetaObject entry from database by its OID.
  68. // It may return ErrLFSObjectNotExist or a database error.
  69. func (repo *Repository) RemoveLFSMetaObjectByOid(oid string) (int64, error) {
  70. if len(oid) == 0 {
  71. return 0, ErrLFSObjectNotExist
  72. }
  73. sess := x.NewSession()
  74. defer sess.Close()
  75. if err := sess.Begin(); err != nil {
  76. return -1, err
  77. }
  78. m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repo.ID}
  79. if _, err := sess.Delete(m); err != nil {
  80. return -1, err
  81. }
  82. count, err := sess.Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
  83. if err != nil {
  84. return count, err
  85. }
  86. return count, sess.Commit()
  87. }
  88. // GetLFSMetaObjects returns all LFSMetaObjects associated with a repository
  89. func (repo *Repository) GetLFSMetaObjects(page, pageSize int) ([]*LFSMetaObject, error) {
  90. sess := x.NewSession()
  91. defer sess.Close()
  92. if page >= 0 && pageSize > 0 {
  93. start := 0
  94. if page > 0 {
  95. start = (page - 1) * pageSize
  96. }
  97. sess.Limit(pageSize, start)
  98. }
  99. lfsObjects := make([]*LFSMetaObject, 0, pageSize)
  100. return lfsObjects, sess.Find(&lfsObjects, &LFSMetaObject{RepositoryID: repo.ID})
  101. }
  102. // CountLFSMetaObjects returns a count of all LFSMetaObjects associated with a repository
  103. func (repo *Repository) CountLFSMetaObjects() (int64, error) {
  104. return x.Count(&LFSMetaObject{RepositoryID: repo.ID})
  105. }
  106. // LFSObjectAccessible checks if a provided Oid is accessible to the user
  107. func LFSObjectAccessible(user *User, oid string) (bool, error) {
  108. if user.IsAdmin {
  109. count, err := x.Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
  110. return count > 0, err
  111. }
  112. cond := accessibleRepositoryCondition(user)
  113. count, err := x.Where(cond).Join("INNER", "repository", "`lfs_meta_object`.repository_id = `repository`.id").Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
  114. return count > 0, err
  115. }
  116. // LFSAutoAssociate auto associates accessible LFSMetaObjects
  117. func LFSAutoAssociate(metas []*LFSMetaObject, user *User, repoID int64) error {
  118. sess := x.NewSession()
  119. defer sess.Close()
  120. if err := sess.Begin(); err != nil {
  121. return err
  122. }
  123. oids := make([]interface{}, len(metas))
  124. oidMap := make(map[string]*LFSMetaObject, len(metas))
  125. for i, meta := range metas {
  126. oids[i] = meta.Oid
  127. oidMap[meta.Oid] = meta
  128. }
  129. cond := builder.NewCond()
  130. if !user.IsAdmin {
  131. cond = builder.In("`lfs_meta_object`.repository_id",
  132. builder.Select("`repository`.id").From("repository").Where(accessibleRepositoryCondition(user)))
  133. }
  134. newMetas := make([]*LFSMetaObject, 0, len(metas))
  135. if err := sess.Cols("oid").Where(cond).In("oid", oids...).GroupBy("oid").Find(&newMetas); err != nil {
  136. return err
  137. }
  138. for i := range newMetas {
  139. newMetas[i].Size = oidMap[newMetas[i].Oid].Size
  140. newMetas[i].RepositoryID = repoID
  141. }
  142. if _, err := sess.InsertMulti(newMetas); err != nil {
  143. return err
  144. }
  145. return sess.Commit()
  146. }
  147. // IterateLFS iterates lfs object
  148. func IterateLFS(f func(mo *LFSMetaObject) error) error {
  149. var start int
  150. const batchSize = 100
  151. for {
  152. mos := make([]*LFSMetaObject, 0, batchSize)
  153. if err := x.Limit(batchSize, start).Find(&mos); err != nil {
  154. return err
  155. }
  156. if len(mos) == 0 {
  157. return nil
  158. }
  159. start += len(mos)
  160. for _, mo := range mos {
  161. if err := f(mo); err != nil {
  162. return err
  163. }
  164. }
  165. }
  166. }