Allow locking/unlocking of nonexistent files

If a file is renamed or removed, a lock can be obtained and released for that file even though it doesn't exist.

Updated tests to verify that a file that doesn't exist can be locked, a file that was locked an removed can be unlocked and a file that doesn't exist can be locked and unlocked.
This commit is contained in:
Matthew Versluys 2020-05-10 19:41:36 -07:00
parent 48b28d971c
commit 88e3e1b286
4 changed files with 41 additions and 18 deletions

@ -60,7 +60,7 @@ func lockCommand(cmd *cobra.Command, args []string) {
// Windows path of "\foo\bar" will be normalized to "foo/bar".
//
// If the root directory, working directory, or file cannot be
// determined/opened, an error will be returned. If the file in question is
// 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.
//
@ -96,15 +96,11 @@ func lockPath(file string) (string, error) {
return "", fmt.Errorf("lfs: unable to canonicalize path %q", path)
}
if stat, err := os.Stat(abs); err != nil {
return "", err
} else {
if stat.IsDir() {
if stat, err := os.Stat(abs); err == nil && stat.IsDir() {
return path, fmt.Errorf("lfs: cannot lock directory: %s", file)
}
return filepath.ToSlash(path), nil
}
}
func init() {

@ -125,9 +125,11 @@ func (c *Client) LockFile(path string) (Lock, error) {
return Lock{}, errors.Wrap(err, "make lockpath absolute")
}
// Ensure writeable on return
// If the file exists, ensure that it's writeable on return
if tools.FileExists(abs) {
if err := tools.SetFileWriteFlag(abs, true); err != nil {
return Lock{}, err
return Lock{}, errors.Wrap(err, "set file write flag")
}
}
return lock, nil

@ -100,6 +100,20 @@ begin_test "creating a lock (with output)"
)
end_test
begin_test "locking a file that doesn't exist"
(
set -e
reponame="lock_create_nonexistent"
setup_remote_repo_with_file "$reponame" "a_output.dat"
git lfs lock "b_output.dat" | tee lock.log
grep "Locked b_output.dat" lock.log
id=$(grep -oh "\((.*)\)" lock.log | tr -d \(\))
assert_server_lock "$reponame" "$id"
)
end_test
begin_test "locking a previously locked file"
(
set -e

@ -140,11 +140,11 @@ begin_test "unlocking a file ignores readonly"
)
end_test
begin_test "force unlocking lock with missing file"
begin_test "unlocking lock removed file"
(
set -e
reponame="force-unlock-missing-file"
reponame="unlock-removed-file"
setup_remote_repo_with_file "$reponame" "a.dat"
git lfs lock --json "a.dat" | tee lock.log
@ -156,12 +156,23 @@ begin_test "force unlocking lock with missing file"
rm *.log *.json # ensure clean git status
git status
git lfs unlock "a.dat" 2>&1 | tee unlock.log
grep "Unable to determine path" unlock.log
git lfs unlock --force "a.dat" 2>&1 | tee unlock.log
refute_server_lock "$reponame" "$id"
)
end_test
begin_test "unlocking nonexistent file"
(
set -e
reponame="unlock-nonexistent-file"
setup_remote_repo_with_file "$reponame" "a.dat"
git lfs lock --json "b.dat" | tee lock.log
id=$(assert_lock lock.log b.dat)
assert_server_lock "$reponame" "$id"
rm unlock.log
git lfs unlock --force "a.dat" 2>&1 | tee unlock.log
git lfs unlock --force "b.dat" 2>&1 | tee unlock.log
refute_server_lock "$reponame" "$id"
)
end_test