diff --git a/.travis.yml b/.travis.yml index c6d4263b..75ab7c47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,12 +3,12 @@ language: go matrix: include: - os: linux - go: 1.9.1 + go: 1.9 - os: linux go: tip - os: osx osx_image: xcode8.3 - go: 1.9.1 + go: 1.9 - os: osx osx_image: xcode8.3 go: tip diff --git a/README.md b/README.md index 198fc135..53301ab4 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,9 @@ Or download binaries from [GitHub releases](https://github.com/vim-volt/volt/rel ## Build environment -* Go 1.9.1 or higher **with [the patch for os.RemoveAll()](https://go-review.googlesource.com/c/go/+/62970) ([#1](https://github.com/vim-volt/go-volt/issues/1))** +* Go 1.9 or higher + * If you are on WSL (Windows Subsystem Linux), note that you need **[the patch for os.RemoveAll()](https://go-review.googlesource.com/c/go/+/62970) ([#1](https://github.com/vim-volt/go-volt/issues/1))** + * But it's a hassle, you can just download linux-386/amd64 binaries from [GitHub releases](https://github.com/vim-volt/volt/releases) :) ## Self upgrade diff --git a/cmd/build.go b/cmd/build.go index 700d176b..7831e3ef 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -26,17 +26,18 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/object" ) -type buildFlagsType struct { +var BuildModeInvalidType = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice + +func init() { + cmdMap["build"] = &buildCmd{} +} + +type buildCmd struct { helped bool full bool } -var buildFlags buildFlagsType - -var BuildModeInvalidType = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice -var ErrBuildModeType = "does not allow symlink, named pipe, socket, device" - -func init() { +func (cmd *buildCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -62,22 +63,17 @@ Description fmt.Println("Options") fs.PrintDefaults() fmt.Println() - buildFlags.helped = true + cmd.helped = true } - fs.BoolVar(&buildFlags.full, "full", false, "full build") - - cmdFlagSet["build"] = fs + fs.BoolVar(&cmd.full, "full", false, "full build") + return fs } -type buildCmd struct{} - -func Build(args []string) int { - cmd := buildCmd{} - +func (cmd *buildCmd) Run(args []string) int { // Parse args - fs := cmdFlagSet["build"] + fs := cmd.FlagSet() fs.Parse(args) - if buildFlags.helped { + if cmd.helped { return 0 } @@ -89,7 +85,7 @@ func Build(args []string) int { } defer transaction.Remove() - err = cmd.doBuild(buildFlags.full) + err = cmd.doBuild(cmd.full) if err != nil { logger.Error("Failed to build:", err.Error()) return 12 @@ -799,12 +795,8 @@ func (cmd *buildCmd) updateNonBareGitRepos(r *git.Repository, src, dst string, r continue } if file.Mode()&BuildModeInvalidType != 0 { - abspath := filepath.Join(src, file.Name()) - done <- actionReposResult{ - err: errors.New(ErrBuildModeType + ": " + abspath), - repos: repos, - } - return + // Currenly skip the invalid files... + continue } if !created[dst] { os.MkdirAll(dst, 0755) diff --git a/cmd/cmd.go b/cmd/cmd.go new file mode 100644 index 00000000..701c2652 --- /dev/null +++ b/cmd/cmd.go @@ -0,0 +1,22 @@ +package cmd + +import ( + "flag" + + "github.com/vim-volt/volt/logger" +) + +var cmdMap = make(map[string]Cmd) + +type Cmd interface { + Run(args []string) int + FlagSet() *flag.FlagSet +} + +func Run(subCmd string, args []string) int { + if self, exists := cmdMap[subCmd]; exists { + return self.Run(args) + } + logger.Error("Unknown command '" + subCmd + "'") + return 3 +} diff --git a/cmd/disable.go b/cmd/disable.go index a363ff3f..6072bfe1 100644 --- a/cmd/disable.go +++ b/cmd/disable.go @@ -10,13 +10,15 @@ import ( "github.com/vim-volt/volt/pathutil" ) -type disableFlagsType struct { - helped bool +func init() { + cmdMap["disable"] = &disableCmd{} } -var disableFlags disableFlagsType +type disableCmd struct { + helped bool +} -func init() { +func (cmd *disableCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -33,17 +35,12 @@ Description //fmt.Println("Options") //fs.PrintDefaults() fmt.Println() - disableFlags.helped = true + cmd.helped = true } - - cmdFlagSet["disable"] = fs + return fs } -type disableCmd struct{} - -func Disable(args []string) int { - cmd := disableCmd{} - +func (cmd *disableCmd) Run(args []string) int { reposPathList, err := cmd.parseArgs(args) if err == ErrShowedHelp { return 0 @@ -66,10 +63,10 @@ func Disable(args []string) int { return 0 } -func (*disableCmd) parseArgs(args []string) ([]string, error) { - fs := cmdFlagSet["disable"] +func (cmd *disableCmd) parseArgs(args []string) ([]string, error) { + fs := cmd.FlagSet() fs.Parse(args) - if disableFlags.helped { + if cmd.helped { return nil, ErrShowedHelp } diff --git a/cmd/enable.go b/cmd/enable.go index a8f8c78e..a52f04d3 100644 --- a/cmd/enable.go +++ b/cmd/enable.go @@ -10,13 +10,15 @@ import ( "github.com/vim-volt/volt/pathutil" ) -type enableFlagsType struct { - helped bool +func init() { + cmdMap["enable"] = &enableCmd{} } -var enableFlags enableFlagsType +type enableCmd struct { + helped bool +} -func init() { +func (cmd *enableCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -33,17 +35,12 @@ Description //fmt.Println("Options") //fs.PrintDefaults() fmt.Println() - enableFlags.helped = true + cmd.helped = true } - - cmdFlagSet["enable"] = fs + return fs } -type enableCmd struct{} - -func Enable(args []string) int { - cmd := enableCmd{} - +func (cmd *enableCmd) Run(args []string) int { reposPathList, err := cmd.parseArgs(args) if err == ErrShowedHelp { return 0 @@ -66,10 +63,10 @@ func Enable(args []string) int { return 0 } -func (*enableCmd) parseArgs(args []string) ([]string, error) { - fs := cmdFlagSet["enable"] +func (cmd *enableCmd) parseArgs(args []string) ([]string, error) { + fs := cmd.FlagSet() fs.Parse(args) - if enableFlags.helped { + if cmd.helped { return nil, ErrShowedHelp } diff --git a/cmd/get.go b/cmd/get.go index a9944e76..1a8f538f 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -22,16 +22,18 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband" ) -type getFlagsType struct { +func init() { + cmdMap["get"] = &getCmd{} +} + +type getCmd struct { helped bool lockJSON bool upgrade bool verbose bool } -var getFlags getFlagsType - -func init() { +func (cmd *getCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -102,22 +104,17 @@ Repository path Options`) fs.PrintDefaults() fmt.Println() - getFlags.helped = true + cmd.helped = true } - fs.BoolVar(&getFlags.lockJSON, "l", false, "use all installed repositories as targets") - fs.BoolVar(&getFlags.upgrade, "u", false, "upgrade repositories") - fs.BoolVar(&getFlags.verbose, "v", false, "output more verbosely") - - cmdFlagSet["get"] = fs + fs.BoolVar(&cmd.lockJSON, "l", false, "use all installed repositories as targets") + fs.BoolVar(&cmd.upgrade, "u", false, "upgrade repositories") + fs.BoolVar(&cmd.verbose, "v", false, "output more verbosely") + return fs } -type getCmd struct{} - -func Get(args []string) int { - cmd := getCmd{} - +func (cmd *getCmd) Run(args []string) int { // Parse args - args, flags, err := cmd.parseArgs(args) + args, err := cmd.parseArgs(args) if err == ErrShowedHelp { return 0 } @@ -133,7 +130,7 @@ func Get(args []string) int { return 11 } - reposPathList, err := cmd.getReposPathList(flags, args, lockJSON) + reposPathList, err := cmd.getReposPathList(args, lockJSON) if err != nil { logger.Error("Could not get repos list: " + err.Error()) return 12 @@ -143,7 +140,7 @@ func Get(args []string) int { return 13 } - err = cmd.doGet(reposPathList, flags, lockJSON) + err = cmd.doGet(reposPathList, lockJSON) if err != nil { logger.Error(err.Error()) return 20 @@ -152,24 +149,24 @@ func Get(args []string) int { return 0 } -func (*getCmd) parseArgs(args []string) ([]string, *getFlagsType, error) { - fs := cmdFlagSet["get"] +func (cmd *getCmd) parseArgs(args []string) ([]string, error) { + fs := cmd.FlagSet() fs.Parse(args) - if getFlags.helped { - return nil, nil, ErrShowedHelp + if cmd.helped { + return nil, ErrShowedHelp } - if !getFlags.lockJSON && len(fs.Args()) == 0 { + if !cmd.lockJSON && len(fs.Args()) == 0 { fs.Usage() - return nil, nil, errors.New("repository was not given") + return nil, errors.New("repository was not given") } - return fs.Args(), &getFlags, nil + return fs.Args(), nil } -func (*getCmd) getReposPathList(flags *getFlagsType, args []string, lockJSON *lockjson.LockJSON) ([]string, error) { +func (cmd *getCmd) getReposPathList(args []string, lockJSON *lockjson.LockJSON) ([]string, error) { reposPathList := make([]string, 0, 32) - if flags.lockJSON { + if cmd.lockJSON { for _, repos := range lockJSON.Repos { reposPathList = append(reposPathList, repos.Path) } @@ -185,7 +182,7 @@ func (*getCmd) getReposPathList(flags *getFlagsType, args []string, lockJSON *lo return reposPathList, nil } -func (cmd *getCmd) doGet(reposPathList []string, flags *getFlagsType, lockJSON *lockjson.LockJSON) error { +func (cmd *getCmd) doGet(reposPathList []string, lockJSON *lockjson.LockJSON) error { // Find matching profile profile, err := lockJSON.Profiles.FindByName(lockJSON.CurrentProfileName) if err != nil { @@ -211,7 +208,7 @@ func (cmd *getCmd) doGet(reposPathList []string, flags *getFlagsType, lockJSON * repos = nil } if repos == nil || repos.Type == lockjson.ReposGitType { - go cmd.getParallel(reposPath, repos, flags, done) + go cmd.getParallel(reposPath, repos, done) getCount++ } } @@ -308,11 +305,11 @@ const ( ) // This function is executed in goroutine of each plugin -func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, flags *getFlagsType, done chan getParallelResult) { +func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, done chan getParallelResult) { // true:upgrade, false:install fullReposPath := pathutil.FullReposPathOf(reposPath) - doUpgrade := flags.upgrade && pathutil.Exists(fullReposPath) + doUpgrade := cmd.upgrade && pathutil.Exists(fullReposPath) var fromHash string var err error @@ -321,7 +318,7 @@ func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, flags *g fromHash, err = getReposHEAD(reposPath) if err != nil { result := errors.New("failed to get HEAD commit hash: " + err.Error()) - if flags.verbose { + if cmd.verbose { logger.Info("Rollbacking " + fullReposPath + " ...") } else { logger.Debug("Rollbacking " + fullReposPath + " ...") @@ -343,7 +340,7 @@ func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, flags *g var upgraded bool if doUpgrade { - // when flags.upgrade is true, repos must not be nil. + // when cmd.upgrade is true, repos must not be nil. if repos == nil { msg := "-u was specified but repos == nil" done <- getParallelResult{ @@ -353,15 +350,15 @@ func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, flags *g } } // Upgrade plugin - if flags.verbose { + if cmd.verbose { logger.Info("Upgrading " + reposPath + " ...") } else { logger.Debug("Upgrading " + reposPath + " ...") } - err := cmd.upgradePlugin(reposPath, flags) + err := cmd.upgradePlugin(reposPath) if err != git.NoErrAlreadyUpToDate && err != nil { result := errors.New("failed to upgrade plugin: " + err.Error()) - if flags.verbose { + if cmd.verbose { logger.Info("Rollbacking " + fullReposPath + " ...") } else { logger.Debug("Rollbacking " + fullReposPath + " ...") @@ -384,16 +381,16 @@ func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, flags *g } } else if !pathutil.Exists(fullReposPath) { // Install plugin - if flags.verbose { + if cmd.verbose { logger.Info("Installing " + reposPath + " ...") } else { logger.Debug("Installing " + reposPath + " ...") } - err := cmd.installPlugin(reposPath, flags) + err := cmd.installPlugin(reposPath) // if err == errRepoExists, silently skip if err != nil && err != errRepoExists { result := errors.New("failed to install plugin: " + err.Error()) - if flags.verbose { + if cmd.verbose { logger.Info("Rollbacking " + fullReposPath + " ...") } else { logger.Debug("Rollbacking " + fullReposPath + " ...") @@ -413,7 +410,7 @@ func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, flags *g status = fmt.Sprintf(fmtAlreadyExists, statusPrefixNoChange, reposPath) } else { // Install plugconf - if flags.verbose { + if cmd.verbose { logger.Info("Installing plugconf " + reposPath + " ...") } else { logger.Debug("Installing plugconf " + reposPath + " ...") @@ -421,7 +418,7 @@ func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, flags *g err = cmd.installPlugconf(reposPath) if err != nil { result := errors.New("failed to install plugconf: " + err.Error()) - if flags.verbose { + if cmd.verbose { logger.Info("Rollbacking " + fullReposPath + " ...") } else { logger.Debug("Rollbacking " + fullReposPath + " ...") @@ -448,7 +445,7 @@ func (cmd *getCmd) getParallel(reposPath string, repos *lockjson.Repos, flags *g toHash, err = getReposHEAD(reposPath) if err != nil { result := errors.New("failed to get HEAD commit hash: " + err.Error()) - if flags.verbose { + if cmd.verbose { logger.Info("Rollbacking " + fullReposPath + " ...") } else { logger.Debug("Rollbacking " + fullReposPath + " ...") @@ -500,11 +497,11 @@ func (*getCmd) rollbackRepos(fullReposPath string) error { return nil } -func (cmd *getCmd) upgradePlugin(reposPath string, flags *getFlagsType) error { +func (cmd *getCmd) upgradePlugin(reposPath string) error { fullpath := pathutil.FullReposPathOf(reposPath) var progress sideband.Progress = nil - // if flags.verbose { + // if cmd.verbose { // progress = os.Stdout // } @@ -537,14 +534,14 @@ func (cmd *getCmd) upgradePlugin(reposPath string, flags *getFlagsType) error { var errRepoExists = errors.New("repository exists") -func (cmd *getCmd) installPlugin(reposPath string, flags *getFlagsType) error { +func (cmd *getCmd) installPlugin(reposPath string) error { fullpath := pathutil.FullReposPathOf(reposPath) if pathutil.Exists(fullpath) { return errRepoExists } var progress sideband.Progress = nil - // if flags.verbose { + // if cmd.verbose { // progress = os.Stdout // } diff --git a/cmd/help.go b/cmd/help.go index 242bb7b8..6e7eae58 100644 --- a/cmd/help.go +++ b/cmd/help.go @@ -4,47 +4,36 @@ import ( "errors" "flag" "fmt" + "os" "github.com/vim-volt/volt/logger" ) -var cmdFlagSet = make(map[string]*flag.FlagSet) - var ErrShowedHelp = errors.New("already showed help") -func Help(args []string) int { - if len(args) == 0 { - showHelp() - return 0 - } - if args[0] == "help" { // "volt help help" - fmt.Println("E478: Don't panic!") - return 0 - } - - if fs, exists := cmdFlagSet[args[0]]; exists { - fs.Usage() - return 0 - } else { - logger.Errorf("Unknown command '%s'", args[0]) - return 1 - } +func init() { + cmdMap["help"] = &helpCmd{} } -func showHelp() { - fmt.Print( - " .----------------. .----------------. .----------------. .----------------.\n" + - "| .--------------. || .--------------. || .--------------. || .--------------. |\n" + - "| | ____ ____ | || | ____ | || | _____ | || | _________ | |\n" + - "| ||_ _| |_ _| | || | .' `. | || | |_ _| | || | | _ _ | | |\n" + - "| | \\ \\ / / | || | / .--. \\ | || | | | | || | |_/ | | \\_| | |\n" + - "| | \\ \\ / / | || | | | | | | || | | | _ | || | | | | |\n" + - "| | \\ ' / | || | \\ `--' / | || | _| |__/ | | || | _| |_ | |\n" + - "| | \\_/ | || | `.____.' | || | |________| | || | |_____| | |\n" + - "| | | || | | || | | || | | |\n" + - "| '--------------' || '--------------' || '--------------' || '--------------' |\n" + - " '----------------' '----------------' '----------------' '----------------'\n" + - ` +type helpCmd struct{} + +func (cmd *helpCmd) FlagSet() *flag.FlagSet { + fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) + fs.SetOutput(os.Stdout) + fs.Usage = func() { + fmt.Print( + " .----------------. .----------------. .----------------. .----------------.\n" + + "| .--------------. || .--------------. || .--------------. || .--------------. |\n" + + "| | ____ ____ | || | ____ | || | _____ | || | _________ | |\n" + + "| ||_ _| |_ _| | || | .' `. | || | |_ _| | || | | _ _ | | |\n" + + "| | \\ \\ / / | || | / .--. \\ | || | | | | || | |_/ | | \\_| | |\n" + + "| | \\ \\ / / | || | | | | | | || | | | _ | || | | | | |\n" + + "| | \\ ' / | || | \\ `--' / | || | _| |__/ | | || | _| |_ | |\n" + + "| | \\_/ | || | `.____.' | || | |________| | || | |_____| | |\n" + + "| | | || | | || | | || | | |\n" + + "| '--------------' || '--------------' || '--------------' || '--------------' |\n" + + " '----------------' '----------------' '----------------' '----------------'\n" + + ` Usage volt COMMAND ARGS @@ -106,4 +95,26 @@ Command version Show volt command version` + "\n\n") + //cmd.helped = true + } + return fs +} + +func (cmd *helpCmd) Run(args []string) int { + if len(args) == 0 { + cmd.FlagSet().Usage() + return 0 + } + if args[0] == "help" { // "volt help help" + fmt.Println("E478: Don't panic!") + return 0 + } + + if fs, exists := cmdMap[args[0]]; exists { + fs.Run([]string{"-help"}) + return 0 + } else { + logger.Errorf("Unknown command '%s'", args[0]) + return 1 + } } diff --git a/cmd/list.go b/cmd/list.go index 6a7fe304..5009e12a 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -8,13 +8,15 @@ import ( "github.com/vim-volt/volt/logger" ) -type listFlagsType struct { - helped bool +func init() { + cmdMap["list"] = &listCmd{} } -var listFlags listFlagsType +type listCmd struct { + helped bool +} -func init() { +func (cmd *listCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -31,15 +33,12 @@ Description //fmt.Println("Options") //fs.PrintDefaults() fmt.Println() - listFlags.helped = true + cmd.helped = true } - - cmdFlagSet["list"] = fs + return fs } -type listCmd struct{} - -func List(args []string) int { +func (cmd *listCmd) Run(args []string) int { profCmd := profileCmd{} err := profCmd.doShow(append( []string{"-current"}, diff --git a/cmd/migrate.go b/cmd/migrate.go index b61bb6c0..a9751c9c 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -11,13 +11,15 @@ import ( "github.com/vim-volt/volt/transaction" ) -type migrateFlagsType struct { - helped bool +func init() { + cmdMap["migrate"] = &migrateCmd{} } -var migrateFlags migrateFlagsType +type migrateCmd struct { + helped bool +} -func init() { +func (cmd *migrateCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -32,17 +34,12 @@ Description //fmt.Println("Options") //fs.PrintDefaults() fmt.Println() - migrateFlags.helped = true + cmd.helped = true } - - cmdFlagSet["migrate"] = fs + return fs } -type migrateCmd struct{} - -func Migrate(args []string) int { - cmd := migrateCmd{} - +func (cmd *migrateCmd) Run(args []string) int { err := cmd.parseArgs(args) if err == ErrShowedHelp { return 0 @@ -61,10 +58,10 @@ func Migrate(args []string) int { return 0 } -func (*migrateCmd) parseArgs(args []string) error { - fs := cmdFlagSet["migrate"] +func (cmd *migrateCmd) parseArgs(args []string) error { + fs := cmd.FlagSet() fs.Parse(args) - if migrateFlags.helped { + if cmd.helped { return ErrShowedHelp } return nil diff --git a/cmd/profile.go b/cmd/profile.go index 888021af..1e2cf04f 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -13,28 +13,17 @@ import ( "github.com/vim-volt/volt/transaction" ) -type profileFlagsType struct { +type profileCmd struct { helped bool } -var profileFlags profileFlagsType - -type profileCmd struct{} - var profileSubCmd = make(map[string]func([]string) error) func init() { - cmd := profileCmd{} - profileSubCmd["set"] = cmd.doSet - profileSubCmd["show"] = cmd.doShow - profileSubCmd["list"] = cmd.doList - profileSubCmd["new"] = cmd.doNew - profileSubCmd["destroy"] = cmd.doDestroy - profileSubCmd["rename"] = cmd.doRename - profileSubCmd["add"] = cmd.doAdd - profileSubCmd["rm"] = cmd.doRm - profileSubCmd["use"] = cmd.doUse + cmdMap["profile"] = &profileCmd{} +} +func (cmd *profileCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -93,15 +82,12 @@ Quick example $ volt profile use -current vimrc false # Disable installing vimrc on current profile on "volt build" $ volt profile use default gvimrc true # Enable installing gvimrc on profile default on "volt build"` + "\n\n") - profileFlags.helped = true + cmd.helped = true } - - cmdFlagSet["profile"] = fs + return fs } -func Profile(args []string) int { - cmd := profileCmd{} - +func (cmd *profileCmd) Run(args []string) int { // Parse args args, err := cmd.parseArgs(args) if err == ErrShowedHelp { @@ -112,32 +98,49 @@ func Profile(args []string) int { return 10 } - if fn, exists := profileSubCmd[args[0]]; exists { - err = fn(args[1:]) - if err != nil { - logger.Error(err.Error()) - return 11 - } + subCmd := args[0] + switch subCmd { + case "set": + err = cmd.doSet(args[1:]) + case "show": + err = cmd.doShow(args[1:]) + case "list": + err = cmd.doList(args[1:]) + case "new": + err = cmd.doNew(args[1:]) + case "destroy": + err = cmd.doDestroy(args[1:]) + case "rename": + err = cmd.doRename(args[1:]) + case "add": + err = cmd.doAdd(args[1:]) + case "rm": + err = cmd.doRm(args[1:]) + case "use": + err = cmd.doUse(args[1:]) + default: + logger.Error("unknown subcommand: " + subCmd) + return 11 + } + + if err != nil { + logger.Error(err.Error()) + return 20 } return 0 } func (cmd *profileCmd) parseArgs(args []string) ([]string, error) { - fs := cmdFlagSet["profile"] + fs := cmd.FlagSet() fs.Parse(args) - if profileFlags.helped { + if cmd.helped { return nil, ErrShowedHelp } if len(fs.Args()) == 0 { return nil, errors.New("must specify subcommand: volt profile") } - - subCmd := fs.Args()[0] - if _, exists := profileSubCmd[subCmd]; !exists { - return nil, errors.New("unknown subcommand: " + subCmd) - } return fs.Args(), nil } @@ -151,7 +154,7 @@ func (*profileCmd) getCurrentProfile() (string, error) { func (cmd *profileCmd) doSet(args []string) error { if len(args) == 0 { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Error("'volt profile set' receives profile name.") return nil } @@ -203,7 +206,7 @@ func (cmd *profileCmd) doSet(args []string) error { func (cmd *profileCmd) doShow(args []string) error { if len(args) == 0 { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Error("'volt profile show' receives profile name.") return nil } @@ -263,7 +266,7 @@ func (cmd *profileCmd) doList(args []string) error { func (cmd *profileCmd) doNew(args []string) error { if len(args) == 0 { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Error("'volt profile new' receives profile name.") return nil } @@ -309,7 +312,7 @@ func (cmd *profileCmd) doNew(args []string) error { func (cmd *profileCmd) doDestroy(args []string) error { if len(args) == 0 { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Error("'volt profile destroy' receives profile name.") return nil } @@ -362,7 +365,7 @@ func (cmd *profileCmd) doDestroy(args []string) error { func (cmd *profileCmd) doRename(args []string) error { if len(args) != 2 { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Error("'volt profile rename' receives profile name.") return nil } @@ -507,7 +510,7 @@ func (cmd *profileCmd) doRm(args []string) error { func (cmd *profileCmd) parseAddArgs(lockJSON *lockjson.LockJSON, subCmd string, args []string) (string, []string, error) { if len(args) == 0 { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Errorf("'volt profile %s' receives profile name and one or more repositories.", subCmd) return "", nil, nil } @@ -561,17 +564,17 @@ func (*profileCmd) transactProfile(lockJSON *lockjson.LockJSON, profileName stri func (cmd *profileCmd) doUse(args []string) error { // Validate arguments if len(args) != 3 { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Error("'volt profile use' receives profile name, rc name, value.") return nil } if args[1] != "vimrc" && args[1] != "gvimrc" { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Error("volt profile use: Please specify \"vimrc\" or \"gvimrc\" to the 2nd argument") return nil } if args[2] != "true" && args[2] != "false" { - cmdFlagSet["profile"].Usage() + cmd.FlagSet().Usage() logger.Error("volt profile use: Please specify \"true\" or \"false\" to the 3rd argument") return nil } diff --git a/cmd/rm.go b/cmd/rm.go index be08e4c0..874519fd 100644 --- a/cmd/rm.go +++ b/cmd/rm.go @@ -16,15 +16,17 @@ import ( "github.com/vim-volt/volt/transaction" ) -type rmFlagsType struct { +func init() { + cmdMap["rm"] = &rmCmd{} +} + +type rmCmd struct { helped bool rmRepos bool rmPlugconf bool } -var rmFlags rmFlagsType - -func init() { +func (cmd *rmCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -49,20 +51,15 @@ Description //fmt.Println("Options") //fs.PrintDefaults() fmt.Println() - rmFlags.helped = true + cmd.helped = true } - fs.BoolVar(&rmFlags.rmRepos, "r", false, "remove also repository directories") - fs.BoolVar(&rmFlags.rmPlugconf, "p", false, "remove also plugconf files") - - cmdFlagSet["rm"] = fs + fs.BoolVar(&cmd.rmRepos, "r", false, "remove also repository directories") + fs.BoolVar(&cmd.rmPlugconf, "p", false, "remove also plugconf files") + return fs } -type rmCmd struct{} - -func Rm(args []string) int { - cmd := rmCmd{} - - reposPathList, flags, err := cmd.parseArgs(args) +func (cmd *rmCmd) Run(args []string) int { + reposPathList, err := cmd.parseArgs(args) if err == ErrShowedHelp { return 0 } @@ -71,7 +68,7 @@ func Rm(args []string) int { return 10 } - err = cmd.doRemove(reposPathList, flags) + err = cmd.doRemove(reposPathList) if err != nil { logger.Error("Failed to remove repository: " + err.Error()) return 11 @@ -87,30 +84,30 @@ func Rm(args []string) int { return 0 } -func (*rmCmd) parseArgs(args []string) ([]string, *rmFlagsType, error) { - fs := cmdFlagSet["rm"] +func (cmd *rmCmd) parseArgs(args []string) ([]string, error) { + fs := cmd.FlagSet() fs.Parse(args) - if rmFlags.helped { - return nil, nil, ErrShowedHelp + if cmd.helped { + return nil, ErrShowedHelp } if len(fs.Args()) == 0 { fs.Usage() - return nil, nil, errors.New("repository was not given") + return nil, errors.New("repository was not given") } var reposPathList []string for _, arg := range fs.Args() { reposPath, err := pathutil.NormalizeRepos(arg) if err != nil { - return nil, nil, err + return nil, err } reposPathList = append(reposPathList, reposPath) } - return reposPathList, &rmFlags, nil + return reposPathList, nil } -func (cmd *rmCmd) doRemove(reposPathList []string, flags *rmFlagsType) error { +func (cmd *rmCmd) doRemove(reposPathList []string) error { // Read lock.json lockJSON, err := lockjson.Read() if err != nil { @@ -140,7 +137,7 @@ func (cmd *rmCmd) doRemove(reposPathList []string, flags *rmFlagsType) error { removeCount := 0 for _, reposPath := range reposPathList { // Remove repository directory - if flags.rmRepos { + if cmd.rmRepos { fullReposPath := pathutil.FullReposPathOf(reposPath) if pathutil.Exists(fullReposPath) { if err = cmd.removeRepos(fullReposPath); err != nil { @@ -153,7 +150,7 @@ func (cmd *rmCmd) doRemove(reposPathList []string, flags *rmFlagsType) error { } // Remove plugconf file - if flags.rmPlugconf { + if cmd.rmPlugconf { plugconfPath := pathutil.PlugconfOf(reposPath) if pathutil.Exists(plugconfPath) { if err = cmd.removePlugconf(plugconfPath); err != nil { diff --git a/cmd/self_upgrade.go b/cmd/self_upgrade.go index 353aedc8..7f0c2314 100644 --- a/cmd/self_upgrade.go +++ b/cmd/self_upgrade.go @@ -19,14 +19,16 @@ import ( "github.com/vim-volt/volt/logger" ) -type selfUpgradeFlagsType struct { +func init() { + cmdMap["self-upgrade"] = &selfUpgradeCmd{} +} + +type selfUpgradeCmd struct { helped bool check bool } -var selfUpgradeFlags selfUpgradeFlagsType - -func init() { +func (cmd *selfUpgradeCmd) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) fs.SetOutput(os.Stdout) fs.Usage = func() { @@ -39,19 +41,14 @@ Description //fmt.Println("Options") //fs.PrintDefaults() fmt.Println() - selfUpgradeFlags.helped = true + cmd.helped = true } - fs.BoolVar(&selfUpgradeFlags.check, "check", false, "only checks the newer version is available") - - cmdFlagSet["self-upgrade"] = fs + fs.BoolVar(&cmd.check, "check", false, "only checks the newer version is available") + return fs } -type selfUpgradeCmd struct{} - -func SelfUpgrade(args []string) int { - cmd := selfUpgradeCmd{} - - flags, err := cmd.parseArgs(args) +func (cmd *selfUpgradeCmd) Run(args []string) int { + err := cmd.parseArgs(args) if err == ErrShowedHelp { return 0 } @@ -67,7 +64,7 @@ func SelfUpgrade(args []string) int { } } else { latestURL := "https://api.github.com/repos/vim-volt/volt/releases/latest" - if err = cmd.doSelfUpgrade(flags, latestURL); err != nil { + if err = cmd.doSelfUpgrade(latestURL); err != nil { logger.Error("Failed to self-upgrade: " + err.Error()) return 12 } @@ -76,13 +73,13 @@ func SelfUpgrade(args []string) int { return 0 } -func (*selfUpgradeCmd) parseArgs(args []string) (*selfUpgradeFlagsType, error) { - fs := cmdFlagSet["self-upgrade"] +func (cmd *selfUpgradeCmd) parseArgs(args []string) error { + fs := cmd.FlagSet() fs.Parse(args) - if selfUpgradeFlags.helped { - return nil, ErrShowedHelp + if cmd.helped { + return ErrShowedHelp } - return &selfUpgradeFlags, nil + return nil } func (cmd *selfUpgradeCmd) doCleanUp(ppidStr string) error { @@ -135,9 +132,9 @@ type releaseAsset struct { Name string `json:"name"` } -func (cmd *selfUpgradeCmd) doSelfUpgrade(flags *selfUpgradeFlagsType, latestURL string) error { - // Check the latest binary - release, err := cmd.check(latestURL) +func (cmd *selfUpgradeCmd) doSelfUpgrade(latestURL string) error { + // Check the latest binary info + release, err := cmd.checkLatest(latestURL) if err != nil { return err } @@ -157,7 +154,7 @@ func (cmd *selfUpgradeCmd) doSelfUpgrade(flags *selfUpgradeFlagsType, latestURL fmt.Println(release.Body) fmt.Println("---") - if flags.check { + if cmd.check { return nil } @@ -166,15 +163,14 @@ func (cmd *selfUpgradeCmd) doSelfUpgrade(flags *selfUpgradeFlagsType, latestURL if err != nil { return err } - { - latestFile, err := os.OpenFile(voltExe+".latest", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777) - if err != nil { - return err - } - defer latestFile.Close() - if err = cmd.download(latestFile, release); err != nil { - return err - } + latestFile, err := os.OpenFile(voltExe+".latest", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777) + if err != nil { + return err + } + err = cmd.download(latestFile, release) + latestFile.Close() + if err != nil { + return err } // Rename dir/volt[.exe] to dir/volt[.exe].old @@ -204,7 +200,7 @@ func (*selfUpgradeCmd) getExecutablePath() (string, error) { return filepath.EvalSymlinks(exe) } -func (*selfUpgradeCmd) check(url string) (*latestRelease, error) { +func (*selfUpgradeCmd) checkLatest(url string) (*latestRelease, error) { content, err := httputil.GetContent(url) if err != nil { return nil, err diff --git a/cmd/version.go b/cmd/version.go index 51c8d0ee..38d4d751 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -2,16 +2,49 @@ package cmd import ( "errors" + "flag" "fmt" + "os" "regexp" "strconv" ) -var voltVersion string = "v0.2.1" +var voltVersion string = "v0.2.2" -func Version(args []string) int { - fmt.Printf("volt version: %s\n", voltVersion) +func init() { + cmdMap["version"] = &versionCmd{} +} + +type versionCmd struct { + helped bool +} + +func (cmd *versionCmd) FlagSet() *flag.FlagSet { + fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError) + fs.SetOutput(os.Stdout) + fs.Usage = func() { + fmt.Print(` +Usage + volt version [-help] +Description + Show current version of volt.` + "\n\n") + //fmt.Println("Options") + //fs.PrintDefaults() + fmt.Println() + cmd.helped = true + } + return fs +} + +func (cmd *versionCmd) Run(args []string) int { + fs := cmd.FlagSet() + fs.Parse(args) + if cmd.helped { + return 0 + } + + fmt.Printf("volt version: %s\n", voltVersion) return 0 } diff --git a/fileutil/copydir.go b/fileutil/copydir.go index 43485fd6..f0047b43 100644 --- a/fileutil/copydir.go +++ b/fileutil/copydir.go @@ -10,7 +10,7 @@ import ( // CopyDir recursively copies a directory tree, attempting to preserve permissions. // Source directory must exist, destination directory must *not* exist. -func CopyDir(src, dst string, buf []byte, perm os.FileMode, invalidType os.FileMode) error { +func CopyDir(src, dst string, buf []byte, perm os.FileMode, ignoreType os.FileMode) error { if err := os.MkdirAll(dst, perm); err != nil { return err } @@ -26,15 +26,15 @@ func CopyDir(src, dst string, buf []byte, perm os.FileMode, invalidType os.FileM } for i := range entries { - if entries[i].Mode()&invalidType != 0 { - return newInvalidType(entries[i].Name()) + if entries[i].Mode()&ignoreType != 0 { + continue } srcPath := filepath.Join(src, entries[i].Name()) dstPath := filepath.Join(dst, entries[i].Name()) if entries[i].IsDir() { - if err = CopyDir(srcPath, dstPath, buf, entries[i].Mode(), invalidType); err != nil { + if err = CopyDir(srcPath, dstPath, buf, entries[i].Mode(), ignoreType); err != nil { return err } } else { diff --git a/fileutil/link.go b/fileutil/link.go index 376d1499..5154e878 100644 --- a/fileutil/link.go +++ b/fileutil/link.go @@ -8,7 +8,7 @@ import ( // TryLinkDir recursively copies a directory tree, attempting to preserve permissions. // Source directory must exist, destination directory must *not* exist. -func TryLinkDir(src, dst string, buf []byte, perm os.FileMode, invalidType os.FileMode) error { +func TryLinkDir(src, dst string, buf []byte, perm os.FileMode, ignoreType os.FileMode) error { if err := os.MkdirAll(dst, perm); err != nil { return err } @@ -23,15 +23,15 @@ func TryLinkDir(src, dst string, buf []byte, perm os.FileMode, invalidType os.Fi } for i := range entries { - if entries[i].Mode()&invalidType != 0 { - return newInvalidType(entries[i].Name()) + if entries[i].Mode()&ignoreType != 0 { + continue } srcPath := filepath.Join(src, entries[i].Name()) dstPath := filepath.Join(dst, entries[i].Name()) if entries[i].IsDir() { - if err = TryLinkDir(srcPath, dstPath, buf, entries[i].Mode(), invalidType); err != nil { + if err = TryLinkDir(srcPath, dstPath, buf, entries[i].Mode(), ignoreType); err != nil { return err } } else { diff --git a/main.go b/main.go index 5c5b083f..9ef79bb3 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,5 @@ +// +build go1.9 + package main import ( @@ -18,31 +20,5 @@ func Main() int { if len(os.Args) <= 1 { os.Args = append(os.Args, "help") } - switch os.Args[1] { - case "get": - return cmd.Get(os.Args[2:]) - case "rm": - return cmd.Rm(os.Args[2:]) - case "enable": - return cmd.Enable(os.Args[2:]) - case "disable": - return cmd.Disable(os.Args[2:]) - case "list": - return cmd.List(os.Args[2:]) - case "profile": - return cmd.Profile(os.Args[2:]) - case "build": - return cmd.Build(os.Args[2:]) - case "migrate": - return cmd.Migrate(os.Args[2:]) - case "self-upgrade": - return cmd.SelfUpgrade(os.Args[2:]) - case "version": - return cmd.Version(os.Args[2:]) - case "help": - return cmd.Help(os.Args[2:]) - default: - logger.Error("Unknown command '" + os.Args[1] + "'") - return 3 - } + return cmd.Run(os.Args[1], os.Args[2:]) }