Skip to content

Commit

Permalink
feat: Better support for non-interactive mode
Browse files Browse the repository at this point in the history
* When stdout is not TTY, then do not display spinner and status
  text and the output of rhc should not be colorful, because
  output is redirected to some file. When temporary status
  messages and escape sequences were added to log file, then
  viewing such file could be complicated.
* When NO_COLOR environment variable is set, then do not
  display color nor animation too.
* When CLI option --no-color is used, then colors and
  animations are suppressed too. Note: this is global
  option and could not be used after sub-command.
* This commit closes #14 issue
  • Loading branch information
jirihnidek committed Oct 21, 2022
1 parent 58fb6c5 commit 0d153d0
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 38 deletions.
140 changes: 102 additions & 38 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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",
Expand All @@ -56,6 +68,11 @@ func main() {
Hidden: true,
Value: "error",
},
&cli.BoolFlag{
Name: "no-color",
Hidden: false,
Value: false,
},
}
app.Commands = []*cli.Command{
{
Expand Down Expand Up @@ -128,47 +145,59 @@ 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")
}
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)

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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
}

Expand Down
7 changes: 7 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 0d153d0

Please sign in to comment.