2016-05-26 20:29:36 +00:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
2016-08-30 20:43:21 +00:00
|
|
|
"encoding/json"
|
|
|
|
"os"
|
2016-05-26 20:29:36 +00:00
|
|
|
|
2017-02-24 23:57:02 +00:00
|
|
|
"github.com/git-lfs/git-lfs/errors"
|
2017-01-30 16:49:56 +00:00
|
|
|
"github.com/git-lfs/git-lfs/git"
|
|
|
|
"github.com/git-lfs/git-lfs/locking"
|
2016-05-26 20:29:36 +00:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2016-05-27 22:26:15 +00:00
|
|
|
unlockCmdFlags unlockFlags
|
2016-05-26 20:29:36 +00:00
|
|
|
)
|
|
|
|
|
2016-05-27 22:26:15 +00:00
|
|
|
// unlockFlags holds the flags given to the `git lfs unlock` command
|
|
|
|
type unlockFlags struct {
|
|
|
|
// Id is the Id of the lock that is being unlocked.
|
|
|
|
Id string
|
|
|
|
// Force specifies whether or not the `lfs unlock` command was invoked
|
|
|
|
// with "--force", signifying the user's intent to break another
|
|
|
|
// individual's lock(s).
|
|
|
|
Force bool
|
|
|
|
}
|
|
|
|
|
2017-02-24 23:57:02 +00:00
|
|
|
var unlockUsage = "Usage: git lfs unlock (--id my-lock-id | <path>)"
|
|
|
|
|
2016-05-26 20:29:36 +00:00
|
|
|
func unlockCommand(cmd *cobra.Command, args []string) {
|
2017-02-27 02:34:56 +00:00
|
|
|
hasPath := len(args) > 0
|
|
|
|
hasId := len(unlockCmdFlags.Id) > 0
|
|
|
|
if hasPath == hasId {
|
|
|
|
// If there is both an `--id` AND a `<path>`, or there is
|
|
|
|
// neither, print the usage and quit.
|
|
|
|
Exit(unlockUsage)
|
2017-02-24 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2017-01-03 22:57:17 +00:00
|
|
|
lockClient := newLockClient(lockRemote)
|
2016-12-05 15:01:25 +00:00
|
|
|
defer lockClient.Close()
|
2017-01-03 21:13:59 +00:00
|
|
|
|
2017-02-27 21:21:59 +00:00
|
|
|
if hasPath {
|
2016-05-27 22:19:16 +00:00
|
|
|
path, err := lockPath(args[0])
|
2017-02-09 21:03:24 +00:00
|
|
|
if err != nil && !unlockCmdFlags.Force {
|
2016-11-28 15:12:47 +00:00
|
|
|
Exit("Unable to determine path: %v", err.Error())
|
2016-05-27 22:19:16 +00:00
|
|
|
}
|
|
|
|
|
2017-02-03 09:51:56 +00:00
|
|
|
// This call can early-out
|
2017-08-03 16:36:56 +00:00
|
|
|
unlockAbortIfFileModified(path, !os.IsNotExist(err))
|
2017-01-30 16:49:56 +00:00
|
|
|
|
2016-12-05 11:25:02 +00:00
|
|
|
err = lockClient.UnlockFile(path, unlockCmdFlags.Force)
|
2016-11-28 15:12:47 +00:00
|
|
|
if err != nil {
|
2017-02-24 23:57:02 +00:00
|
|
|
Exit("%s", errors.Cause(err))
|
2016-05-27 21:28:42 +00:00
|
|
|
}
|
2017-01-30 16:49:56 +00:00
|
|
|
|
2017-02-27 21:21:59 +00:00
|
|
|
if !locksCmdFlags.JSON {
|
|
|
|
Print("Unlocked %s", path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else if unlockCmdFlags.Id != "" {
|
2017-02-03 09:51:56 +00:00
|
|
|
// This call can early-out
|
|
|
|
unlockAbortIfFileModifiedById(unlockCmdFlags.Id, lockClient)
|
2017-01-30 16:49:56 +00:00
|
|
|
|
2016-12-05 11:25:02 +00:00
|
|
|
err := lockClient.UnlockFileById(unlockCmdFlags.Id, unlockCmdFlags.Force)
|
2016-11-28 15:12:47 +00:00
|
|
|
if err != nil {
|
2017-02-24 23:57:02 +00:00
|
|
|
Exit("Unable to unlock %v: %v", unlockCmdFlags.Id, errors.Cause(err))
|
2016-11-28 15:12:47 +00:00
|
|
|
}
|
2017-02-27 21:21:59 +00:00
|
|
|
|
|
|
|
if !locksCmdFlags.JSON {
|
|
|
|
Print("Unlocked Lock %s", unlockCmdFlags.Id)
|
|
|
|
return
|
|
|
|
}
|
2016-05-27 21:28:42 +00:00
|
|
|
} else {
|
2017-02-24 23:57:02 +00:00
|
|
|
Error(unlockUsage)
|
2016-05-26 20:29:36 +00:00
|
|
|
}
|
|
|
|
|
2017-02-27 21:21:59 +00:00
|
|
|
if err := json.NewEncoder(os.Stdout).Encode(struct {
|
|
|
|
Unlocked bool `json:"unlocked"`
|
|
|
|
}{true}); err != nil {
|
|
|
|
Error(err.Error())
|
2016-08-30 20:43:21 +00:00
|
|
|
}
|
2017-02-27 21:21:59 +00:00
|
|
|
return
|
2016-05-26 20:29:36 +00:00
|
|
|
}
|
|
|
|
|
2017-08-03 16:36:56 +00:00
|
|
|
func unlockAbortIfFileModified(path string, exists bool) {
|
2017-01-30 16:49:56 +00:00
|
|
|
modified, err := git.IsFileModified(path)
|
|
|
|
|
|
|
|
if err != nil {
|
2017-08-03 16:36:56 +00:00
|
|
|
if !exists && unlockCmdFlags.Force {
|
|
|
|
// Since git/git@b9a7d55, `git-status(1)` causes an
|
|
|
|
// error when asked about files that don't exist,
|
|
|
|
// causing `err != nil`, as above.
|
|
|
|
//
|
|
|
|
// Unlocking a files that does not exist with
|
|
|
|
// --force is OK.
|
|
|
|
return
|
|
|
|
}
|
2017-01-30 16:49:56 +00:00
|
|
|
Exit(err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
if modified {
|
|
|
|
if unlockCmdFlags.Force {
|
|
|
|
// Only a warning
|
|
|
|
Error("Warning: unlocking with uncommitted changes because --force")
|
|
|
|
} else {
|
|
|
|
Exit("Cannot unlock file with uncommitted changes")
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-03 09:51:56 +00:00
|
|
|
func unlockAbortIfFileModifiedById(id string, lockClient *locking.Client) {
|
2017-01-30 16:49:56 +00:00
|
|
|
// Get the path so we can check the status
|
|
|
|
filter := map[string]string{"id": id}
|
|
|
|
// try local cache first
|
|
|
|
locks, _ := lockClient.SearchLocks(filter, 0, true)
|
|
|
|
if len(locks) == 0 {
|
|
|
|
// Fall back on calling server
|
|
|
|
locks, _ = lockClient.SearchLocks(filter, 0, false)
|
|
|
|
}
|
|
|
|
|
2017-02-03 09:53:38 +00:00
|
|
|
if len(locks) == 0 {
|
|
|
|
// Don't block if we can't determine the path, may be cleaning up old data
|
|
|
|
return
|
2017-01-30 16:49:56 +00:00
|
|
|
}
|
|
|
|
|
2017-08-03 16:36:56 +00:00
|
|
|
unlockAbortIfFileModified(locks[0].Path, true)
|
2017-01-30 16:49:56 +00:00
|
|
|
}
|
|
|
|
|
2016-05-26 20:29:36 +00:00
|
|
|
func init() {
|
2016-09-01 16:09:38 +00:00
|
|
|
RegisterCommand("unlock", unlockCommand, func(cmd *cobra.Command) {
|
2016-08-10 15:33:25 +00:00
|
|
|
cmd.Flags().StringVarP(&lockRemote, "remote", "r", cfg.CurrentRemote, lockRemoteHelp)
|
|
|
|
cmd.Flags().StringVarP(&unlockCmdFlags.Id, "id", "i", "", "unlock a lock by its ID")
|
|
|
|
cmd.Flags().BoolVarP(&unlockCmdFlags.Force, "force", "f", false, "forcibly break another user's lock(s)")
|
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
|
|
|
}
|