cmd/glab/main.go (190 lines of code) (raw):

package main import ( "errors" "fmt" "net" "os" "os/exec" "runtime" "strconv" "strings" "gitlab.com/gitlab-org/cli/api" "gitlab.com/gitlab-org/cli/pkg/iostreams" "github.com/mgutz/ansi" surveyCore "github.com/AlecAivazis/survey/v2/core" "gitlab.com/gitlab-org/cli/commands" "gitlab.com/gitlab-org/cli/commands/alias/expand" "gitlab.com/gitlab-org/cli/commands/cmdutils" "gitlab.com/gitlab-org/cli/commands/help" "gitlab.com/gitlab-org/cli/commands/update" "gitlab.com/gitlab-org/cli/internal/config" "gitlab.com/gitlab-org/cli/internal/run" "gitlab.com/gitlab-org/cli/pkg/glinstance" "gitlab.com/gitlab-org/cli/pkg/tableprinter" "gitlab.com/gitlab-org/cli/pkg/utils" "github.com/spf13/cobra" ) var ( // version is set dynamically at build version = "DEV" // commit is set dynamically at build commit string // platform is set dynamically at build platform = runtime.GOOS ) // debug is set dynamically at build and can be overridden by // the configuration file or environment variable // sets to "true" or "false" or "1" or "0" as string var debugMode = "false" // debug is parsed boolean of debugMode var debug bool func main() { debug = debugMode == "true" || debugMode == "1" cmdFactory := cmdutils.NewFactory() cfg, err := cmdFactory.Config() if err != nil { cmdFactory.IO.Logf("failed to read configuration: %s\n", err) os.Exit(2) } api.SetUserAgent(version, platform, runtime.GOARCH) maybeOverrideDefaultHost(cmdFactory, cfg) if !cmdFactory.IO.ColorEnabled() { surveyCore.DisableColor = true } else { // Override survey's choice of color for default values // For default values for e.g. `Input` prompts, Survey uses the literal "white" color, // which makes no sense on dark terminals and is literally invisible on light backgrounds. // This overrides Survey to output a gray color for 256-color terminals and "default" for basic terminals. surveyCore.TemplateFuncsWithColor["color"] = func(style string) string { switch style { case "white": if cmdFactory.IO.Is256ColorSupported() { return fmt.Sprintf("\x1b[%d;5;%dm", 38, 242) } return ansi.ColorCode("default") default: return ansi.ColorCode(style) } } } rootCmd := commands.NewCmdRoot(cmdFactory, version, commit) // Set Debug mode from config if not previously set by debugMode if !debug { debugModeCfg, _ := cfg.Get("", "debug") debug = debugModeCfg == "true" || debugModeCfg == "1" } if pager, _ := cfg.Get("", "glab_pager"); pager != "" { cmdFactory.IO.SetPager(pager) } if promptDisabled, _ := cfg.Get("", "no_prompt"); promptDisabled != "" { cmdFactory.IO.SetPrompt(promptDisabled) } if forceHyperlinks := os.Getenv("FORCE_HYPERLINKS"); forceHyperlinks != "" && forceHyperlinks != "0" { cmdFactory.IO.SetDisplayHyperlinks("always") } else if displayHyperlinks, _ := cfg.Get("", "display_hyperlinks"); displayHyperlinks == "true" { cmdFactory.IO.SetDisplayHyperlinks("auto") } var expandedArgs []string if len(os.Args) > 0 { expandedArgs = os.Args[1:] } cmd, _, err := rootCmd.Traverse(expandedArgs) if err != nil || cmd == rootCmd { originalArgs := expandedArgs isShell := false expandedArgs, isShell, err = expand.ExpandAlias(cfg, os.Args, nil) if err != nil { cmdFactory.IO.LogInfof("Failed to process alias: %s\n", err) os.Exit(2) } if debug { fmt.Printf("%v -> %v\n", originalArgs, expandedArgs) } if isShell { externalCmd := exec.Command(expandedArgs[0], expandedArgs[1:]...) externalCmd.Stderr = os.Stderr externalCmd.Stdout = os.Stdout externalCmd.Stdin = os.Stdin preparedCmd := run.PrepareCmd(externalCmd) err = preparedCmd.Run() if err != nil { if ee, ok := err.(*exec.ExitError); ok { os.Exit(ee.ExitCode()) } cmdFactory.IO.LogInfof("failed to run external command: %s", err) os.Exit(3) } os.Exit(0) } } // Override the default column separator of tableprinter to double spaces tableprinter.SetTTYSeparator(" ") // Override the default terminal width of tableprinter tableprinter.SetTerminalWidth(cmdFactory.IO.TerminalWidth()) // set whether terminal is a TTY or non-TTY tableprinter.SetIsTTY(cmdFactory.IO.IsOutputTTY()) rootCmd.SetArgs(expandedArgs) if cmd, err := rootCmd.ExecuteC(); err != nil { if !errors.Is(err, cmdutils.SilentError) { printError(cmdFactory.IO, err, cmd, debug) } var exitError *cmdutils.ExitError if errors.As(err, &exitError) { os.Exit(exitError.Code) } else { os.Exit(1) } } if help.HasFailed() { os.Exit(1) } var argCommand string if expandedArgs != nil { argCommand = expandedArgs[0] } else { argCommand = "" } shouldCheck := false // GLAB_CHECK_UPDATE has higher priority than the check_update configuration value if envVal, ok := os.LookupEnv("GLAB_CHECK_UPDATE"); ok { if checkUpdate, err := strconv.ParseBool(envVal); err == nil { shouldCheck = checkUpdate } } else { // Fall back to config value if env var not set if checkUpdate, _ := cfg.Get("", "check_update"); checkUpdate != "" { if parsed, err := strconv.ParseBool(checkUpdate); err == nil { shouldCheck = parsed } } } if shouldCheck { if err := update.CheckUpdate(cmdFactory, version, true, argCommand); err != nil { printError(cmdFactory.IO, err, rootCmd, debug) } } api.GetClient().HTTPClient().CloseIdleConnections() } func printError(streams *iostreams.IOStreams, err error, cmd *cobra.Command, debug bool) { color := streams.Color() var dnsError *net.DNSError if errors.As(err, &dnsError) { streams.Logf("%s error connecting to %s\n", color.FailedIcon(), dnsError.Name) if debug { streams.Log(color.FailedIcon(), dnsError) } streams.Logf("%s Check your internet connection and status.gitlab.com. If on GitLab Self-Managed, run 'sudo gitlab-ctl status' on your server.\n", color.DotWarnIcon()) } else { var exitError *cmdutils.ExitError if errors.As(err, &exitError) { streams.Logf("%s %s %s=%s\n", color.FailedIcon(), color.Bold(exitError.Details), color.Red("error"), exitError.Err) } else { streams.Log("ERROR:", err) var flagError *cmdutils.FlagError if errors.As(err, &flagError) || strings.HasPrefix(err.Error(), "unknown command ") { streams.Logf("Try '%s --help' for more information.", cmd.CommandPath()) } } } if cmd != nil { cmd.Print("\n") } } func maybeOverrideDefaultHost(f *cmdutils.Factory, cfg config.Config) { baseRepo, err := f.BaseRepo() if err == nil { glinstance.OverrideDefault(baseRepo.RepoHost()) } // Fetch the custom host config from env vars, then local config.yml, then global config,yml. customGLHost, _ := cfg.Get("", "host") if customGLHost != "" { if utils.IsValidURL(customGLHost) { var protocol string customGLHost, protocol = glinstance.StripHostProtocol(customGLHost) glinstance.OverrideDefaultProtocol(protocol) } glinstance.OverrideDefault(customGLHost) } }