github.com/stffabi/git-lfs@v2.3.5-0.20180214015214-8eeaa8d88902+incompatible/commands/command_unlock.go (about) 1 package commands 2 3 import ( 4 "encoding/json" 5 "os" 6 7 "github.com/git-lfs/git-lfs/errors" 8 "github.com/git-lfs/git-lfs/git" 9 "github.com/git-lfs/git-lfs/locking" 10 "github.com/spf13/cobra" 11 ) 12 13 var ( 14 unlockCmdFlags unlockFlags 15 ) 16 17 // unlockFlags holds the flags given to the `git lfs unlock` command 18 type unlockFlags struct { 19 // Id is the Id of the lock that is being unlocked. 20 Id string 21 // Force specifies whether or not the `lfs unlock` command was invoked 22 // with "--force", signifying the user's intent to break another 23 // individual's lock(s). 24 Force bool 25 } 26 27 var unlockUsage = "Usage: git lfs unlock (--id my-lock-id | <path>)" 28 29 func unlockCommand(cmd *cobra.Command, args []string) { 30 hasPath := len(args) > 0 31 hasId := len(unlockCmdFlags.Id) > 0 32 if hasPath == hasId { 33 // If there is both an `--id` AND a `<path>`, or there is 34 // neither, print the usage and quit. 35 Exit(unlockUsage) 36 } 37 38 if len(lockRemote) > 0 { 39 cfg.SetRemote(lockRemote) 40 } 41 42 refUpdate := git.NewRefUpdate(cfg.Git, cfg.PushRemote(), cfg.CurrentRef(), nil) 43 lockClient := newLockClient() 44 lockClient.RemoteRef = refUpdate.Right() 45 defer lockClient.Close() 46 47 if hasPath { 48 path, err := lockPath(args[0]) 49 if err != nil { 50 if !unlockCmdFlags.Force { 51 Exit("Unable to determine path: %v", err.Error()) 52 } 53 path = args[0] 54 } 55 56 // This call can early-out 57 unlockAbortIfFileModified(path, !os.IsNotExist(err)) 58 59 err = lockClient.UnlockFile(path, unlockCmdFlags.Force) 60 if err != nil { 61 Exit("%s", errors.Cause(err)) 62 } 63 64 if !locksCmdFlags.JSON { 65 Print("Unlocked %s", path) 66 return 67 } 68 } else if unlockCmdFlags.Id != "" { 69 // This call can early-out 70 unlockAbortIfFileModifiedById(unlockCmdFlags.Id, lockClient) 71 72 err := lockClient.UnlockFileById(unlockCmdFlags.Id, unlockCmdFlags.Force) 73 if err != nil { 74 Exit("Unable to unlock %v: %v", unlockCmdFlags.Id, errors.Cause(err)) 75 } 76 77 if !locksCmdFlags.JSON { 78 Print("Unlocked Lock %s", unlockCmdFlags.Id) 79 return 80 } 81 } else { 82 Error(unlockUsage) 83 } 84 85 if err := json.NewEncoder(os.Stdout).Encode(struct { 86 Unlocked bool `json:"unlocked"` 87 }{true}); err != nil { 88 Error(err.Error()) 89 } 90 return 91 } 92 93 func unlockAbortIfFileModified(path string, exists bool) { 94 modified, err := git.IsFileModified(path) 95 96 if err != nil { 97 if !exists && unlockCmdFlags.Force { 98 // Since git/git@b9a7d55, `git-status(1)` causes an 99 // error when asked about files that don't exist, 100 // causing `err != nil`, as above. 101 // 102 // Unlocking a files that does not exist with 103 // --force is OK. 104 return 105 } 106 Exit(err.Error()) 107 } 108 109 if modified { 110 if unlockCmdFlags.Force { 111 // Only a warning 112 Error("Warning: unlocking with uncommitted changes because --force") 113 } else { 114 Exit("Cannot unlock file with uncommitted changes") 115 } 116 117 } 118 } 119 120 func unlockAbortIfFileModifiedById(id string, lockClient *locking.Client) { 121 // Get the path so we can check the status 122 filter := map[string]string{"id": id} 123 // try local cache first 124 locks, _ := lockClient.SearchLocks(filter, 0, true) 125 if len(locks) == 0 { 126 // Fall back on calling server 127 locks, _ = lockClient.SearchLocks(filter, 0, false) 128 } 129 130 if len(locks) == 0 { 131 // Don't block if we can't determine the path, may be cleaning up old data 132 return 133 } 134 135 unlockAbortIfFileModified(locks[0].Path, true) 136 } 137 138 func init() { 139 RegisterCommand("unlock", unlockCommand, func(cmd *cobra.Command) { 140 cmd.Flags().StringVarP(&lockRemote, "remote", "r", "", lockRemoteHelp) 141 cmd.Flags().StringVarP(&unlockCmdFlags.Id, "id", "i", "", "unlock a lock by its ID") 142 cmd.Flags().BoolVarP(&unlockCmdFlags.Force, "force", "f", false, "forcibly break another user's lock(s)") 143 cmd.Flags().BoolVarP(&locksCmdFlags.JSON, "json", "", false, "print output in json") 144 }) 145 }