1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
package commands
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/git"
"github.com/git-lfs/git-lfs/v3/locking"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/spf13/cobra"
)
var (
lockRemote string
)
func lockCommand(cmd *cobra.Command, args []string) {
if len(lockRemote) > 0 {
cfg.SetRemote(lockRemote)
}
lockData, err := computeLockData()
if err != nil {
ExitWithError(err)
}
refUpdate := git.NewRefUpdate(cfg.Git, cfg.PushRemote(), cfg.CurrentRef(), nil)
lockClient := newLockClient()
lockClient.RemoteRef = refUpdate.RemoteRef()
defer lockClient.Close()
success := true
locks := make([]locking.Lock, 0, len(args))
for _, path := range args {
path, err := lockPath(lockData, path)
if err != nil {
Error(err.Error())
success = false
continue
}
lock, err := lockClient.LockFile(path)
if err != nil {
Error(tr.Tr.Get("Locking %s failed: %v", path, errors.Cause(err)))
success = false
continue
}
locks = append(locks, lock)
if locksCmdFlags.JSON {
continue
}
Print(tr.Tr.Get("Locked %s", path))
}
if locksCmdFlags.JSON {
if err := json.NewEncoder(os.Stdout).Encode(locks); err != nil {
Error(err.Error())
success = false
}
}
if !success {
lockClient.Close()
os.Exit(2)
}
}
type lockData struct {
rootDir string
workingDir string
}
// computeLockData computes data about the given repository and working
// directory to use in lockPath.
func computeLockData() (*lockData, error) {
wd, err := tools.Getwd()
if err != nil {
return nil, err
}
wd, err = tools.CanonicalizeSystemPath(wd)
if err != nil {
return nil, err
}
return &lockData{
rootDir: cfg.LocalWorkingDir(),
workingDir: wd,
}, nil
}
// lockPath relativizes the given filepath such that it is relative to the root
// path of the repository it is contained within, taking into account the
// working directory of the caller.
//
// lockPaths also respects different filesystem directory separators, so that a
// Windows path of "\foo\bar" will be normalized to "foo/bar".
//
// If the file path cannot be determined, an error will be returned. If the file
// in question is actually a directory, an error will be returned. Otherwise,
// the cleaned path will be returned.
//
// For example:
// - Working directory: /code/foo/bar/
// - Repository root: /code/foo/
// - File to lock: ./baz
// - Resolved path bar/baz
func lockPath(data *lockData, file string) (string, error) {
var abs string
var err error
if filepath.IsAbs(file) {
abs, err = tools.CanonicalizeSystemPath(file)
if err != nil {
return "", errors.New(tr.Tr.Get("unable to canonicalize path %q: %v", file, err))
}
} else {
abs = filepath.Join(data.workingDir, file)
}
path, err := filepath.Rel(data.rootDir, abs)
if err != nil {
return "", err
}
path = filepath.ToSlash(path)
if strings.HasPrefix(path, "../") {
return "", errors.New(tr.Tr.Get("unable to canonicalize path %q", path))
}
if stat, err := os.Stat(abs); err == nil && stat.IsDir() {
return path, errors.New(tr.Tr.Get("cannot lock directory: %s", file))
}
return filepath.ToSlash(path), nil
}
func init() {
RegisterCommand("lock", lockCommand, func(cmd *cobra.Command) {
cmd.Flags().StringVarP(&lockRemote, "remote", "r", "", "specify which remote to use when interacting with locks")
cmd.Flags().BoolVarP(&locksCmdFlags.JSON, "json", "", false, "print output in json")
})
}
|