cli/cmd/gh/main.go
2020-07-15 12:36:45 -05:00

140 lines
3.1 KiB
Go

package main
import (
"errors"
"fmt"
"io"
"net"
"os"
"os/exec"
"path"
"strings"
"github.com/cli/cli/command"
"github.com/cli/cli/internal/config"
"github.com/cli/cli/pkg/cmdutil"
"github.com/cli/cli/update"
"github.com/cli/cli/utils"
"github.com/mgutz/ansi"
"github.com/spf13/cobra"
)
var updaterEnabled = ""
func main() {
currentVersion := command.Version
updateMessageChan := make(chan *update.ReleaseInfo)
go func() {
rel, _ := checkForUpdate(currentVersion)
updateMessageChan <- rel
}()
hasDebug := os.Getenv("DEBUG") != ""
stderr := utils.NewColorable(os.Stderr)
expandedArgs := []string{}
if len(os.Args) > 0 {
expandedArgs = os.Args[1:]
}
cmd, _, err := command.RootCmd.Traverse(expandedArgs)
if err != nil || cmd == command.RootCmd {
originalArgs := expandedArgs
isShell := false
expandedArgs, isShell, err = command.ExpandAlias(os.Args)
if err != nil {
fmt.Fprintf(stderr, "failed to process aliases: %s\n", err)
os.Exit(2)
}
if isShell {
err = command.ExecuteShellAlias(expandedArgs)
if err != nil {
if ee, ok := err.(*exec.ExitError); ok {
os.Exit(ee.ExitCode())
}
fmt.Fprintf(stderr, "failed to run external command: %s", err)
os.Exit(3)
}
os.Exit(0)
}
if hasDebug {
fmt.Fprintf(stderr, "%v -> %v\n", originalArgs, expandedArgs)
}
}
command.RootCmd.SetArgs(expandedArgs)
if cmd, err := command.RootCmd.ExecuteC(); err != nil {
printError(os.Stderr, err, cmd, hasDebug)
os.Exit(1)
}
if command.HasFailed() {
os.Exit(1)
}
newRelease := <-updateMessageChan
if newRelease != nil {
msg := fmt.Sprintf("%s %s → %s\n%s",
ansi.Color("A new release of gh is available:", "yellow"),
ansi.Color(currentVersion, "cyan"),
ansi.Color(newRelease.Version, "cyan"),
ansi.Color(newRelease.URL, "yellow"))
stderr := utils.NewColorable(os.Stderr)
fmt.Fprintf(stderr, "\n\n%s\n\n", msg)
}
}
func printError(out io.Writer, err error, cmd *cobra.Command, debug bool) {
if err == cmdutil.SilentError {
return
}
var dnsError *net.DNSError
if errors.As(err, &dnsError) {
fmt.Fprintf(out, "error connecting to %s\n", dnsError.Name)
if debug {
fmt.Fprintln(out, dnsError)
}
fmt.Fprintln(out, "check your internet connection or githubstatus.com")
return
}
fmt.Fprintln(out, err)
var flagError *cmdutil.FlagError
if errors.As(err, &flagError) || strings.HasPrefix(err.Error(), "unknown command ") {
if !strings.HasSuffix(err.Error(), "\n") {
fmt.Fprintln(out)
}
fmt.Fprintln(out, cmd.UsageString())
}
}
func shouldCheckForUpdate() bool {
return updaterEnabled != "" && !isCompletionCommand() && utils.IsTerminal(os.Stderr)
}
func isCompletionCommand() bool {
return len(os.Args) > 1 && os.Args[1] == "completion"
}
func checkForUpdate(currentVersion string) (*update.ReleaseInfo, error) {
if !shouldCheckForUpdate() {
return nil, nil
}
client, err := command.BasicClient()
if err != nil {
return nil, err
}
repo := updaterEnabled
stateFilePath := path.Join(config.ConfigDir(), "state.yml")
return update.CheckForUpdate(client, stateFilePath, repo, currentVersion)
}