github.com/asifdxtreme/cli@v6.1.3-0.20150123051144-9ead8700b4ae+incompatible/main/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"runtime"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/cloudfoundry/cli/cf/api"
    12  	"github.com/cloudfoundry/cli/cf/app"
    13  	"github.com/cloudfoundry/cli/cf/command_factory"
    14  	"github.com/cloudfoundry/cli/cf/command_metadata"
    15  	"github.com/cloudfoundry/cli/cf/command_runner"
    16  	"github.com/cloudfoundry/cli/cf/configuration/config_helpers"
    17  	"github.com/cloudfoundry/cli/cf/configuration/core_config"
    18  	"github.com/cloudfoundry/cli/cf/configuration/plugin_config"
    19  	. "github.com/cloudfoundry/cli/cf/i18n"
    20  	"github.com/cloudfoundry/cli/cf/i18n/detection"
    21  	"github.com/cloudfoundry/cli/cf/manifest"
    22  	"github.com/cloudfoundry/cli/cf/net"
    23  	"github.com/cloudfoundry/cli/cf/panic_printer"
    24  	"github.com/cloudfoundry/cli/cf/requirements"
    25  	"github.com/cloudfoundry/cli/cf/terminal"
    26  	"github.com/cloudfoundry/cli/cf/trace"
    27  	"github.com/cloudfoundry/cli/plugin/rpc"
    28  	"github.com/codegangsta/cli"
    29  )
    30  
    31  var deps = setupDependencies()
    32  
    33  type cliDependencies struct {
    34  	termUI         terminal.UI
    35  	configRepo     core_config.Repository
    36  	pluginConfig   plugin_config.PluginConfiguration
    37  	manifestRepo   manifest.ManifestRepository
    38  	apiRepoLocator api.RepositoryLocator
    39  	gateways       map[string]net.Gateway
    40  	teePrinter     *terminal.TeePrinter
    41  	detector       detection.Detector
    42  }
    43  
    44  func setupDependencies() (deps *cliDependencies) {
    45  	deps = new(cliDependencies)
    46  
    47  	deps.teePrinter = terminal.NewTeePrinter()
    48  
    49  	deps.termUI = terminal.NewUI(os.Stdin, deps.teePrinter)
    50  
    51  	deps.manifestRepo = manifest.NewManifestDiskRepository()
    52  
    53  	errorHandler := func(err error) {
    54  		if err != nil {
    55  			deps.termUI.Failed(fmt.Sprintf("Config error: %s", err))
    56  		}
    57  	}
    58  	deps.configRepo = core_config.NewRepositoryFromFilepath(config_helpers.DefaultFilePath(), errorHandler)
    59  	deps.pluginConfig = plugin_config.NewPluginConfig(errorHandler)
    60  	deps.detector = &detection.JibberJabberDetector{}
    61  
    62  	T = Init(deps.configRepo, deps.detector)
    63  
    64  	terminal.UserAskedForColors = deps.configRepo.ColorEnabled()
    65  	terminal.InitColorSupport()
    66  
    67  	if os.Getenv("CF_TRACE") != "" {
    68  		trace.Logger = trace.NewLogger(os.Getenv("CF_TRACE"))
    69  	} else {
    70  		trace.Logger = trace.NewLogger(deps.configRepo.Trace())
    71  	}
    72  
    73  	deps.gateways = map[string]net.Gateway{
    74  		"auth":             net.NewUAAGateway(deps.configRepo, deps.termUI),
    75  		"cloud-controller": net.NewCloudControllerGateway(deps.configRepo, time.Now, deps.termUI),
    76  		"uaa":              net.NewUAAGateway(deps.configRepo, deps.termUI),
    77  	}
    78  	deps.apiRepoLocator = api.NewRepositoryLocator(deps.configRepo, deps.gateways)
    79  
    80  	return
    81  }
    82  
    83  func main() {
    84  	defer handlePanics(deps.teePrinter)
    85  	defer deps.configRepo.Close()
    86  
    87  	cmdFactory := command_factory.NewFactory(deps.termUI, deps.configRepo, deps.manifestRepo, deps.apiRepoLocator, deps.pluginConfig)
    88  	requirementsFactory := requirements.NewFactory(deps.termUI, deps.configRepo, deps.apiRepoLocator)
    89  	cmdRunner := command_runner.NewRunner(cmdFactory, requirementsFactory, deps.termUI)
    90  	pluginsConfig := plugin_config.NewPluginConfig(func(err error) { panic(err) })
    91  	pluginList := pluginsConfig.Plugins()
    92  
    93  	var badFlags string
    94  	metaDatas := cmdFactory.CommandMetadatas()
    95  	//return only metadata for current command
    96  	metaDatas = mergePluginMetaData(metaDatas, pluginList)
    97  
    98  	if len(os.Args) > 1 {
    99  		flags := cmdFactory.GetCommandFlags(os.Args[1])
   100  		totalArgs, _ := cmdFactory.GetCommandTotalArgs(os.Args[1])
   101  
   102  		if args2skip := totalArgs + 2; len(os.Args) >= args2skip {
   103  			badFlags = matchArgAndFlags(flags, os.Args[args2skip:])
   104  		}
   105  
   106  		if badFlags != "" {
   107  			badFlags = badFlags + "\n\n"
   108  		}
   109  	}
   110  
   111  	injectHelpTemplate(badFlags)
   112  
   113  	theApp := app.NewApp(cmdRunner, metaDatas...)
   114  	//command `cf` without argument
   115  	if len(os.Args) == 1 || os.Args[1] == "help" || requestHelp(os.Args[2:]) {
   116  		theApp.Run(os.Args)
   117  	} else if cmdFactory.CheckIfCoreCmdExists(os.Args[1]) {
   118  		callCoreCommand(os.Args[0:], theApp)
   119  	} else {
   120  		// run each plugin and find the method/
   121  		// run method if exist
   122  
   123  		ran := rpc.RunMethodIfExists(theApp, os.Args[1:], deps.teePrinter, deps.teePrinter, pluginList)
   124  		if !ran {
   125  			theApp.Run(os.Args)
   126  		}
   127  	}
   128  }
   129  
   130  func gatewaySliceFromMap(gateway_map map[string]net.Gateway) []net.WarningProducer {
   131  	gateways := []net.WarningProducer{}
   132  	for _, gateway := range gateway_map {
   133  		gateways = append(gateways, gateway)
   134  	}
   135  	return gateways
   136  }
   137  
   138  func injectHelpTemplate(badFlags string) {
   139  	cli.CommandHelpTemplate = fmt.Sprintf(`%sNAME:
   140     {{.Name}} - {{.Description}}
   141  {{with .ShortName}}
   142  ALIAS:
   143     {{.}}
   144  {{end}}
   145  USAGE:
   146     {{.Usage}}{{with .Flags}}
   147  
   148  OPTIONS:
   149  {{range .}}   {{.}}
   150  {{end}}{{else}}
   151  {{end}}`, badFlags)
   152  }
   153  
   154  func handlePanics(printer terminal.Printer) {
   155  	panic_printer.UI = terminal.NewUI(os.Stdin, printer)
   156  
   157  	commandArgs := strings.Join(os.Args, " ")
   158  	stackTrace := generateBacktrace()
   159  
   160  	err := recover()
   161  	panic_printer.DisplayCrashDialog(err, commandArgs, stackTrace)
   162  
   163  	if err != nil {
   164  		os.Exit(1)
   165  	}
   166  }
   167  
   168  func generateBacktrace() string {
   169  	stackByteCount := 0
   170  	STACK_SIZE_LIMIT := 1024 * 1024
   171  	var bytes []byte
   172  	for stackSize := 1024; (stackByteCount == 0 || stackByteCount == stackSize) && stackSize < STACK_SIZE_LIMIT; stackSize = 2 * stackSize {
   173  		bytes = make([]byte, stackSize)
   174  		stackByteCount = runtime.Stack(bytes, true)
   175  	}
   176  	stackTrace := "\t" + strings.Replace(string(bytes), "\n", "\n\t", -1)
   177  	return stackTrace
   178  }
   179  
   180  func callCoreCommand(args []string, theApp *cli.App) {
   181  	err := theApp.Run(args)
   182  	if err != nil {
   183  		os.Exit(1)
   184  	}
   185  	gateways := gatewaySliceFromMap(deps.gateways)
   186  
   187  	warningsCollector := net.NewWarningsCollector(deps.termUI, gateways...)
   188  	warningsCollector.PrintWarnings()
   189  }
   190  
   191  func matchArgAndFlags(flags []string, args []string) string {
   192  	var badFlag string
   193  	var lastPassed bool
   194  	multipleFlagErr := false
   195  
   196  Loop:
   197  	for _, arg := range args {
   198  		prefix := ""
   199  
   200  		//only take flag name, ignore value after '='
   201  		arg = strings.Split(arg, "=")[0]
   202  
   203  		if arg == "--h" || arg == "-h" {
   204  			continue Loop
   205  		}
   206  
   207  		if strings.HasPrefix(arg, "--") {
   208  			prefix = "--"
   209  		} else if strings.HasPrefix(arg, "-") {
   210  			prefix = "-"
   211  		}
   212  		arg = strings.TrimLeft(arg, prefix)
   213  
   214  		//skip verification for negative integers, e.g. -i -10
   215  		if lastPassed {
   216  			lastPassed = false
   217  			if _, err := strconv.ParseInt(arg, 10, 32); err == nil {
   218  				continue Loop
   219  			}
   220  		}
   221  
   222  		if prefix != "" {
   223  			for _, flag := range flags {
   224  				if flag == arg {
   225  					lastPassed = true
   226  					continue Loop
   227  				}
   228  			}
   229  
   230  			if badFlag == "" {
   231  				badFlag = fmt.Sprintf("\"%s%s\"", prefix, arg)
   232  			} else {
   233  				multipleFlagErr = true
   234  				badFlag = badFlag + fmt.Sprintf(", \"%s%s\"", prefix, arg)
   235  			}
   236  		}
   237  	}
   238  
   239  	if multipleFlagErr && badFlag != "" {
   240  		badFlag = fmt.Sprintf("%s %s", T("Unknown flags:"), badFlag)
   241  	} else if badFlag != "" {
   242  		badFlag = fmt.Sprintf("%s %s", T("Unknown flag"), badFlag)
   243  	}
   244  
   245  	return badFlag
   246  }
   247  
   248  func mergePluginMetaData(coreMetas []command_metadata.CommandMetadata, pluginMetas map[string]plugin_config.PluginMetadata) []command_metadata.CommandMetadata {
   249  	for _, meta := range pluginMetas {
   250  		for _, cmd := range meta.Commands {
   251  			tmpMeta := command_metadata.CommandMetadata{}
   252  			if cmd.UsageDetails.Usage == "" {
   253  				tmpMeta.Usage = "N/A"
   254  			} else {
   255  				tmpMeta.Usage = cmd.UsageDetails.Usage
   256  			}
   257  			tmpMeta.Name = cmd.Name
   258  			tmpMeta.ShortName = cmd.Alias
   259  			tmpMeta.Description = cmd.HelpText
   260  
   261  			for k, v := range cmd.UsageDetails.Options {
   262  				tmpMeta.Flags = append(tmpMeta.Flags, cli.BoolFlag{Name: k, Usage: v})
   263  			}
   264  			coreMetas = append(coreMetas, tmpMeta)
   265  		}
   266  	}
   267  
   268  	return coreMetas
   269  }
   270  
   271  func requestHelp(args []string) bool {
   272  	for _, v := range args {
   273  		if v == "-h" || v == "--help" {
   274  			return true
   275  		}
   276  	}
   277  
   278  	return false
   279  }