mirror of https://github.com/go-gitea/gitea
Make repository management section handle lfs locks (#8726)
* Make repository maangement section handle lfs locks * Add check attribute handling and handle locking paths better * More cleanly check-attributes * handle error * Check if file exists in default branch before linking to it. * fixup * Properly cleanPath * Use cleanPath * Sighpull/9332/head^2
parent
751cfb805d
commit
dc2fe9801f
@ -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 |
||||
} |
@ -0,0 +1,61 @@ |
||||
{{template "base/head" .}} |
||||
<div class="repository settings lfs"> |
||||
{{template "repo/header" .}} |
||||
{{template "repo/settings/navbar" .}} |
||||
<div class="ui container repository file list"> |
||||
{{template "base/alert" .}} |
||||
<div class="tab-size-8 non-diff-file-content"> |
||||
<h4 class="ui top attached header"> |
||||
<a href="{{.LFSFilesLink}}">{{.i18n.Tr "repo.settings.lfs"}}</a> / {{.i18n.Tr "repo.settings.lfs_locks"}} ({{.i18n.Tr "admin.total" .Total}}) |
||||
</h4> |
||||
<div class="ui attached segment"> |
||||
<form class="ui form ignore-dirty" method="POST"> |
||||
{{$.CsrfTokenHtml}} |
||||
<div class="ui fluid action input"> |
||||
<input name="path" value="" placeholder="{{.i18n.Tr "repo.settings.lfs_lock_path"}}" autofocus> |
||||
<button class="ui blue button">{{.i18n.Tr "repo.settings.lfs_lock"}}</button> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
<table id="lfs-files-locks-table" class="ui attached segment single line table"> |
||||
<tbody> |
||||
{{range $index, $lock := .LFSLocks}} |
||||
<tr> |
||||
<td> |
||||
{{if index $.Linkable $index}} |
||||
<span class="octicon octicon-file-text"></span> |
||||
<a href="{{EscapePound $.RepoLink}}/src/branch/{{EscapePound $lock.Repo.DefaultBranch}}/{{EscapePound $lock.Path}}" title="{{$lock.Path}}">{{$lock.Path}}</a> |
||||
{{else}} |
||||
<span class="octicon octicon-diff"></span> |
||||
<span class="poping up" title="{{$.i18n.Tr "repo.settings.lfs_lock_file_no_exist"}}">{{$lock.Path}}</span> |
||||
{{end}} |
||||
{{if not (index $.Lockables $index)}} |
||||
<i class="octicon octicon-alert poping up" title="{{$.i18n.Tr "repo.settings.lfs_noattribute"}}"></i> |
||||
{{end}} |
||||
</td> |
||||
<td> |
||||
<a href="{{$.AppSubUrl}}/{{$lock.Owner.Name}}"> |
||||
<img class="ui avatar image" src="{{$lock.Owner.RelAvatarLink}}"> |
||||
{{$lock.Owner.DisplayName}} |
||||
</a> |
||||
</td> |
||||
<td>{{TimeSince .Created $.Lang}}</td> |
||||
<td class="right aligned"> |
||||
<form action="{{$.LFSFilesLink}}/locks/{{$lock.ID}}/unlock" method="POST"> |
||||
{{$.CsrfTokenHtml}} |
||||
<button class="ui blue button"><i class="octicon octicon-lock btn-octicon"></i>{{$.i18n.Tr "repo.settings.lfs_force_unlock"}}</button> |
||||
</form> |
||||
</td> |
||||
</tr> |
||||
{{else}} |
||||
<tr> |
||||
<td colspan="4">{{.i18n.Tr "repo.settings.lfs_locks_no_locks"}}</td> |
||||
</tr> |
||||
{{end}} |
||||
</tbody> |
||||
</table> |
||||
{{template "base/paginate" .}} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{{template "base/footer" .}} |
Loading…
Reference in new issue