Skip to content
2 changes: 1 addition & 1 deletion cli/cmd/app_hostname_ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ replicated app hostname ls --app myapp --output json`,
func (r *runners) listAppHostnames(ctx context.Context, outputFormat string) error {
// Only show spinners for table output
showSpinners := outputFormat == "table"
log := logger.NewLogger(r.w)
log := logger.NewLogger(r.w).SetIsTerminal(r.stdoutIsTTY)

// Resolve app ID from slug or ID
appSlugOrID := r.appSlug
Expand Down
27 changes: 20 additions & 7 deletions cli/cmd/app_rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,22 @@ replicated app delete "Custom App" --output json`,
}

func (r *runners) deleteApp(ctx context.Context, cmd *cobra.Command, appName string, opts deleteAppOpts, outputFormat string) error {
log := logger.NewLogger(r.w)
log := logger.NewLogger(r.w).SetIsTerminal(r.stdoutIsTTY)
showSpinners := outputFormat == "table"

log.ActionWithSpinner("Fetching App")
if showSpinners {
log.ActionWithSpinner("Fetching App")
}
app, err := r.kotsAPI.GetApp(ctx, appName, true)
if err != nil {
log.FinishSpinnerWithError()
if showSpinners {
log.FinishSpinnerWithError()
}
return errors.Wrap(err, "list apps")
}
log.FinishSpinner()
if showSpinners {
log.FinishSpinner()
}

apps := []types.AppAndChannels{
{
Expand All @@ -86,13 +93,19 @@ func (r *runners) deleteApp(ctx context.Context, cmd *cobra.Command, appName str
}
}

log.ActionWithSpinner("Deleting App")
if showSpinners {
log.ActionWithSpinner("Deleting App")
}
err = r.kotsAPI.DeleteKOTSApp(ctx, app.ID)
if err != nil {
log.FinishSpinnerWithError()
if showSpinners {
log.FinishSpinnerWithError()
}
return errors.Wrap(err, "delete app")
}
log.FinishSpinner()
if showSpinners {
log.FinishSpinner()
}

return nil
}
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/cluster_kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (r *runners) kubeconfigCluster(_ *cobra.Command, args []string) error {
}

if r.args.kubeconfigStdout {
fmt.Println(string(kubeconfig))
fmt.Print(string(kubeconfig))
return nil
}

Expand All @@ -123,7 +123,7 @@ func (r *runners) kubeconfigCluster(_ *cobra.Command, args []string) error {
return errors.Wrap(err, "write kubeconfig")
}

fmt.Printf("kubeconfig written to %s\n", r.args.kubeconfigPath)
fmt.Fprintf(os.Stderr, "kubeconfig written to %s\n", r.args.kubeconfigPath)
return nil
}

Expand Down Expand Up @@ -180,7 +180,7 @@ func (r *runners) kubeconfigCluster(_ *cobra.Command, args []string) error {
for _, backupPath := range backupPaths {
err := os.Remove(backupPath)
if err != nil {
fmt.Printf("failed to remove backup kubeconfig: %s\n", err.Error())
fmt.Fprintf(os.Stderr, "failed to remove backup kubeconfig: %s\n", err.Error())
}
}
}()
Expand Down Expand Up @@ -215,7 +215,7 @@ func (r *runners) kubeconfigCluster(_ *cobra.Command, args []string) error {
return errors.Wrap(err, "write kubeconfig")
}

fmt.Printf(" ✓ Updated kubernetes context '%s' in '%s'\n", mergedConfig.CurrentContext, kubeconfigPaths[0])
fmt.Fprintf(os.Stderr, " ✓ Updated kubernetes context '%s' in '%s'\n", mergedConfig.CurrentContext, kubeconfigPaths[0])

return nil
}
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/cluster_prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func (r *runners) prepareCluster(_ *cobra.Command, args []string) error {
return errors.New("no app specified")
}

log := logger.NewLogger(r.w)
log := logger.NewLogger(r.w).SetIsTerminal(r.stdoutIsTTY)

release, err := prepareRelease(r, log)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/installer_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (r *runners) installerCreate(_ *cobra.Command, _ []string) error {
return errors.Errorf("Installer specs are only supported for KOTS applications, app %q has type %q", r.appID, r.appType)
}

log := logger.NewLogger(r.w)
log := logger.NewLogger(r.w).SetIsTerminal(r.stdoutIsTTY)
if r.args.createInstallerAutoDefaults {
log.ActionWithSpinner("Reading Environment")
err := r.setKOTSDefaultInstallerParams()
Expand Down
34 changes: 24 additions & 10 deletions cli/cmd/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,12 @@ func (r *runners) runLint(cmd *cobra.Command, args []string) error {
autoDiscoveryMode := len(config.Charts) == 0 && len(config.Preflights) == 0 && len(config.Manifests) == 0

if autoDiscoveryMode {
fmt.Fprintf(r.w, "No .replicated config found. Auto-discovering lintable resources in current directory...\n\n")
r.w.Flush()
showAutoDiscoveryMessages := r.outputFormat == "table"

if showAutoDiscoveryMessages {
fmt.Fprintf(r.w, "No .replicated config found. Auto-discovering lintable resources in current directory...\n\n")
r.w.Flush()
}

// Auto-discover Helm charts (for counting and display)
chartPaths, err := lint2.DiscoverChartPaths(filepath.Join(".", "**"))
Expand Down Expand Up @@ -190,18 +194,28 @@ func (r *runners) runLint(cmd *cobra.Command, args []string) error {
}

// Print what was discovered
fmt.Fprintf(r.w, "Discovered resources:\n")
fmt.Fprintf(r.w, " - %d Helm chart(s)\n", len(chartPaths))
fmt.Fprintf(r.w, " - %d Preflight spec(s)\n", len(preflightPaths))
fmt.Fprintf(r.w, " - %d Support Bundle spec(s)\n", len(sbPaths))
fmt.Fprintf(r.w, " - %d HelmChart manifest(s)\n\n", len(helmChartPaths))
r.w.Flush()
if showAutoDiscoveryMessages {
fmt.Fprintf(r.w, "Discovered resources:\n")
fmt.Fprintf(r.w, " - %d Helm chart(s)\n", len(chartPaths))
fmt.Fprintf(r.w, " - %d Preflight spec(s)\n", len(preflightPaths))
fmt.Fprintf(r.w, " - %d Support Bundle spec(s)\n", len(sbPaths))
fmt.Fprintf(r.w, " - %d HelmChart manifest(s)\n\n", len(helmChartPaths))
r.w.Flush()
}

// If nothing was found and EC linting is not enabled, exit early.
// EC linting runs after this block, so don't bail out when it's enabled.
if len(chartPaths) == 0 && len(preflightPaths) == 0 && len(sbPaths) == 0 && !config.ReplLint.Linters.EmbeddedCluster.IsEnabled() {
fmt.Fprintf(r.w, "No lintable resources found in current directory.\n")
r.w.Flush()
if showAutoDiscoveryMessages {
fmt.Fprintf(r.w, "No lintable resources found in current directory.\n")
r.w.Flush()
}
if r.outputFormat == "json" {
output.Summary = r.calculateOverallSummary(output)
if err := print.LintResults(r.outputFormat, r.w, output); err != nil {
return errors.Wrap(err, "failed to print JSON output to stdout")
}
}
return nil
}
}
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/release_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func (r *runners) releaseCreate(cmd *cobra.Command, args []string) (err error) {
printIfError(cmd, err)
}()

log := logger.NewLogger(r.w)
log := logger.NewLogger(r.w).SetIsTerminal(r.stdoutIsTTY)
if r.outputFormat == "json" {
// suppress log lines for machine-readable output
log.Silence()
Expand Down
4 changes: 2 additions & 2 deletions cli/cmd/release_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (r *runners) releaseDownload(command *cobra.Command, args []string) error {
return r.releaseInspect(command, args)
}

log := logger.NewLogger(os.Stdout)
log := logger.NewLogger(os.Stderr)

// Determine sequence to download
var seq int64
Expand Down Expand Up @@ -280,7 +280,7 @@ func (r *runners) downloadReleaseArchive(seq int64, dest string) error {
}
defer os.RemoveAll(tempDir)

log := logger.NewLogger(os.Stdout)
log := logger.NewLogger(os.Stderr)
if err := kotsrelease.Save(tempDir, release, log); err != nil {
return errors.Wrap(err, "save release to temp dir")
}
Expand Down
20 changes: 16 additions & 4 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"text/tabwriter"

"github.com/Masterminds/sprig/v3"
"github.com/mattn/go-isatty"
"github.com/pkg/errors"
"github.com/replicatedhq/replicated/client"
replicatedcache "github.com/replicatedhq/replicated/pkg/cache"
Expand Down Expand Up @@ -104,20 +105,31 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e
func Execute(rootCmd *cobra.Command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
w := tabwriter.NewWriter(stdout, minWidth, tabWidth, padding, padChar, tabwriter.TabIndent)

stdoutIsTTY := false
if f, ok := stdout.(*os.File); ok {
stdoutIsTTY = isatty.IsTerminal(f.Fd())
}

// get api client and app ID after flags are parsed
runCmds := &runners{
rootCmd: rootCmd,
stdin: stdin,
w: w,
rootCmd: rootCmd,
stdin: stdin,
w: w,
stdoutIsTTY: stdoutIsTTY,
}
if runCmds.rootCmd == nil {
runCmds.rootCmd = GetRootCmd()
}
if stderr != nil {
runCmds.rootCmd.SetErr(stderr)
runCmds.rootCmd.SetOut(stderr)
Comment thread
cursor[bot] marked this conversation as resolved.
}
if stdout != nil {
runCmds.rootCmd.SetOut(stdout)
defaultHelpFunc := runCmds.rootCmd.HelpFunc()
runCmds.rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
cmd.SetOut(stdout)
defaultHelpFunc(cmd, args)
})
}

// Setup PersistentPreRun to handle --debug flag
Expand Down
1 change: 1 addition & 0 deletions cli/cmd/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type runners struct {
stdin io.Reader
outputFormat string
w *tabwriter.Writer
stdoutIsTTY bool

rootCmd *cobra.Command
args runnerArgs
Expand Down
32 changes: 27 additions & 5 deletions pkg/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Logger struct {
spinnerArgs []interface{}
isSilent bool
isVerbose bool
isTerminal *bool
}

func NewLogger(writer io.Writer) *Logger {
Expand All @@ -26,6 +27,27 @@ func NewLogger(writer io.Writer) *Logger {
}
}

// SetIsTerminal lets callers override TTY detection. Useful when the
// logger writes through a wrapper (e.g. tabwriter) that hides the
// underlying file descriptor.
func (l *Logger) SetIsTerminal(isTerminal bool) *Logger {
if l == nil {
return l
}
l.isTerminal = &isTerminal
return l
}

func (l *Logger) isTTY() bool {
if l.isTerminal != nil {
return *l.isTerminal
}
if f, ok := l.w.(*os.File); ok {
return isatty.IsTerminal(f.Fd())
}
return false
}
Comment thread
cursor[bot] marked this conversation as resolved.

func (l *Logger) Silence() {
if l == nil {
return
Expand Down Expand Up @@ -107,7 +129,7 @@ func (l *Logger) ActionWithSpinner(msg string, args ...interface{}) {
fmt.Fprintf(l.w, " • ")
fmt.Fprintf(l.w, msg, args...)

if isatty.IsTerminal(os.Stdout.Fd()) {
if l.isTTY() {
s := spin.New()

fmt.Fprintf(l.w, " %s", s.Next())
Expand Down Expand Up @@ -140,7 +162,7 @@ func (l *Logger) ChildActionWithSpinner(msg string, args ...interface{}) {
fmt.Fprintf(l.w, " • ")
fmt.Fprintf(l.w, msg, args...)

if isatty.IsTerminal(os.Stdout.Fd()) {
if l.isTTY() {
s := spin.New()

fmt.Fprintf(l.w, " %s", s.Next())
Expand Down Expand Up @@ -178,7 +200,7 @@ func (l *Logger) FinishChildSpinner() {
green.Fprintf(l.w, " ✓")
fmt.Fprintf(l.w, " \n")

if isatty.IsTerminal(os.Stdout.Fd()) {
if l.isTTY() {
l.spinnerStopCh <- true
close(l.spinnerStopCh)
}
Expand Down Expand Up @@ -207,7 +229,7 @@ func (l *Logger) FinishSpinner() {
green.Fprintf(l.w, " ✓")
fmt.Fprintf(l.w, " \n")

if isatty.IsTerminal(os.Stdout.Fd()) {
if l.isTTY() {
l.spinnerStopCh <- true
close(l.spinnerStopCh)
}
Expand All @@ -226,7 +248,7 @@ func (l *Logger) FinishSpinnerWithError() {
red.Fprintf(l.w, " ✗")
fmt.Fprintf(l.w, " \n")

if isatty.IsTerminal(os.Stdout.Fd()) {
if l.isTTY() {
l.spinnerStopCh <- true
close(l.spinnerStopCh)
}
Expand Down
Loading