github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+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/v2"
    14  	"code.cloudfoundry.org/cli/util/configv3"
    15  	"code.cloudfoundry.org/cli/util/panichandler"
    16  	"code.cloudfoundry.org/cli/util/ui"
    17  	"github.com/jessevdk/go-flags"
    18  )
    19  
    20  type UI interface {
    21  	DisplayError(err error)
    22  }
    23  
    24  var ErrFailed = errors.New("command failed")
    25  var ParseErr = errors.New("incorrect type for arg")
    26  
    27  func main() {
    28  	defer panichandler.HandlePanic()
    29  	parse(os.Args[1:])
    30  }
    31  
    32  func parse(args []string) {
    33  	parser := flags.NewParser(&common.Commands, flags.HelpFlag)
    34  	parser.CommandHandler = executionWrapper
    35  	extraArgs, err := parser.ParseArgs(args)
    36  	if err == nil {
    37  		return
    38  	}
    39  
    40  	if flagErr, ok := err.(*flags.Error); ok {
    41  		switch flagErr.Type {
    42  		case flags.ErrHelp, flags.ErrUnknownFlag, flags.ErrExpectedArgument:
    43  			_, found := reflect.TypeOf(common.Commands).FieldByNameFunc(
    44  				func(fieldName string) bool {
    45  					field, _ := reflect.TypeOf(common.Commands).FieldByName(fieldName)
    46  					return parser.Active != nil && parser.Active.Name == field.Tag.Get("command")
    47  				},
    48  			)
    49  
    50  			if found && flagErr.Type == flags.ErrUnknownFlag && parser.Active.Name == "set-env" {
    51  				newArgs := []string{}
    52  				for _, arg := range args {
    53  					if arg[0] == '-' {
    54  						newArgs = append(newArgs, fmt.Sprintf("%s%s", v2.WorkAroundPrefix, arg))
    55  					} else {
    56  						newArgs = append(newArgs, arg)
    57  					}
    58  				}
    59  				parse(newArgs)
    60  				return
    61  			}
    62  
    63  			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
    64  				fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
    65  			}
    66  
    67  			if found {
    68  				parse([]string{"help", parser.Active.Name})
    69  			} else {
    70  				switch len(extraArgs) {
    71  				case 0:
    72  					parse([]string{"help"})
    73  				case 1:
    74  					if !isOption(extraArgs[0]) || (len(args) > 1 && extraArgs[0] == "-a") {
    75  						parse([]string{"help", extraArgs[0]})
    76  					} else {
    77  						parse([]string{"help"})
    78  					}
    79  				default:
    80  					if isCommand(extraArgs[0]) {
    81  						parse([]string{"help", extraArgs[0]})
    82  					} else {
    83  						parse(extraArgs[1:])
    84  					}
    85  				}
    86  			}
    87  
    88  			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
    89  				os.Exit(1)
    90  			}
    91  		case flags.ErrRequired:
    92  			fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
    93  			parse([]string{"help", args[0]})
    94  			os.Exit(1)
    95  		case flags.ErrMarshal:
    96  			errMessage := strings.Split(flagErr.Message, ":")
    97  			fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", errMessage[0])
    98  			parse([]string{"help", args[0]})
    99  			os.Exit(1)
   100  		case flags.ErrUnknownCommand:
   101  			cmd.Main(os.Getenv("CF_TRACE"), os.Args)
   102  		case flags.ErrCommandRequired:
   103  			if common.Commands.VerboseOrVersion {
   104  				parse([]string{"version"})
   105  			} else {
   106  				parse([]string{"help"})
   107  			}
   108  		default:
   109  			fmt.Fprintf(os.Stderr, "Unexpected flag error\ntype: %s\nmessage: %s\n", flagErr.Type, flagErr.Error())
   110  		}
   111  	} else if err == ErrFailed {
   112  		os.Exit(1)
   113  	} else if err == ParseErr {
   114  		fmt.Println()
   115  		parse([]string{"help", args[0]})
   116  		os.Exit(1)
   117  	} else {
   118  		fmt.Fprintf(os.Stderr, "Unexpected error: %s\n", err.Error())
   119  		os.Exit(1)
   120  	}
   121  }
   122  
   123  func isCommand(s string) bool {
   124  	_, found := reflect.TypeOf(common.Commands).FieldByNameFunc(
   125  		func(fieldName string) bool {
   126  			field, _ := reflect.TypeOf(common.Commands).FieldByName(fieldName)
   127  			return s == field.Tag.Get("command") || s == field.Tag.Get("alias")
   128  		})
   129  
   130  	return found
   131  }
   132  func isOption(s string) bool {
   133  	return strings.HasPrefix(s, "-")
   134  }
   135  
   136  func executionWrapper(cmd flags.Commander, args []string) error {
   137  	cfConfig, err := configv3.LoadConfig(configv3.FlagOverride{
   138  		Verbose: common.Commands.VerboseOrVersion,
   139  	})
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	defer func() {
   145  		configWriteErr := configv3.WriteConfig(cfConfig)
   146  		if configWriteErr != nil {
   147  			fmt.Fprintf(os.Stderr, "Error writing config: %s", configWriteErr.Error())
   148  		}
   149  	}()
   150  
   151  	if extendedCmd, ok := cmd.(command.ExtendedCommander); ok {
   152  		commandUI, err := ui.NewUI(cfConfig)
   153  		if err != nil {
   154  			return err
   155  		}
   156  
   157  		err = extendedCmd.Setup(cfConfig, commandUI)
   158  		if err != nil {
   159  			return handleError(err, commandUI)
   160  		}
   161  		return handleError(extendedCmd.Execute(args), commandUI)
   162  	}
   163  
   164  	return fmt.Errorf("command does not conform to ExtendedCommander")
   165  }
   166  
   167  func handleError(err error, commandUI UI) error {
   168  	if err == nil {
   169  		return nil
   170  	}
   171  
   172  	commandUI.DisplayError(err)
   173  	if _, isParseArgumentError := err.(command.ParseArgumentError); isParseArgumentError {
   174  		return ParseErr
   175  	}
   176  	if _, isRequiredArgumentError := err.(command.RequiredArgumentError); isRequiredArgumentError {
   177  		return ParseErr
   178  	}
   179  
   180  	return ErrFailed
   181  }