From b746463706f59a046db06ac303098739108978da Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Mon, 28 Oct 2019 22:32:04 +0000 Subject: [PATCH 1/9] Make repository maangement section handle lfs locks --- models/lfs_lock.go | 23 +++++++-- modules/lfs/locks.go | 4 +- options/locale/locale_en-US.ini | 5 ++ public/css/index.css | 1 + public/less/_base.less | 4 ++ routers/repo/lfs.go | 67 ++++++++++++++++++++++++++ routers/routes/routes.go | 5 ++ templates/repo/settings/lfs.tmpl | 5 +- templates/repo/settings/lfs_locks.tmpl | 53 ++++++++++++++++++++ 9 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 templates/repo/settings/lfs_locks.tmpl diff --git a/models/lfs_lock.go b/models/lfs_lock.go index ba1a4528153b9..3caa67e3c2208 100644 --- a/models/lfs_lock.go +++ b/models/lfs_lock.go @@ -71,6 +71,8 @@ func CreateLFSLock(lock *LFSLock) (*LFSLock, error) { return nil, err } + lock.Path = cleanPath(lock.Path) + l, err := GetLFSLock(lock.Repo, lock.Path) if err == nil { return l, ErrLFSLockAlreadyExist{lock.RepoID, lock.Path} @@ -110,9 +112,24 @@ func GetLFSLockByID(id int64) (*LFSLock, error) { } // GetLFSLockByRepoID returns a list of locks of repository. -func GetLFSLockByRepoID(repoID int64) (locks []*LFSLock, err error) { - err = x.Where("repo_id = ?", repoID).Find(&locks) - return +func GetLFSLockByRepoID(repoID int64, page, pageSize int) ([]*LFSLock, error) { + sess := x.NewSession() + defer sess.Close() + + if page >= 0 && pageSize > 0 { + start := 0 + if page > 0 { + start = (page - 1) * pageSize + } + sess.Limit(pageSize, start) + } + lfsLocks := make([]*LFSLock, 0, pageSize) + return lfsLocks, sess.Find(&lfsLocks, &LFSLock{RepoID: repoID}) +} + +// CountLFSLockByRepoID returns a count of all LFSLocks associated with a repository. +func CountLFSLockByRepoID(repoID int64) (int64, error) { + return x.Count(&LFSLock{RepoID: repoID}) } // DeleteLFSLockByID deletes a lock by given ID. diff --git a/modules/lfs/locks.go b/modules/lfs/locks.go index 9ffe6b9d59482..b077cd2d0b507 100644 --- a/modules/lfs/locks.go +++ b/modules/lfs/locks.go @@ -110,7 +110,7 @@ func GetListLockHandler(ctx *context.Context) { } //If no query params path or id - lockList, err := models.GetLFSLockByRepoID(repository.ID) + lockList, err := models.GetLFSLockByRepoID(repository.ID, 0, 0) if err != nil { ctx.JSON(500, api.LFSLockError{ Message: "unable to list locks : " + err.Error(), @@ -220,7 +220,7 @@ func VerifyLockHandler(ctx *context.Context) { } //TODO handle body json cursor and limit - lockList, err := models.GetLFSLockByRepoID(repository.ID) + lockList, err := models.GetLFSLockByRepoID(repository.ID, 0, 0) if err != nil { ctx.JSON(500, api.LFSLockError{ Message: "unable to list locks : " + err.Error(), diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4210ed1212a80..049285eaf499a 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1386,6 +1386,11 @@ settings.lfs_lfs_file_no_commits=No Commits found for this LFS file settings.lfs_delete=Delete LFS file with OID %s settings.lfs_delete_warning=Deleting an LFS file may cause 'object does not exist' errors on checkout. Are you sure? settings.lfs_findpointerfiles=Find pointer files +settings.lfs_locks=Locks +settings.lfs_lock=Lock +settings.lfs_lock_path=Filepath to lock... +settings.lfs_locks_no_locks=No Locks +settings.lfs_force_unlock=Force Unlock settings.lfs_pointers.found=Found %d blob pointer(s) - %d associated, %d unassociated (%d missing from store) settings.lfs_pointers.sha=Blob SHA settings.lfs_pointers.oid=OID diff --git a/public/css/index.css b/public/css/index.css index d0fe896a0611c..dc70fd627877a 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -247,6 +247,7 @@ i.icon.centerlock{top:1.5em} .code-view :not(.fa):not(.octicon):not(.icon){font-size:12px;font-family:'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;line-height:20px} .code-view table{width:100%} .code-view .active{background:#fff866} +.octicon-tiny{font-size:.85714286rem} .markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word} .markdown:not(code).ui.segment{padding:3em} .markdown:not(code).file-view{padding:2em 2em 2em!important} diff --git a/public/less/_base.less b/public/less/_base.less index 7fcfaf82eabba..17768d3c89009 100644 --- a/public/less/_base.less +++ b/public/less/_base.less @@ -1087,3 +1087,7 @@ i.icon.centerlock { background: #fff866; } } + +.octicon-tiny { + font-size: 0.85714286rem; +} diff --git a/routers/repo/lfs.go b/routers/repo/lfs.go index de5020c944044..d8ceb524a7a74 100644 --- a/routers/repo/lfs.go +++ b/routers/repo/lfs.go @@ -38,6 +38,7 @@ import ( const ( tplSettingsLFS base.TplName = "repo/settings/lfs" + tplSettingsLFSLocks base.TplName = "repo/settings/lfs_locks" tplSettingsLFSFile base.TplName = "repo/settings/lfs_file" tplSettingsLFSFileFind base.TplName = "repo/settings/lfs_file_find" tplSettingsLFSPointers base.TplName = "repo/settings/lfs_pointers" @@ -58,6 +59,7 @@ func LFSFiles(ctx *context.Context) { ctx.ServerError("LFSFiles", err) return } + ctx.Data["Total"] = total pager := context.NewPagination(int(total), setting.UI.ExplorePagingNum, page, 5) ctx.Data["Title"] = ctx.Tr("repo.settings.lfs") @@ -72,6 +74,71 @@ func LFSFiles(ctx *context.Context) { ctx.HTML(200, tplSettingsLFS) } +// LFSLocks shows a repository's LFS locks +func LFSLocks(ctx *context.Context) { + if !setting.LFS.StartServer { + ctx.NotFound("LFSLocks", nil) + return + } + ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs" + + page := ctx.QueryInt("page") + if page <= 1 { + page = 1 + } + total, err := models.CountLFSLockByRepoID(ctx.Repo.Repository.ID) + if err != nil { + ctx.ServerError("LFSLocks", err) + return + } + ctx.Data["Total"] = total + + pager := context.NewPagination(int(total), setting.UI.ExplorePagingNum, page, 5) + ctx.Data["Title"] = ctx.Tr("repo.settings.lfs_locks") + ctx.Data["PageIsSettingsLFS"] = true + lfsLocks, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID, pager.Paginater.Current(), setting.UI.ExplorePagingNum) + if err != nil { + ctx.ServerError("LFSLocks", err) + return + } + ctx.Data["LFSLocks"] = lfsLocks + ctx.Data["Page"] = pager + ctx.HTML(200, tplSettingsLFSLocks) +} + +// LFSLockFile locks a file +func LFSLockFile(ctx *context.Context) { + if !setting.LFS.StartServer { + ctx.NotFound("LFSLocks", nil) + return + } + path := ctx.Query("path") + _, err := models.CreateLFSLock(&models.LFSLock{ + Repo: ctx.Repo.Repository, + Path: path, + Owner: ctx.User, + }) + if err != nil { + ctx.ServerError("LFSLockFile", err) + return + } + ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks") +} + +// LFSUnlock forcibly unlocks an LFS lock +func LFSUnlock(ctx *context.Context) { + if !setting.LFS.StartServer { + ctx.NotFound("LFSUnlock", nil) + return + } + _, err := models.DeleteLFSLockByID(ctx.ParamsInt64("lid"), ctx.User, true) + if err != nil { + ctx.ServerError("LFSUnlock", err) + return + } + ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks") +} + // LFSFileGet serves a single LFS file func LFSFileGet(ctx *context.Context) { if !setting.LFS.StartServer { diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 13a5bb27084d0..dcdc327f8f4f3 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -684,6 +684,11 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/pointers", repo.LFSPointerFiles) m.Post("/pointers/associate", repo.LFSAutoAssociate) m.Get("/find", repo.LFSFileFind) + m.Group("/locks", func() { + m.Get("/", repo.LFSLocks) + m.Post("/", repo.LFSLockFile) + m.Post("/:lid/unlock", repo.LFSUnlock) + }) }) }, func(ctx *context.Context) { diff --git a/templates/repo/settings/lfs.tmpl b/templates/repo/settings/lfs.tmpl index e4480a8b97220..f43f9479a257e 100644 --- a/templates/repo/settings/lfs.tmpl +++ b/templates/repo/settings/lfs.tmpl @@ -5,9 +5,10 @@
{{template "base/alert" .}}

- {{.i18n.Tr "repo.settings.lfs_filelist"}} + {{.i18n.Tr "repo.settings.lfs_filelist"}} ({{.i18n.Tr "admin.total" .Total}})

diff --git a/templates/repo/settings/lfs_locks.tmpl b/templates/repo/settings/lfs_locks.tmpl new file mode 100644 index 0000000000000..6fec74df7736e --- /dev/null +++ b/templates/repo/settings/lfs_locks.tmpl @@ -0,0 +1,53 @@ +{{template "base/head" .}} +
+ {{template "repo/header" .}} + {{template "repo/settings/navbar" .}} +
+ {{template "base/alert" .}} +
+

+ {{.i18n.Tr "repo.settings.lfs"}} / {{.i18n.Tr "repo.settings.lfs_locks"}} ({{.i18n.Tr "admin.total" .Total}}) +

+
+
+ {{$.CsrfTokenHtml}} +
+ + +
+ +
+
+ + {{range .LFSLocks}} + + + + + + + {{else}} + + + + {{end}} + +
+ + {{.Path}} + + + + {{.Owner.DisplayName}} + + {{TimeSince .Created $.Lang}} +
+ {{$.CsrfTokenHtml}} + +
+
{{.i18n.Tr "repo.settings.lfs_locks_no_locks"}}
+ {{template "base/paginate" .}} +
+ + +{{template "base/footer" .}} From 33781086b7cb5858f79f9964956319c566c92a05 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 29 Oct 2019 18:30:57 +0000 Subject: [PATCH 2/9] Add check attribute handling and handle locking paths better --- modules/git/repo_attribute.go | 84 ++++++++++++++++++++++++++ options/locale/locale_en-US.ini | 4 ++ routers/repo/lfs.go | 55 ++++++++++++++++- templates/repo/settings/lfs_locks.tmpl | 15 +++-- 4 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 modules/git/repo_attribute.go diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go new file mode 100644 index 0000000000000..c10c96f5584b6 --- /dev/null +++ b/modules/git/repo_attribute.go @@ -0,0 +1,84 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bytes" + "fmt" + + "github.com/mcuadros/go-version" +) + +// CheckAttributeOpts represents the possible options to CheckAttribute +type CheckAttributeOpts struct { + CachedOnly bool + AllAttributes bool + Attributes []string + Filenames []string +} + +// CheckAttribute return the Blame object of file +func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[string]string, error) { + binVersion, err := BinVersion() + if err != nil { + return nil, fmt.Errorf("Git version missing: %v", err) + } + + stdOut := new(bytes.Buffer) + stdErr := new(bytes.Buffer) + + cmdArgs := []string{"check-attr", "-z"} + + if opts.AllAttributes { + cmdArgs = append(cmdArgs, "-a") + } else { + for _, attribute := range opts.Attributes { + if attribute != "" { + cmdArgs = append(cmdArgs, attribute) + } + } + } + + // git check-attr --cached first appears in git 1.7.8 + if opts.CachedOnly && version.Compare(binVersion, "1.7.8", ">=") { + cmdArgs = append(cmdArgs, "--cached") + } + + cmdArgs = append(cmdArgs, "--") + + for _, arg := range opts.Filenames { + if arg != "" { + cmdArgs = append(cmdArgs, arg) + } + } + + cmd := NewCommand(cmdArgs...) + + if err := cmd.RunInDirPipeline(repo.Path, stdOut, stdErr); err != nil { + return nil, fmt.Errorf("Failed to run check-attr: %v\n%s\n%s", err, stdOut.String(), stdErr.String()) + } + + fields := bytes.Split(stdOut.Bytes(), []byte{'\000'}) + + if len(fields)%3 != 1 { + return nil, fmt.Errorf("Wrong number of fields in return from check-attr") + } + + var name2attribute2info = make(map[string]map[string]string) + + for i := 0; i < (len(fields) / 3); i++ { + filename := string(fields[3*i]) + attribute := string(fields[3*i+1]) + info := string(fields[3*i+2]) + attribute2info := name2attribute2info[filename] + if attribute2info == nil { + attribute2info = make(map[string]string) + } + attribute2info[attribute] = info + name2attribute2info[filename] = attribute2info + } + + return name2attribute2info, nil +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 049285eaf499a..ff8a7cc80dfc8 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1383,10 +1383,14 @@ settings.lfs_filelist=LFS files stored in this repository settings.lfs_no_lfs_files=No LFS files stored in this repository settings.lfs_findcommits=Find commits settings.lfs_lfs_file_no_commits=No Commits found for this LFS file +settings.lfs_noattribute=This path does not have the lockable attribute settings.lfs_delete=Delete LFS file with OID %s settings.lfs_delete_warning=Deleting an LFS file may cause 'object does not exist' errors on checkout. Are you sure? settings.lfs_findpointerfiles=Find pointer files settings.lfs_locks=Locks +settings.lfs_invalid_locking_path=Invalid path: %s +settings.lfs_invalid_lock_directory=Cannot lock directory: %s +settings.lfs_lock_already_exists=Lock already exists: %s settings.lfs_lock=Lock settings.lfs_lock_path=Filepath to lock... settings.lfs_locks_no_locks=No Locks diff --git a/routers/repo/lfs.go b/routers/repo/lfs.go index d8ceb524a7a74..1f65163fd410a 100644 --- a/routers/repo/lfs.go +++ b/routers/repo/lfs.go @@ -12,6 +12,7 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" "sort" "strconv" @@ -102,6 +103,30 @@ func LFSLocks(ctx *context.Context) { return } ctx.Data["LFSLocks"] = lfsLocks + + filenames := make([]string, len(lfsLocks)) + + for i, lock := range lfsLocks { + filenames[i] = lock.Path + } + + name2attribute2info, err := ctx.Repo.GitRepo.CheckAttribute(git.CheckAttributeOpts{ + Attributes: []string{"lockable"}, + Filenames: filenames, + }) + if err != nil { + ctx.ServerError("LFSLocks", err) + } + + lockables := make([]bool, len(lfsLocks)) + for i, lock := range lfsLocks { + if _, has := name2attribute2info[lock.Path]; has { + lockables[i] = true + } + } + + ctx.Data["Lockables"] = lockables + ctx.Data["Page"] = pager ctx.HTML(200, tplSettingsLFSLocks) } @@ -112,13 +137,39 @@ func LFSLockFile(ctx *context.Context) { ctx.NotFound("LFSLocks", nil) return } - path := ctx.Query("path") + originalPath := ctx.Query("path") + lockPath := originalPath + if len(lockPath) == 0 { + ctx.Flash.Error(ctx.Tr("repo.settings.lfs_invalid_locking_path", originalPath)) + ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks") + return + } + if lockPath[len(lockPath)-1] == '/' { + ctx.Flash.Error(ctx.Tr("repo.settings.lfs_invalid_lock_directory", originalPath)) + ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks") + return + } + lockPath = path.Clean(lockPath) + if lockPath[0] == '/' { + lockPath = lockPath[1:] + } + if len(lockPath) == 0 { + ctx.Flash.Error(ctx.Tr("repo.settings.lfs_invalid_locking_path", originalPath)) + ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks") + return + } + _, err := models.CreateLFSLock(&models.LFSLock{ Repo: ctx.Repo.Repository, - Path: path, + Path: lockPath, Owner: ctx.User, }) if err != nil { + if models.IsErrLFSLockAlreadyExist(err) { + ctx.Flash.Error(ctx.Tr("repo.settings.lfs_lock_already_exists", originalPath)) + ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks") + return + } ctx.ServerError("LFSLockFile", err) return } diff --git a/templates/repo/settings/lfs_locks.tmpl b/templates/repo/settings/lfs_locks.tmpl index 6fec74df7736e..f1dc2a5267684 100644 --- a/templates/repo/settings/lfs_locks.tmpl +++ b/templates/repo/settings/lfs_locks.tmpl @@ -19,21 +19,24 @@ - {{range .LFSLocks}} + {{range $index, $lock := .LFSLocks}} From 15ad539a744de656837469a82c952419c7c3ee8f Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 29 Oct 2019 19:45:09 +0000 Subject: [PATCH 4/9] handle error --- routers/repo/lfs.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/routers/repo/lfs.go b/routers/repo/lfs.go index 3cda79d56e9da..5a16a470abe1b 100644 --- a/routers/repo/lfs.go +++ b/routers/repo/lfs.go @@ -143,7 +143,10 @@ func LFSLocks(ctx *context.Context) { filenames[i] = lock.Path } - gitRepo.ReadTreeToIndex(ctx.Repo.Repository.DefaultBranch) + if err := gitRepo.ReadTreeToIndex(ctx.Repo.Repository.DefaultBranch); err != nil { + log.Error("Unable to read the default branch to the index: %s (%v)", ctx.Repo.Repository.DefaultBranch, err) + ctx.ServerError("LFSLocks", fmt.Errorf("Unable to read the default branch to the index: %s (%v)", ctx.Repo.Repository.DefaultBranch, err)) + } name2attribute2info, err := gitRepo.CheckAttribute(git.CheckAttributeOpts{ Attributes: []string{"lockable"}, From 8f618686aa91f6b40b1bcb2600cf766e4d9ccd41 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 29 Oct 2019 20:37:25 +0000 Subject: [PATCH 5/9] Check if file exists in default branch before linking to it. --- options/locale/locale_en-US.ini | 3 ++- routers/repo/lfs.go | 19 ++++++++++++++++++- templates/repo/settings/lfs_locks.tmpl | 5 +++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ff8a7cc80dfc8..c5785ded567d0 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1383,7 +1383,7 @@ settings.lfs_filelist=LFS files stored in this repository settings.lfs_no_lfs_files=No LFS files stored in this repository settings.lfs_findcommits=Find commits settings.lfs_lfs_file_no_commits=No Commits found for this LFS file -settings.lfs_noattribute=This path does not have the lockable attribute +settings.lfs_noattribute=This path does not have the lockable attribute in the default branch settings.lfs_delete=Delete LFS file with OID %s settings.lfs_delete_warning=Deleting an LFS file may cause 'object does not exist' errors on checkout. Are you sure? settings.lfs_findpointerfiles=Find pointer files @@ -1394,6 +1394,7 @@ settings.lfs_lock_already_exists=Lock already exists: %s settings.lfs_lock=Lock settings.lfs_lock_path=Filepath to lock... settings.lfs_locks_no_locks=No Locks +settings.lfs_lock_file_no_exist=Locked file does not exist in default branch settings.lfs_force_unlock=Force Unlock settings.lfs_pointers.found=Found %d blob pointer(s) - %d associated, %d unassociated (%d missing from store) settings.lfs_pointers.sha=Blob SHA diff --git a/routers/repo/lfs.go b/routers/repo/lfs.go index 5a16a470abe1b..6b292a1a775b1 100644 --- a/routers/repo/lfs.go +++ b/routers/repo/lfs.go @@ -154,6 +154,7 @@ func LFSLocks(ctx *context.Context) { CachedOnly: true, }) if err != nil { + log.Error("Unable to check attributes in %s (%v)", tmpBasePath, err) ctx.ServerError("LFSLocks", err) } @@ -168,9 +169,25 @@ func LFSLocks(ctx *context.Context) { } lockables[i] = true } - ctx.Data["Lockables"] = lockables + filelist, err := gitRepo.LsFiles(filenames...) + if err != nil { + log.Error("Unable to lsfiles in %s (%v)", tmpBasePath, err) + ctx.ServerError("LFSLocks", err) + } + + filemap := make(map[string]bool, len(filelist)) + for _, name := range filelist { + filemap[name] = true + } + + linkable := make([]bool, len(lfsLocks)) + for i, lock := range lfsLocks { + linkable[i] = filemap[lock.Path] + } + ctx.Data["Linkable"] = linkable + ctx.Data["Page"] = pager ctx.HTML(200, tplSettingsLFSLocks) } diff --git a/templates/repo/settings/lfs_locks.tmpl b/templates/repo/settings/lfs_locks.tmpl index aba947d1ad651..8a5f6e16584cb 100644 --- a/templates/repo/settings/lfs_locks.tmpl +++ b/templates/repo/settings/lfs_locks.tmpl @@ -22,8 +22,13 @@ {{range $index, $lock := .LFSLocks}}
- {{.Path}} + {{$lock.Path}} + {{if index $.Lockables $index}} + + {{end}} - - - {{.Owner.DisplayName}} + + + {{$lock.Owner.DisplayName}} {{TimeSince .Created $.Lang}} -
+ {{$.CsrfTokenHtml}}
From afb0c26c128befba1c17191ebb49e5e30036e78c Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 29 Oct 2019 19:29:40 +0000 Subject: [PATCH 3/9] More cleanly check-attributes --- routers/repo/lfs.go | 47 ++++++++++++++++++++++++-- templates/repo/settings/lfs_locks.tmpl | 2 +- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/routers/repo/lfs.go b/routers/repo/lfs.go index 1f65163fd410a..3cda79d56e9da 100644 --- a/routers/repo/lfs.go +++ b/routers/repo/lfs.go @@ -104,15 +104,51 @@ func LFSLocks(ctx *context.Context) { } ctx.Data["LFSLocks"] = lfsLocks + if len(lfsLocks) == 0 { + ctx.Data["Page"] = pager + ctx.HTML(200, tplSettingsLFSLocks) + return + } + + // Clone base repo. + tmpBasePath, err := models.CreateTemporaryPath("locks") + if err != nil { + log.Error("Failed to create temporary path: %v", err) + ctx.ServerError("LFSLocks", err) + return + } + defer func() { + if err := models.RemoveTemporaryPath(tmpBasePath); err != nil { + log.Error("LFSLocks: RemoveTemporaryPath: %v", err) + } + }() + + if err := git.Clone(ctx.Repo.Repository.RepoPath(), tmpBasePath, git.CloneRepoOptions{ + Bare: true, + Shared: true, + }); err != nil { + log.Error("Failed to clone repository: %s (%v)", ctx.Repo.Repository.FullName(), err) + ctx.ServerError("LFSLocks", fmt.Errorf("Failed to clone repository: %s (%v)", ctx.Repo.Repository.FullName(), err)) + } + + gitRepo, err := git.OpenRepository(tmpBasePath) + if err != nil { + log.Error("Unable to open temporary repository: %s (%v)", tmpBasePath, err) + ctx.ServerError("LFSLocks", fmt.Errorf("Failed to open new temporary repository in: %s %v", tmpBasePath, err)) + } + filenames := make([]string, len(lfsLocks)) for i, lock := range lfsLocks { filenames[i] = lock.Path } - name2attribute2info, err := ctx.Repo.GitRepo.CheckAttribute(git.CheckAttributeOpts{ + gitRepo.ReadTreeToIndex(ctx.Repo.Repository.DefaultBranch) + + name2attribute2info, err := gitRepo.CheckAttribute(git.CheckAttributeOpts{ Attributes: []string{"lockable"}, Filenames: filenames, + CachedOnly: true, }) if err != nil { ctx.ServerError("LFSLocks", err) @@ -120,9 +156,14 @@ func LFSLocks(ctx *context.Context) { lockables := make([]bool, len(lfsLocks)) for i, lock := range lfsLocks { - if _, has := name2attribute2info[lock.Path]; has { - lockables[i] = true + attribute2info, has := name2attribute2info[lock.Path] + if !has { + continue + } + if attribute2info["lockable"] != "set" { + continue } + lockables[i] = true } ctx.Data["Lockables"] = lockables diff --git a/templates/repo/settings/lfs_locks.tmpl b/templates/repo/settings/lfs_locks.tmpl index f1dc2a5267684..aba947d1ad651 100644 --- a/templates/repo/settings/lfs_locks.tmpl +++ b/templates/repo/settings/lfs_locks.tmpl @@ -24,7 +24,7 @@
{{$lock.Path}} - {{if index $.Lockables $index}} + {{if not (index $.Lockables $index)}} {{end}}
+ {{if index $.Linkable $index}} {{$lock.Path}} + {{else}} + + {{$lock.Path}} + {{end}} {{if not (index $.Lockables $index)}} {{end}} From 03233756dbeeffea91a9adcb334758826eeac231 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Sat, 30 Nov 2019 10:30:00 -0600 Subject: [PATCH 6/9] fixup --- models/repo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/repo.go b/models/repo.go index 0ccf786db3bfb..324645a260e7f 100644 --- a/models/repo.go +++ b/models/repo.go @@ -2881,7 +2881,7 @@ func (repo *Repository) GetOriginalURLHostname() string { // GetTreePathLock returns LSF lock for the treePath func (repo *Repository) GetTreePathLock(treePath string) (*LFSLock, error) { if setting.LFS.StartServer { - locks, err := GetLFSLockByRepoID(repo.ID) + locks, err := GetLFSLockByRepoID(repo.ID, 0, 0) if err != nil { return nil, err } From af3e5741e8327de63681a1f32a8e3267ea9a5a56 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 12 Dec 2019 07:51:05 +0000 Subject: [PATCH 7/9] Properly cleanPath --- models/lfs_lock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/lfs_lock.go b/models/lfs_lock.go index 3caa67e3c2208..3e56a7960b2a6 100644 --- a/models/lfs_lock.go +++ b/models/lfs_lock.go @@ -49,7 +49,7 @@ func (l *LFSLock) AfterLoad(session *xorm.Session) { } func cleanPath(p string) string { - return path.Clean(p) + return path.Clean("/" + p)[1:] } // APIFormat convert a Release to lfs.LFSLock From 9de6cfbe1b69371cf2bba59e501ec95d169bb046 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 12 Dec 2019 07:52:21 +0000 Subject: [PATCH 8/9] Use cleanPath --- routers/repo/lfs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/repo/lfs.go b/routers/repo/lfs.go index 6b292a1a775b1..91533914848ff 100644 --- a/routers/repo/lfs.go +++ b/routers/repo/lfs.go @@ -210,7 +210,7 @@ func LFSLockFile(ctx *context.Context) { ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks") return } - lockPath = path.Clean(lockPath) + lockPath = cleanPath(lockPath) if lockPath[0] == '/' { lockPath = lockPath[1:] } From 76bc3b94254bce3fc050643ce5eb0d98707c3e06 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 12 Dec 2019 11:10:46 +0000 Subject: [PATCH 9/9] Sigh --- routers/repo/lfs.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/routers/repo/lfs.go b/routers/repo/lfs.go index 91533914848ff..c3266844b403c 100644 --- a/routers/repo/lfs.go +++ b/routers/repo/lfs.go @@ -210,10 +210,7 @@ func LFSLockFile(ctx *context.Context) { ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks") return } - lockPath = cleanPath(lockPath) - if lockPath[0] == '/' { - lockPath = lockPath[1:] - } + lockPath = path.Clean("/" + lockPath)[1:] if len(lockPath) == 0 { ctx.Flash.Error(ctx.Tr("repo.settings.lfs_invalid_locking_path", originalPath)) ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks")