lock: allow locking multiple files

Since it's useful to be able to lock multiple files, let's add this
functionality.  We iterate over each path provided and attempt to lock
it.  If we're using JSON, we report all successful locks at the end;
otherwise, we report all successful locks as we process them.  All
errors are reported to standard error immediately, and we additionally
exit 2 on failure.

Note that this causes an incompatible change to the JSON output, since
we now always output an array of locks.
This commit is contained in:
brian m. carlson 2021-07-22 13:35:29 +00:00
parent 4b3dc46f6c
commit a0aa09d1b6
No known key found for this signature in database
GPG Key ID: 2D0C9BC12F82B3A1
2 changed files with 55 additions and 18 deletions

@ -9,6 +9,7 @@ import (
"github.com/git-lfs/git-lfs/v2/errors"
"github.com/git-lfs/git-lfs/v2/git"
"github.com/git-lfs/git-lfs/v2/locking"
"github.com/git-lfs/git-lfs/v2/tools"
"github.com/spf13/cobra"
)
@ -19,15 +20,6 @@ var (
)
func lockCommand(cmd *cobra.Command, args []string) {
if len(args) != 1 {
Exit("Usage: git lfs lock <path>")
}
path, err := lockPath(args[0])
if err != nil {
Exit(err.Error())
}
if len(lockRemote) > 0 {
cfg.SetRemote(lockRemote)
}
@ -37,19 +29,42 @@ func lockCommand(cmd *cobra.Command, args []string) {
lockClient.RemoteRef = refUpdate.Right()
defer lockClient.Close()
lock, err := lockClient.LockFile(path)
if err != nil {
Exit("Lock failed: %v", errors.Cause(err))
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 {
Error("Locking %s failed: %v", path, errors.Cause(err))
success = false
continue
}
locks = append(locks, lock)
if locksCmdFlags.JSON {
continue
}
Print("Locked %s", path)
}
if locksCmdFlags.JSON {
if err := json.NewEncoder(os.Stdout).Encode(lock); err != nil {
if err := json.NewEncoder(os.Stdout).Encode(locks); err != nil {
Error(err.Error())
success = false
}
return
}
Print("Locked %s", path)
if !success {
os.Exit(2)
}
}
// lockPaths relativizes the given filepath such that it is relative to the root

@ -70,7 +70,7 @@ begin_test "lock with bad ref"
exit 1
fi
grep 'Lock failed: Expected ref "refs/heads/other", got "refs/heads/main"' lock.json
grep 'Locking a.dat failed: Expected ref "refs/heads/other", got "refs/heads/main"' lock.json
)
end_test
@ -89,9 +89,31 @@ begin_test "lock multiple files"
git commit -m "add dat files"
git push origin main:other
git lfs lock *.dat >log 2>&1 && exit 1
GIT_TRACE=0 git lfs lock *.dat >log 2>errlog
[ $(grep -c "Locked [ab].dat" log) -eq 2 ]
grep -v CREDS errlog && exit 1
grep "Usage:" errlog && exit 1
true
)
end_test
grep "Usage:" log
begin_test "lock multiple files (JSON)"
(
set -e
reponame="lock-multiple-files-json"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "a" > a.dat
echo "b" > b.dat
git add .gitattributes a.dat b.dat
git commit -m "add dat files"
git push origin main:other
git lfs lock --json *.dat | tee lock.json
grep -E '\[{"id":"[^"]+","path":"a\.dat","owner":{"name":"Git LFS Tests"},"locked_at":"[^"]+"},{"id":"[^"]+","path":"b\.dat","owner":{"name":"Git LFS Tests"},"locked_at":"[^"]+"}\]' lock.json
)
end_test