github.com/criteo/command-launcher@v0.0.0-20230407142452-fb616f546e98/internal/console/console.go (about)

     1  package console
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"runtime"
     7  	"strings"
     8  
     9  	"github.com/fatih/color"
    10  	ps "github.com/mitchellh/go-ps"
    11  	log "github.com/sirupsen/logrus"
    12  )
    13  
    14  var (
    15  	colorWarn               = color.New(color.FgHiYellow).Add(color.BgBlack)
    16  	isAnsiSequenceSupported = checkAnsiSequenceSupported()
    17  )
    18  
    19  func processName() string {
    20  	if runtime.GOOS == "windows" {
    21  		return "cdt.exe"
    22  	}
    23  
    24  	return "cdt"
    25  }
    26  
    27  func parentName() (string, error) {
    28  	parent, err := ps.FindProcess(os.Getppid())
    29  	if err != nil {
    30  		return "", err
    31  	}
    32  
    33  	if parent.Executable() == processName() {
    34  		parent, err = ps.FindProcess(parent.PPid())
    35  		if err != nil {
    36  			return "", err
    37  		}
    38  	}
    39  
    40  	return parent.Executable(), nil
    41  }
    42  
    43  func checkAnsiSequenceSupported() bool {
    44  	maybeSupported := !color.NoColor
    45  	// The Powershell console does not support the escape ANSI chars
    46  	if runtime.GOOS == "windows" && maybeSupported {
    47  		parent, err := parentName()
    48  		if err != nil {
    49  			maybeSupported = false
    50  		} else {
    51  			log.Debugf("Parent Process name %s", parent)
    52  			maybeSupported = strings.ToLower(parent) != "powershell.exe"
    53  		}
    54  	}
    55  
    56  	log.Debugf("ANSI sequences are supported by the console: %t", maybeSupported)
    57  	return maybeSupported
    58  }
    59  
    60  // When the ANSI sequence is supported, the console will display the colors and cursor moves
    61  //
    62  // On Windows, when cdt runs in a powershell console, the ANSI sequences are not supported.
    63  func IsAnsiSequenceSupported() bool {
    64  	return isAnsiSequenceSupported
    65  }
    66  
    67  // Color code
    68  //
    69  // Blue: for highlighted informative text
    70  // Magenta: for interactive questions, reminder
    71  // Yellow: for warning
    72  // Red: for errors
    73  
    74  // highlight informative text in the output so that
    75  // user can distinguish different steps in the output
    76  // for example: highlight the command used under the hood
    77  // see: hotfix create, hotfix review
    78  func Highlight(format string, a ...interface{}) {
    79  	if isAnsiSequenceSupported {
    80  		color.Blue(format, a...)
    81  	} else {
    82  		fmt.Printf(format, a...)
    83  	}
    84  }
    85  
    86  // usually used as a reminder, a question, or additional
    87  // information that need the user interact, but not mandatory.
    88  // for example: ask for user to update
    89  func Reminder(format string, a ...interface{}) {
    90  	if isAnsiSequenceSupported {
    91  		color.Magenta(format, a...)
    92  	} else {
    93  		fmt.Printf(format, a...)
    94  	}
    95  }
    96  
    97  // usually used as warning message
    98  func Warn(format string, a ...interface{}) {
    99  	if isAnsiSequenceSupported {
   100  		colorWarn.Printf(format, a...)
   101  	} else {
   102  		fmt.Printf(format, a...)
   103  	}
   104  }
   105  
   106  // usually used as error message
   107  func Error(format string, a ...interface{}) {
   108  	if isAnsiSequenceSupported {
   109  		color.Red(format, a...)
   110  	} else {
   111  		fmt.Printf(format, a...)
   112  	}
   113  }
   114  
   115  // usually used as success message
   116  func Success(format string, a ...interface{}) {
   117  	if isAnsiSequenceSupported {
   118  		color.Green(format, a...)
   119  	} else {
   120  		fmt.Printf(format, a...)
   121  	}
   122  }