From e4757455f6f6583e4916182dce7757a0a3438f24 Mon Sep 17 00:00:00 2001 From: nexustar Date: Mon, 18 Apr 2022 12:36:03 +0800 Subject: [PATCH] tiup: refactor help (#1831) --- cmd/help.go | 148 ----------------------------------- cmd/root.go | 123 +++++++++++++++-------------- pkg/repository/repository.go | 1 - 3 files changed, 61 insertions(+), 211 deletions(-) delete mode 100644 cmd/help.go diff --git a/cmd/help.go b/cmd/help.go deleted file mode 100644 index da6bf175d7..0000000000 --- a/cmd/help.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2020 PingCAP, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/pingcap/tiup/pkg/environment" - "github.com/pingcap/tiup/pkg/localdata" - "github.com/pingcap/tiup/pkg/utils" - "github.com/spf13/cobra" -) - -func newHelpCmd() *cobra.Command { - return &cobra.Command{ - Use: "help [command]", - Short: "Help about any command or component", - Long: `Help provides help for any command or component in the application. -Simply type tiup help | for full details.`, - Run: func(cmd *cobra.Command, args []string) { - env := environment.GlobalEnv() - cmd, n, e := cmd.Root().Find(args) - if (cmd == rootCmd || e != nil) && len(n) > 0 { - externalHelp(env, n[0], n[1:]...) - } else { - cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown - cmd.HelpFunc()(cmd, args) - } - }, - } -} - -func externalHelp(env *environment.Environment, spec string, args ...string) { - profile := env.Profile() - component, version := environment.ParseCompVersion(spec) - selectVer, err := env.SelectInstalledVersion(component, version) - if err != nil { - fmt.Println(err) - return - } - binaryPath, err := env.BinaryPath(component, selectVer) - if err != nil { - fmt.Println(err) - return - } - - installPath, err := profile.ComponentInstalledPath(component, selectVer) - if err != nil { - fmt.Println(err) - return - } - - sd := profile.Path(filepath.Join(localdata.StorageParentDir, strings.Split(spec, ":")[0])) - envs := []string{ - fmt.Sprintf("%s=%s", localdata.EnvNameHome, profile.Root()), - fmt.Sprintf("%s=%s", localdata.EnvNameComponentInstallDir, installPath), - fmt.Sprintf("%s=%s", localdata.EnvNameComponentDataDir, sd), - } - envs = append(envs, os.Environ()...) - - comp := exec.Command(binaryPath, utils.RebuildArgs(args)...) - comp.Env = envs - comp.Stdout = os.Stdout - comp.Stderr = os.Stderr - if err := comp.Start(); err != nil { - fmt.Printf("Cannot fetch help message from %s failed: %v\n", binaryPath, err) - return - } - if err := comp.Wait(); err != nil { - fmt.Printf("Cannot fetch help message from %s failed: %v\n", binaryPath, err) - } -} - -// nolint unused -func rebuildArgs(args []string) []string { - helpFlag := "--help" - argList := []string{} - for _, arg := range args { - if arg == "-h" || arg == "--help" { - helpFlag = arg - } else { - argList = append(argList, arg) - } - } - argList = append(argList, helpFlag) - return argList -} - -func usageTemplate(profile *localdata.Profile) string { - installComps := ` -Components Manifest: - use "tiup list" to fetch the latest components manifest -` - - return `Usage:{{if .Runnable}} - {{.UseLine}}{{end}}{{if gt (len .Aliases) 0}} - -Aliases: - {{.NameAndAliases}}{{end}}{{if .HasExample}} - -Examples: -{{.Example}}{{end}}{{if .HasAvailableSubCommands}} - -Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} -{{if not .HasParent}}` + installComps + `{{end}} -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if not .HasParent}} - -Component instances with the same "tag" will share a data directory ($TIUP_HOME/data/$tag): - $ tiup --tag mycluster playground - -Examples: - $ tiup playground # Quick start - $ tiup playground nightly # Start a playground with the latest nightly version - $ tiup install [:version] # Install a component of specific version - $ tiup update --all # Update all installed components to the latest version - $ tiup update --nightly # Update all installed components to the nightly version - $ tiup update --self # Update the "tiup" to the latest version - $ tiup list # Fetch the latest supported components list - $ tiup status # Display all running/terminated instances - $ tiup clean # Clean the data of running/terminated instance (Kill process if it's running) - $ tiup clean --all # Clean the data of all running/terminated instances{{end}}{{if .HasAvailableSubCommands}} - -Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} -` -} diff --git a/cmd/root.go b/cmd/root.go index c3afc690a8..d1e4410317 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -49,10 +49,8 @@ var ( // arguments var ( - binary string - binPath string - tag string - printVersion bool // not using cobra.Command.Version to make it possible to show component versions + binPath string + tag string ) func init() { @@ -67,18 +65,25 @@ TiDB platform components to the local system. You can run a specific version of "tiup [:version]". If no version number is specified, the latest version installed locally will be used. If the specified component does not have any version installed locally, the latest stable version will be downloaded from the repository.`, + Example: ` $ tiup playground # Quick start + $ tiup playground nightly # Start a playground with the latest nightly version + $ tiup install [:version] # Install a component of specific version + $ tiup update --all # Update all installed components to the latest version + $ tiup update --nightly # Update all installed components to the nightly version + $ tiup update --self # Update the "tiup" to the latest version + $ tiup list # Fetch the latest supported components list + $ tiup status # Display all running/terminated instances + $ tiup clean # Clean the data of running/terminated instance (Kill process if it's running) + $ tiup clean --all # Clean the data of all running/terminated instances`, SilenceErrors: true, - FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true}, + DisableFlagParsing: true, Args: func(cmd *cobra.Command, args []string) error { // Support `tiup ` return nil }, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { teleCommand = cmd.CommandPath() - if printVersion && len(args) == 0 { - return nil - } switch cmd.Name() { case "init", "set": @@ -100,13 +105,30 @@ the latest stable version will be downloaded from the repository.`, return nil }, RunE: func(cmd *cobra.Command, args []string) error { - if printVersion && len(args) == 0 { - fmt.Println(version.NewTiUPVersion().String()) - return nil + if len(args) == 0 { + return cmd.Help() } env := environment.GlobalEnv() - if binary != "" { - component, ver := environment.ParseCompVersion(binary) + + // TBD: change this flag to subcommand + + // We assume the first unknown parameter is the component name and following + // parameters will be transparent passed because registered flags and subcommands + // will be parsed correctly. + // e.g: tiup --tag mytag --rm playground --db 3 --pd 3 --kv 4 + // => run "playground" with parameters "--db 3 --pd 3 --kv 4" + // tiup --tag mytag --binpath /xxx/tikv-server tikv + switch args[0] { + case "--help", "-h": + return cmd.Help() + case "--version", "-v": + fmt.Println(version.NewTiUPVersion().String()) + return nil + case "--binary": + if len(args) < 2 { + return fmt.Errorf("flag needs an argument: %s", args[0]) + } + component, ver := environment.ParseCompVersion(args[1]) selectedVer, err := env.SelectInstalledVersion(component, ver) if err != nil { return err @@ -117,36 +139,31 @@ the latest stable version will be downloaded from the repository.`, } fmt.Println(binaryPath) return nil - } - if len(args) > 0 { - // We assume the first unknown parameter is the component name and following - // parameters will be transparent passed because registered flags and subcommands - // will be parsed correctly. - // e.g: tiup --tag mytag --rm playground --db 3 --pd 3 --kv 4 - // => run "playground" with parameters "--db 3 --pd 3 --kv 4" - // tiup --tag mytag --binpath /xxx/tikv-server tikv - var transparentParams []string - componentSpec := args[0] - for i, arg := range os.Args { - if arg == componentSpec { - transparentParams = os.Args[i+1:] - break - } + case "--binpath": + if len(args) < 2 { + return fmt.Errorf("flag needs an argument: %s", args[0]) } - if len(transparentParams) > 0 && transparentParams[0] == "--" { - transparentParams = transparentParams[1:] + binPath = args[1] + args = args[2:] + case "--tag", "-T": + if len(args) < 2 { + return fmt.Errorf("flag needs an argument: %s", args[0]) } - - teleCommand = fmt.Sprintf("%s %s", cmd.CommandPath(), componentSpec) - return tiupexec.RunComponent(env, tag, componentSpec, binPath, transparentParams) + tag = args[1] + args = args[2:] } - return cmd.Help() - }, - PersistentPostRunE: func(cmd *cobra.Command, args []string) error { - if env := environment.GlobalEnv(); env != nil { - return env.Close() + if len(args) < 1 { + return cmd.Help() } - return nil + + componentSpec := args[0] + args = args[1:] + if len(args) > 0 && args[0] == "--" { + args = args[1:] + } + + teleCommand = fmt.Sprintf("%s %s", cmd.CommandPath(), componentSpec) + return tiupexec.RunComponent(env, tag, componentSpec, binPath, args) }, SilenceUsage: true, // implement auto completion for tiup components @@ -181,12 +198,12 @@ the latest stable version will be downloaded from the repository.`, }, } - rootCmd.PersistentFlags().BoolVarP(&repoOpts.SkipVersionCheck, "skip-version-check", "", false, "Skip the strict version check, by default a version must be a valid SemVer string") - rootCmd.Flags().StringVar(&binary, "binary", "", "Print binary path of a specific version of a component `[:version]`\n"+ + // useless, exist to generate help infomation + rootCmd.Flags().String("binary", "", "Print binary path of a specific version of a component `[:version]`\n"+ "and the latest version installed will be selected if no version specified") - rootCmd.Flags().StringVarP(&tag, "tag", "T", "", "[Deprecated] Specify a tag for component instance") - rootCmd.Flags().StringVar(&binPath, "binpath", "", "Specify the binary path of component instance") - rootCmd.Flags().BoolVarP(&printVersion, "version", "v", false, "Print the version of tiup") + rootCmd.Flags().StringP("tag", "T", "", "[Deprecated] Specify a tag for component instance") + rootCmd.Flags().String("binpath", "", "Specify the binary path of component instance") + rootCmd.Flags().BoolP("version", "v", false, "Print the version of tiup") rootCmd.AddCommand( newInstallCmd(), @@ -200,24 +217,6 @@ the latest stable version will be downloaded from the repository.`, newEnvCmd(), newHistoryCmd(), ) - - originHelpFunc := rootCmd.HelpFunc() - rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { - cmd, _, _ = cmd.Root().Find(args) - if len(args) < 2 || cmd != rootCmd { - originHelpFunc(cmd, args) - return - } - - env, _ := environment.InitEnv(repoOpts) - environment.SetGlobalEnv(env) - _ = cmd.RunE(cmd, args) - }) - - rootCmd.SetHelpCommand(newHelpCmd()) - // If env is inited before, localdata.InitProfile() will return a valid profile - // or it will return an invalid one but still print usage - rootCmd.SetUsageTemplate(usageTemplate(localdata.InitProfile())) } // Execute parses the command line arguments and calls proper functions diff --git a/pkg/repository/repository.go b/pkg/repository/repository.go index 8924ace8ef..0dd38fb3e1 100644 --- a/pkg/repository/repository.go +++ b/pkg/repository/repository.go @@ -22,7 +22,6 @@ type Repository struct { // Options represents options for a repository type Options struct { - SkipVersionCheck bool GOOS string GOARCH string DisableDecompress bool