diff --git a/command.go b/command.go index 1ed94b8..5490480 100644 --- a/command.go +++ b/command.go @@ -68,15 +68,16 @@ func processCmd(params []string, dir string, conf *config, flags int) error { cmdArgs = args[1:] } - cmd := exec.Command(cmdName, cmdArgs...) - cmd.Dir = dir - cmd.Stderr = os.Stderr - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - if flags&flagVerbose != 0 { log.Printf("executing command: %s %s", cmdName, strings.Join(cmdArgs, " ")) } - return cmd.Run() + return try(func() error { + cmd := exec.Command(cmdName, cmdArgs...) + cmd.Dir = dir + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + cmd.Stdin = os.Stdin + return cmd.Run() + }) } diff --git a/link.go b/link.go index b112735..418d4b2 100644 --- a/link.go +++ b/link.go @@ -32,15 +32,8 @@ import ( func cleanPath(loc string, flags int) error { if info, _ := os.Lstat(loc); info != nil { - if info.Mode()&os.ModeSymlink != 0 { - if flags&flagVerbose != 0 { - log.Printf("removing symlink: %s", loc) - } - if err := os.Remove(loc); err != nil { - return err - } - } else { - if flags&flagClobber != 0 { + if info.Mode()&os.ModeSymlink == 0 { + if flags&flagClobber != 0 || prompt("clobber path", loc) { if flags&flagVerbose != 0 { log.Printf("clobbering path: %s", loc) } @@ -48,6 +41,13 @@ func cleanPath(loc string, flags int) error { return err } } + } else { + if flags&flagVerbose != 0 { + log.Printf("removing symlink: %s", loc) + } + if err := os.Remove(loc); err != nil { + return err + } } } @@ -55,9 +55,10 @@ func cleanPath(loc string, flags int) error { } func createPath(loc string, flags int, mode os.FileMode) error { - if flags&flagForce != 0 { - parentDir, _ := path.Split(loc) - if _, err := os.Stat(parentDir); os.IsNotExist(err) { + parentDir := path.Dir(loc) + + if _, err := os.Stat(parentDir); os.IsNotExist(err) { + if flags&flagForce != 0 || prompt("force create path", parentDir) { if flags&flagVerbose != 0 { log.Printf("force creating path: %s", parentDir) } @@ -118,11 +119,11 @@ func processLink(params []string, srcDir, dstDir string, flags int) error { return fmt.Errorf("source path %s does not exist in filesystem", srcPathAbs) } - if err := createPath(dstPathAbs, flags, mode); err != nil { + if err := try(func() error { return createPath(dstPathAbs, flags, mode) }); err != nil { return err } - if err := cleanPath(dstPathAbs, flags); err != nil { + if err := try(func() error { return cleanPath(dstPathAbs, flags) }); err != nil { return err } @@ -130,9 +131,7 @@ func processLink(params []string, srcDir, dstDir string, flags int) error { log.Printf("linking %s to %s", srcPathAbs, dstPathAbs) } - if err := os.Symlink(srcPathAbs, dstPathAbs); err != nil { - return err - } - - return nil + return try(func() error { + return os.Symlink(srcPathAbs, dstPathAbs) + }) } diff --git a/util.go b/util.go index ec03f53..e977894 100644 --- a/util.go +++ b/util.go @@ -23,9 +23,11 @@ package main import ( + "fmt" "log" "os" "path/filepath" + "strings" ) func appendExpEnv(dst, src []string) []string { @@ -44,3 +46,45 @@ func makeAbsPath(path string) string { return path } + +func prompt(prompts ...string) bool { + for { + fmt.Printf("%s: [y]es, [n]o? ", strings.Join(prompts, " ")) + + var ans string + fmt.Scanln(&ans) + + switch strings.ToLower(ans) { + case "y": + return true + case "n": + return false + } + } +} + +func try(task func() error) error { + for { + err := task() + if err == nil { + return nil + } + + loop: + for { + fmt.Printf("%s: [a]bort, [r]etry, [c]ancel? ", err) + + var ans string + fmt.Scanln(&ans) + + switch strings.ToLower(ans) { + case "a": + return err + case "r": + break loop + case "c": + return nil + } + } + } +}