summaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2022-01-01 17:05:31 +0800
committerGitHub <noreply@github.com>2022-01-01 17:05:31 +0800
commit385dc6a9927bd4bb66cb2a62e3f7e5643b973ee9 (patch)
tree287d120cd7125e59b8fa2cd6fd82a399f3189901 /models
parent25a290e320de630eaf8ef4e56bb435c1ecfe1032 (diff)
downloadgitea-385dc6a9927bd4bb66cb2a62e3f7e5643b973ee9.tar.gz
gitea-385dc6a9927bd4bb66cb2a62e3f7e5643b973ee9.zip
Allow admin to associate missing LFS objects for repositories (#18143)
This PR reworked the Find pointer files feature in Settings -> LFS page. When a LFS object is missing from database but exists in LFS content store, admin can associate it to the repository by clicking the Associate button. This PR is not perfect (because the LFS module itself should be improved too), it's just a nice-to-have feature to help users recover their LFS repositories (eg: database was lost / table was truncated)
Diffstat (limited to 'models')
-rw-r--r--models/lfs.go53
1 files changed, 38 insertions, 15 deletions
diff --git a/models/lfs.go b/models/lfs.go
index 56924ffcf2..cf596f5468 100644
--- a/models/lfs.go
+++ b/models/lfs.go
@@ -7,11 +7,13 @@ package models
import (
"context"
"errors"
+ "fmt"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/lfs"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
@@ -145,6 +147,11 @@ func LFSObjectAccessible(user *user_model.User, oid string) (bool, error) {
return count > 0, err
}
+// LFSObjectIsAssociated checks if a provided Oid is associated
+func LFSObjectIsAssociated(oid string) (bool, error) {
+ return db.GetEngine(db.DefaultContext).Exist(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
+}
+
// LFSAutoAssociate auto associates accessible LFSMetaObjects
func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int64) error {
ctx, committer, err := db.TxContext()
@@ -162,23 +169,39 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6
oidMap[meta.Oid] = meta
}
- cond := builder.NewCond()
if !user.IsAdmin {
- cond = builder.In("`lfs_meta_object`.repository_id",
- builder.Select("`repository`.id").From("repository").Where(accessibleRepositoryCondition(user)))
- }
- newMetas := make([]*LFSMetaObject, 0, len(metas))
- if err := sess.Cols("oid").Where(cond).In("oid", oids...).GroupBy("oid").Find(&newMetas); err != nil {
- return err
- }
- for i := range newMetas {
- newMetas[i].Size = oidMap[newMetas[i].Oid].Size
- newMetas[i].RepositoryID = repoID
- }
- if err := db.Insert(ctx, newMetas); err != nil {
- return err
+ newMetas := make([]*LFSMetaObject, 0, len(metas))
+ cond := builder.In(
+ "`lfs_meta_object`.repository_id",
+ builder.Select("`repository`.id").From("repository").Where(accessibleRepositoryCondition(user)),
+ )
+ err = sess.Cols("oid").Where(cond).In("oid", oids...).GroupBy("oid").Find(&newMetas)
+ if err != nil {
+ return err
+ }
+ if len(newMetas) != len(oidMap) {
+ return fmt.Errorf("unable collect all LFS objects from database, expected %d, actually %d", len(oidMap), len(newMetas))
+ }
+ for i := range newMetas {
+ newMetas[i].Size = oidMap[newMetas[i].Oid].Size
+ newMetas[i].RepositoryID = repoID
+ }
+ if err = db.Insert(ctx, newMetas); err != nil {
+ return err
+ }
+ } else {
+ // admin can associate any LFS object to any repository, and we do not care about errors (eg: duplicated unique key),
+ // even if error occurs, it won't hurt users and won't make things worse
+ for i := range metas {
+ _, err = sess.Insert(&LFSMetaObject{
+ Pointer: lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size},
+ RepositoryID: repoID,
+ })
+ if err != nil {
+ log.Warn("failed to insert LFS meta object into database, err=%v", err)
+ }
+ }
}
-
return committer.Commit()
}