diff --git a/main.go b/main.go index df3932b..4d852d2 100644 --- a/main.go +++ b/main.go @@ -21,9 +21,15 @@ const redColor = "\u001B[31m" const greenColor = "\u001B[32m" const endColor = "\u001B[0m" -const successPrefix = greenColor + "●" + endColor -const failPrefix = redColor + "●" + endColor -const errorPrefix = redColor + "!" + endColor +// Colorful prefixes +const ttySuccessPrefix = greenColor + "●" + endColor +const ttyFailPrefix = redColor + "●" + endColor +const ttyErrorPrefix = redColor + "!" + endColor + +// Black & white prefixes. Unicode characters +const bwSuccessPrefix = "✓" +const bwFailPrefix = "𐄂" +const bwErrorPrefix = "!" func main() { app := cli.NewApp() @@ -42,6 +48,12 @@ func main() { log.SetFlags(0) log.SetPrefix("") + isColorful := true + + successPrefix := ttySuccessPrefix + failPrefix := ttyFailPrefix + errorPrefix := ttyErrorPrefix + app.Flags = []cli.Flag{ &cli.BoolFlag{ Name: "generate-man-page", @@ -56,6 +68,11 @@ func main() { Hidden: true, Value: "error", }, + &cli.BoolFlag{ + Name: "no-color", + Hidden: false, + Value: false, + }, } app.Commands = []*cli.Command{ { @@ -128,20 +145,24 @@ func main() { } } - s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) - s.Suffix = " Connecting to Red Hat Subscription Management..." - s.Start() + var s *spinner.Spinner + if isColorful { + s = spinner.New(spinner.CharSets[9], 100*time.Millisecond) + s.Suffix = " Connecting to Red Hat Subscription Management..." + s.Start() + } var err error if c.String("organization") != "" { err = registerActivationKey(c.String("organization"), c.StringSlice("activation-key"), c.String("server")) } else { err = registerPassword(username, password, c.String("server")) } - if err != nil { + if isColorful { s.Stop() + } + if err != nil { return cli.Exit(err, 1) } - s.Stop() fmt.Printf(successPrefix + " Connected to Red Hat Subscription Management\n") } else { fmt.Printf(successPrefix + " This system is already connected to Red Hat Subscription Management\n") @@ -149,26 +170,34 @@ func main() { durations["rhsm"] = time.Since(start) start = time.Now() - s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) - - s.Suffix = " Connecting to Red Hat Insights..." - s.Start() - if err := registerInsights(); err != nil { + var s *spinner.Spinner + if isColorful { + s = spinner.New(spinner.CharSets[9], 100*time.Millisecond) + s.Suffix = " Connecting to Red Hat Insights..." + s.Start() + } + err = registerInsights() + if isColorful { s.Stop() + } + if err != nil { return cli.Exit(err, 1) } - s.Stop() fmt.Printf(successPrefix + " Connected to Red Hat Insights\n") durations["insights"] = time.Since(start) start = time.Now() - s.Suffix = fmt.Sprintf(" Activating the %v daemon", BrandName) - s.Start() - if err := activate(); err != nil { + if isColorful { + s.Suffix = fmt.Sprintf(" Activating the %v daemon", BrandName) + s.Start() + } + err = activate() + if isColorful { s.Stop() + } + if err != nil { return cli.Exit(err, 1) } - s.Stop() fmt.Printf(successPrefix+" Activated the %v daemon\n", BrandName) durations[BrandName] = time.Since(start) @@ -205,40 +234,52 @@ func main() { s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) start = time.Now() - s.Suffix = fmt.Sprintf(" Deactivating the %v daemon", BrandName) - s.Start() - if err := deactivate(); err != nil { - errorMessages[BrandName] = fmt.Errorf("cannot deactivate daemon: %w", err) + if isColorful { + s.Suffix = fmt.Sprintf(" Deactivating the %v daemon", BrandName) + s.Start() + } + err = deactivate() + if isColorful { s.Stop() + } + if err != nil { + errorMessages[BrandName] = fmt.Errorf("cannot deactivate daemon: %w", err) fmt.Printf(errorPrefix+" Cannot deactivate the %v daemon\n", BrandName) } else { - s.Stop() fmt.Printf(failPrefix+" Deactivated the %v daemon\n", BrandName) } durations[BrandName] = time.Since(start) start = time.Now() - s.Suffix = " Disconnecting from Red Hat Insights..." - s.Start() - if err := unregisterInsights(); err != nil { - errorMessages["insights"] = fmt.Errorf("cannot disconnect from Red Hat Insights: %w", err) + if isColorful { + s.Suffix = " Disconnecting from Red Hat Insights..." + s.Start() + } + err = unregisterInsights() + if isColorful { s.Stop() + } + if err != nil { + errorMessages["insights"] = fmt.Errorf("cannot disconnect from Red Hat Insights: %w", err) fmt.Printf(errorPrefix + " Cannot disconnect from Red Hat Insights\n") } else { - s.Stop() fmt.Print(failPrefix + " Disconnected from Red Hat Insights\n") } durations["insights"] = time.Since(start) start = time.Now() - s.Suffix = " Disconnecting from Red Hat Subscription Management..." - s.Start() - if err := unregister(); err != nil { - errorMessages["rhsm"] = fmt.Errorf("cannot disconnect from Red Hat Subscription Management: %w", err) + if isColorful { + s.Suffix = " Disconnecting from Red Hat Subscription Management..." + s.Start() + } + err = unregister() + if isColorful { s.Stop() + } + if err != nil { + errorMessages["rhsm"] = fmt.Errorf("cannot disconnect from Red Hat Subscription Management: %w", err) fmt.Printf(errorPrefix + " Cannot disconnect from Red Hat Subscription Management\n") } else { - s.Stop() fmt.Printf(failPrefix + " Disconnected from Red Hat Subscription Management\n") } durations["rhsm"] = time.Since(start) @@ -312,12 +353,16 @@ func main() { fmt.Printf(successPrefix + " Connected to Red Hat Subscription Management\n") } - s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) - - s.Suffix = " Checking Red Hat Insights..." - s.Start() + var s *spinner.Spinner + if isColorful { + s = spinner.New(spinner.CharSets[9], 100*time.Millisecond) + s.Suffix = " Checking Red Hat Insights..." + s.Start() + } isRegistered, err := insightsIsRegistered() - s.Stop() + if isColorful { + s.Stop() + } if isRegistered { fmt.Print(successPrefix + " Connected to Red Hat Insights\n") @@ -381,6 +426,25 @@ func main() { } log.SetLevel(level) + // Detect if the output goes to TTY or some file + isColorful = isTerminal(os.Stdout.Fd()) + + // When environment variable NO_COLOR is set, then do not display colors and animations too. + // We do not care about value of NO_COLOR variable + if _, isNoColorSet := os.LookupEnv("NO_COLOR"); isNoColorSet { + isColorful = false + } + + if c.Bool("no-color") { + isColorful = false + } + + if !isColorful { + successPrefix = bwSuccessPrefix + failPrefix = bwFailPrefix + errorPrefix = bwErrorPrefix + } + return nil } diff --git a/util.go b/util.go index 4234683..d634bbf 100644 --- a/util.go +++ b/util.go @@ -5,8 +5,15 @@ import ( "io" "github.com/urfave/cli/v2" + "golang.org/x/sys/unix" ) +// isTerminal returns true if the file descriptor is terminal. +func isTerminal(fd uintptr) bool { + _, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) + return err == nil +} + // BashCompleteCommand prints all visible flag options for the given command, // and then recursively calls itself on each subcommand. func BashCompleteCommand(cmd *cli.Command, w io.Writer) {