2016-05-26 20:29:36 +00:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
2016-08-30 20:43:21 +00:00
|
|
|
"encoding/json"
|
2016-05-27 22:19:16 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2019-03-12 18:19:20 +00:00
|
|
|
"strings"
|
2016-05-27 22:19:16 +00:00
|
|
|
|
2021-09-01 19:41:10 +00:00
|
|
|
"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"
|
2021-12-13 18:36:54 +00:00
|
|
|
"github.com/git-lfs/git-lfs/v3/tr"
|
2016-05-26 20:29:36 +00:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2021-12-13 18:49:04 +00:00
|
|
|
lockRemote string
|
2016-05-26 20:29:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func lockCommand(cmd *cobra.Command, args []string) {
|
2017-10-27 21:07:32 +00:00
|
|
|
if len(lockRemote) > 0 {
|
|
|
|
cfg.SetRemote(lockRemote)
|
|
|
|
}
|
|
|
|
|
2018-01-05 22:22:25 +00:00
|
|
|
refUpdate := git.NewRefUpdate(cfg.Git, cfg.PushRemote(), cfg.CurrentRef(), nil)
|
2017-10-27 21:07:32 +00:00
|
|
|
lockClient := newLockClient()
|
commands,git,lfs: rename left/right RefUpdate vars
Since at least PR #2706, and indeed earlier, the local and remote
refs which are part of the RefUpdate structure have been referred
to as the "left" and "right" refs, terminology which stems from
the origin of this structure in the "git lfs pre-push" hook command,
where each line of input contains commit information in the form:
<local ref> <local sha1> <remote ref> <remote sha1>
However, outside of this context, "left" and "right" are ambiguous
terms, and may potentially be confused with the left and right
refs specified in a Git-style two-dot range notation. We therefore
replace these terms with "local" and "remote", which should help
clarify their purpose throughout the codebase.
2022-02-07 03:09:53 +00:00
|
|
|
lockClient.RemoteRef = refUpdate.RemoteRef()
|
2016-12-05 15:01:25 +00:00
|
|
|
defer lockClient.Close()
|
2017-01-03 21:13:59 +00:00
|
|
|
|
2021-07-22 13:35:29 +00:00
|
|
|
success := true
|
|
|
|
locks := make([]locking.Lock, 0, len(args))
|
|
|
|
for _, path := range args {
|
|
|
|
path, err := lockPath(path)
|
|
|
|
if err != nil {
|
|
|
|
Error(err.Error())
|
|
|
|
success = false
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
lock, err := lockClient.LockFile(path)
|
|
|
|
if err != nil {
|
2021-12-13 18:36:54 +00:00
|
|
|
Error(tr.Tr.Get("Locking %s failed: %v", path, errors.Cause(err)))
|
2021-07-22 13:35:29 +00:00
|
|
|
success = false
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
locks = append(locks, lock)
|
|
|
|
|
|
|
|
if locksCmdFlags.JSON {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-12-13 18:36:54 +00:00
|
|
|
Print(tr.Tr.Get("Locked %s", path))
|
2016-05-26 20:29:36 +00:00
|
|
|
}
|
|
|
|
|
2016-08-30 20:43:21 +00:00
|
|
|
if locksCmdFlags.JSON {
|
2021-07-22 13:35:29 +00:00
|
|
|
if err := json.NewEncoder(os.Stdout).Encode(locks); err != nil {
|
2016-08-30 20:43:21 +00:00
|
|
|
Error(err.Error())
|
2021-07-22 13:35:29 +00:00
|
|
|
success = false
|
2016-08-30 20:43:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 13:35:29 +00:00
|
|
|
if !success {
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
2016-05-26 20:29:36 +00:00
|
|
|
}
|
|
|
|
|
2016-06-04 17:25:02 +00:00
|
|
|
// lockPaths 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.
|
|
|
|
//
|
2017-04-07 14:54:59 +00:00
|
|
|
// lockPaths also respects different filesystem directory separators, so that a
|
|
|
|
// Windows path of "\foo\bar" will be normalized to "foo/bar".
|
|
|
|
//
|
2016-06-04 17:25:02 +00:00
|
|
|
// If the root directory, working directory, or file cannot be
|
2020-05-11 02:41:36 +00:00
|
|
|
// determined, an error will be returned. If the file in question is
|
2016-06-04 17:25:02 +00:00
|
|
|
// actually a directory, an error will be returned. Otherwise, the cleaned path
|
|
|
|
// will be returned.
|
|
|
|
//
|
|
|
|
// For example:
|
2022-09-26 01:15:31 +00:00
|
|
|
// - Working directory: /code/foo/bar/
|
|
|
|
// - Repository root: /code/foo/
|
|
|
|
// - File to lock: ./baz
|
|
|
|
// - Resolved path bar/baz
|
2016-05-27 22:19:16 +00:00
|
|
|
func lockPath(file string) (string, error) {
|
|
|
|
repo, err := git.RootDir()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
wd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2021-03-01 16:30:19 +00:00
|
|
|
wd, err = tools.CanonicalizeSystemPath(wd)
|
2018-05-04 22:03:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", errors.Wrapf(err,
|
2021-12-13 18:36:54 +00:00
|
|
|
tr.Tr.Get("could not follow symlinks for %s", wd))
|
2018-05-04 22:03:35 +00:00
|
|
|
}
|
2016-05-27 22:19:16 +00:00
|
|
|
|
2021-06-17 13:25:46 +00:00
|
|
|
var abs string
|
|
|
|
if filepath.IsAbs(file) {
|
|
|
|
abs, err = tools.CanonicalizeSystemPath(file)
|
|
|
|
if err != nil {
|
2022-01-26 07:47:36 +00:00
|
|
|
return "", errors.New(tr.Tr.Get("unable to canonicalize path %q: %v", file, err))
|
2021-06-17 13:25:46 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
abs = filepath.Join(wd, file)
|
|
|
|
}
|
2018-09-21 14:47:08 +00:00
|
|
|
path, err := filepath.Rel(repo, abs)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
path = filepath.ToSlash(path)
|
2019-03-12 18:19:20 +00:00
|
|
|
if strings.HasPrefix(path, "../") {
|
2022-01-26 07:47:36 +00:00
|
|
|
return "", errors.New(tr.Tr.Get("unable to canonicalize path %q", path))
|
2019-03-12 18:19:20 +00:00
|
|
|
}
|
2018-09-21 14:47:08 +00:00
|
|
|
|
2020-05-11 02:41:36 +00:00
|
|
|
if stat, err := os.Stat(abs); err == nil && stat.IsDir() {
|
2022-01-26 07:47:36 +00:00
|
|
|
return path, errors.New(tr.Tr.Get("cannot lock directory: %s", file))
|
2016-06-04 17:25:02 +00:00
|
|
|
}
|
2020-05-11 02:41:36 +00:00
|
|
|
|
|
|
|
return filepath.ToSlash(path), nil
|
2016-05-27 22:19:16 +00:00
|
|
|
}
|
|
|
|
|
2016-05-26 20:29:36 +00:00
|
|
|
func init() {
|
2016-09-01 16:09:38 +00:00
|
|
|
RegisterCommand("lock", lockCommand, func(cmd *cobra.Command) {
|
2021-12-13 18:36:54 +00:00
|
|
|
cmd.Flags().StringVarP(&lockRemote, "remote", "r", "", "specify which remote to use when interacting with locks")
|
2016-08-30 20:43:21 +00:00
|
|
|
cmd.Flags().BoolVarP(&locksCmdFlags.JSON, "json", "", false, "print output in json")
|
2016-08-10 15:33:25 +00:00
|
|
|
})
|
2016-05-26 20:29:36 +00:00
|
|
|
}
|