github.com/cloudfoundry-attic/cli-with-i18n@v6.32.1-0.20171002233121-7401370d3b85+incompatible/main.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  
    10  	"code.cloudfoundry.org/cli/cf/cmd"
    11  	"code.cloudfoundry.org/cli/command"
    12  	"code.cloudfoundry.org/cli/command/common"
    13  	"code.cloudfoundry.org/cli/command/translatableerror"
    14  	"code.cloudfoundry.org/cli/command/v2"
    15  	"code.cloudfoundry.org/cli/util/configv3"
    16  	"code.cloudfoundry.org/cli/util/panichandler"
    17  	"code.cloudfoundry.org/cli/util/ui"
    18  	"github.com/jessevdk/go-flags"
    19  	log "github.com/sirupsen/logrus"
    20  )
    21  
    22  type UI interface {
    23  	DisplayError(err error)
    24  	DisplayWarning(template string, templateValues ...map[string]interface{})
    25  }
    26  
    27  type DisplayUsage interface {
    28  	DisplayUsage()
    29  }
    30  
    31  var ErrFailed = errors.New("command failed")
    32  var ParseErr = errors.New("incorrect type for arg")
    33  
    34  func main() {
    35  	defer panichandler.HandlePanic()
    36  	parse(os.Args[1:])
    37  }
    38  
    39  func parse(args []string) {
    40  	parser := flags.NewParser(&common.Commands, flags.HelpFlag)
    41  	parser.CommandHandler = executionWrapper
    42  	extraArgs, err := parser.ParseArgs(args)
    43  	if err == nil {
    44  		return
    45  	}
    46  
    47  	if flagErr, ok := err.(*flags.Error); ok {
    48  		switch flagErr.Type {
    49  		case flags.ErrHelp, flags.ErrUnknownFlag, flags.ErrExpectedArgument, flags.ErrInvalidChoice:
    50  			_, found := reflect.TypeOf(common.Commands).FieldByNameFunc(
    51  				func(fieldName string) bool {
    52  					field, _ := reflect.TypeOf(common.Commands).FieldByName(fieldName)
    53  					return parser.Active != nil && parser.Active.Name == field.Tag.Get("command")
    54  				},
    55  			)
    56  
    57  			if found && flagErr.Type == flags.ErrUnknownFlag && parser.Active.Name == "set-env" {
    58  				newArgs := []string{}
    59  				for _, arg := range args {
    60  					if arg[0] == '-' {
    61  						newArgs = append(newArgs, fmt.Sprintf("%s%s", v2.WorkAroundPrefix, arg))
    62  					} else {
    63  						newArgs = append(newArgs, arg)
    64  					}
    65  				}
    66  				parse(newArgs)
    67  				return
    68  			}
    69  
    70  			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument || flagErr.Type == flags.ErrInvalidChoice {
    71  				fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
    72  			}
    73  
    74  			if found {
    75  				parse([]string{"help", parser.Active.Name})
    76  			} else {
    77  				switch len(extraArgs) {
    78  				case 0:
    79  					parse([]string{"help"})
    80  				case 1:
    81  					if !isOption(extraArgs[0]) || (len(args) > 1 && extraArgs[0] == "-a") {
    82  						parse([]string{"help", extraArgs[0]})
    83  					} else {
    84  						parse([]string{"help"})
    85  					}
    86  				default:
    87  					if isCommand(extraArgs[0]) {
    88  						parse([]string{"help", extraArgs[0]})
    89  					} else {
    90  						parse(extraArgs[1:])
    91  					}
    92  				}
    93  			}
    94  
    95  			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument || flagErr.Type == flags.ErrInvalidChoice {
    96  				os.Exit(1)
    97  			}
    98  		case flags.ErrRequired:
    99  			fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
   100  			parse([]string{"help", args[0]})
   101  			os.Exit(1)
   102  		case flags.ErrMarshal:
   103  			errMessage := strings.Split(flagErr.Message, ":")
   104  			fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", errMessage[0])
   105  			parse([]string{"help", args[0]})
   106  			os.Exit(1)
   107  		case flags.ErrUnknownCommand:
   108  			cmd.Main(os.Getenv("CF_TRACE"), os.Args)
   109  		case flags.ErrCommandRequired:
   110  			if common.Commands.VerboseOrVersion {
   111  				parse([]string{"version"})
   112  			} else {
   113  				parse([]string{"help"})
   114  			}
   115  		default:
   116  			fmt.Fprintf(os.Stderr, "Unexpected flag error\ntype: %s\nmessage: %s\n", flagErr.Type, flagErr.Error())
   117  		}
   118  	} else if err == ErrFailed {
   119  		os.Exit(1)
   120  	} else if err == ParseErr {
   121  		fmt.Println()
   122  		parse([]string{"help", args[0]})
   123  		os.Exit(1)
   124  	} else {
   125  		fmt.Fprintf(os.Stderr, "Unexpected error: %s\n", err.Error())
   126  		os.Exit(1)
   127  	}
   128  }
   129  
   130  func isCommand(s string) bool {
   131  	_, found := reflect.TypeOf(common.Commands).FieldByNameFunc(
   132  		func(fieldName string) bool {
   133  			field, _ := reflect.TypeOf(common.Commands).FieldByName(fieldName)
   134  			return s == field.Tag.Get("command") || s == field.Tag.Get("alias")
   135  		})
   136  
   137  	return found
   138  }
   139  
   140  func isOption(s string) bool {
   141  	return strings.HasPrefix(s, "-")
   142  }
   143  
   144  func executionWrapper(cmd flags.Commander, args []string) error {
   145  	cfConfig, configErr := configv3.LoadConfig(configv3.FlagOverride{
   146  		Verbose: common.Commands.VerboseOrVersion,
   147  	})
   148  	if configErr != nil {
   149  		if _, ok := configErr.(translatableerror.EmptyConfigError); !ok {
   150  			return configErr
   151  		}
   152  	}
   153  
   154  	commandUI, err := ui.NewUI(cfConfig)
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	// TODO: when the line in the old code under `cf` which calls
   160  	// configv3.LoadConfig() is finally removed, then we should replace the code
   161  	// path above with the following:
   162  	//
   163  	// var configErrTemplate string
   164  	// if configErr != nil {
   165  	// 	if ce, ok := configErr.(translatableerror.EmptyConfigError); ok {
   166  	// 		configErrTemplate = ce.Error()
   167  	// 	} else {
   168  	// 		return configErr
   169  	// 	}
   170  	// }
   171  
   172  	// commandUI, err := ui.NewUI(cfConfig)
   173  	// if err != nil {
   174  	// 	return err
   175  	// }
   176  
   177  	// if configErr != nil {
   178  	//   commandUI.DisplayWarning(configErrTemplate, map[string]interface{}{
   179  	//   	"FilePath": configv3.ConfigFilePath(),
   180  	//   })
   181  	// }
   182  
   183  	defer func() {
   184  		configWriteErr := configv3.WriteConfig(cfConfig)
   185  		if configWriteErr != nil {
   186  			fmt.Fprintf(os.Stderr, "Error writing config: %s", configWriteErr.Error())
   187  		}
   188  	}()
   189  
   190  	if extendedCmd, ok := cmd.(command.ExtendedCommander); ok {
   191  		log.SetOutput(os.Stderr)
   192  		log.SetLevel(log.Level(cfConfig.LogLevel()))
   193  
   194  		err = extendedCmd.Setup(cfConfig, commandUI)
   195  		if err != nil {
   196  			return handleError(err, commandUI)
   197  		}
   198  		return handleError(extendedCmd.Execute(args), commandUI)
   199  	}
   200  
   201  	return fmt.Errorf("command does not conform to ExtendedCommander")
   202  }
   203  
   204  func handleError(err error, commandUI UI) error {
   205  	if err == nil {
   206  		return nil
   207  	}
   208  
   209  	commandUI.DisplayError(err)
   210  
   211  	if _, ok := err.(DisplayUsage); ok {
   212  		return ParseErr
   213  	}
   214  
   215  	return ErrFailed
   216  }