Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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