Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

chore: limit direct uses of os.Stdout/os.Stderr/os.Stdin #278

Merged
merged 1 commit into from
Mar 10, 2021
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
10 changes: 4 additions & 6 deletions internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
package cmd

import (
"os"

"github.com/spf13/cobra"
"github.com/spf13/cobra/doc"

Expand Down Expand Up @@ -106,13 +104,13 @@ $ coder completion fish > ~/.config/fish/completions/coder.fish
Run: func(cmd *cobra.Command, args []string) {
switch args[0] {
case "bash":
_ = cmd.Root().GenBashCompletion(os.Stdout) // Best effort.
_ = cmd.Root().GenBashCompletion(cmd.OutOrStdout()) // Best effort.
case "zsh":
_ = cmd.Root().GenZshCompletion(os.Stdout) // Best effort.
_ = cmd.Root().GenZshCompletion(cmd.OutOrStdout()) // Best effort.
case "fish":
_ = cmd.Root().GenFishCompletion(os.Stdout, true) // Best effort.
_ = cmd.Root().GenFishCompletion(cmd.OutOrStdout(), true) // Best effort.
case "powershell":
_ = cmd.Root().GenPowerShellCompletion(os.Stdout) // Best effort.
_ = cmd.Root().GenPowerShellCompletion(cmd.OutOrStdout()) // Best effort.
}
},
}
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/envs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"io"
"io/ioutil"
"net/url"
"os"

"cdr.dev/coder-cli/coder-sdk"
"cdr.dev/coder-cli/internal/coderutil"
Expand Down Expand Up @@ -82,7 +81,7 @@ func lsEnvsCommand() *cobra.Command {
return xerrors.Errorf("write table: %w", err)
}
case jsonOutput:
err := json.NewEncoder(os.Stdout).Encode(envs)
err := json.NewEncoder(cmd.OutOrStdout()).Encode(envs)
if err != nil {
return xerrors.Errorf("write environments as JSON: %w", err)
}
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

import (
"encoding/json"
"os"

"github.com/spf13/cobra"
"golang.org/x/xerrors"
Expand Down Expand Up @@ -62,7 +61,7 @@ func lsImgsCommand(user *string) *cobra.Command {

switch outputFmt {
case jsonOutput:
enc := json.NewEncoder(os.Stdout)
enc := json.NewEncoder(cmd.OutOrStdout())
// pretty print the json
enc.SetIndent("", "\t")

Expand Down
14 changes: 7 additions & 7 deletions internal/cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"bufio"
"context"
"fmt"
"io"
"net/url"
"os"
"strings"

"github.com/pkg/browser"
Expand Down Expand Up @@ -40,7 +40,7 @@ func loginCmd() *cobra.Command {
// From this point, the commandline is correct.
// Don't return errors as it would print the usage.

if err := login(cmd.Context(), u); err != nil {
if err := login(cmd, u); err != nil {
return xerrors.Errorf("login error: %w", err)
}
return nil
Expand All @@ -60,7 +60,7 @@ func storeConfig(envURL *url.URL, sessionToken string, urlCfg, sessionCfg config
return nil
}

func login(ctx context.Context, envURL *url.URL) error {
func login(cmd *cobra.Command, envURL *url.URL) error {
authURL := *envURL
authURL.Path = envURL.Path + "/internal-auth"
q := authURL.Query()
Expand All @@ -73,8 +73,8 @@ func login(ctx context.Context, envURL *url.URL) error {
fmt.Printf("Your browser has been opened to visit:\n\n\t%s\n\n", authURL.String())
}

token := readLine("Paste token here: ")
if err := pingAPI(ctx, envURL, token); err != nil {
token := readLine("Paste token here: ", cmd.InOrStdin())
if err := pingAPI(cmd.Context(), envURL, token); err != nil {
return xerrors.Errorf("ping API with credentials: %w", err)
}
if err := storeConfig(envURL, token, config.URL, config.Session); err != nil {
Expand All @@ -84,8 +84,8 @@ func login(ctx context.Context, envURL *url.URL) error {
return nil
}

func readLine(prompt string) string {
reader := bufio.NewReader(os.Stdin)
func readLine(prompt string, r io.Reader) string {
reader := bufio.NewReader(r)
fmt.Print(prompt)
text, _ := reader.ReadString('\n')
return strings.TrimSuffix(text, "\n")
Expand Down
4 changes: 1 addition & 3 deletions internal/cmd/rebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ package cmd
import (
"context"
"fmt"
"os"
"strings"
"time"

"github.com/briandowns/spinner"
"github.com/fatih/color"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/xerrors"

"cdr.dev/coder-cli/coder-sdk"
Expand Down Expand Up @@ -85,7 +83,7 @@ func trailBuildLogs(ctx context.Context, client coder.Client, envID string) erro
newSpinner := func() *spinner.Spinner { return spinner.New(spinner.CharSets[11], 100*time.Millisecond) }

// this tells us whether to show dynamic loaders when printing output
isTerminal := terminal.IsTerminal(int(os.Stdout.Fd()))
isTerminal := showInteractiveOutput

logs, err := client.FollowEnvironmentBuildLog(ctx, envID)
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/resourcemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cmd
import (
"fmt"
"io"
"os"
"sort"
"text/tabwriter"

Expand Down Expand Up @@ -96,7 +95,7 @@ func runResourceTop(options *resourceTopOptions) func(cmd *cobra.Command, args [
return xerrors.Errorf("unknown --group %q", options.group)
}

return printResourceTop(os.Stdout, groups, labeler, options.showEmptyGroups, options.sortBy)
return printResourceTop(cmd.OutOrStdout(), groups, labeler, options.showEmptyGroups, options.sortBy)
}
}

Expand Down
38 changes: 20 additions & 18 deletions internal/cmd/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ import (
"cdr.dev/coder-cli/pkg/clog"
)

var (
showInteractiveOutput = terminal.IsTerminal(int(os.Stdout.Fd()))
outputFd = os.Stdout.Fd()
inputFd = os.Stdin.Fd()
)

func getEnvsForCompletion(user string) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
ctx := cmd.Context()
Expand Down Expand Up @@ -146,15 +152,14 @@ func shell(cmd *cobra.Command, cmdArgs []string) error {
}

// TODO: Verify this is the correct behavior
isInteractive := terminal.IsTerminal(int(os.Stdout.Fd()))
if isInteractive { // checkAndRebuildEnvironment requires an interactive shell
if showInteractiveOutput { // checkAndRebuildEnvironment requires an interactive shell
// Checks & Rebuilds the environment if needed.
if err := checkAndRebuildEnvironment(ctx, client, env); err != nil {
return err
}
}

if err := runCommand(ctx, client, env, command, args); err != nil {
if err := runCommand(cmd, client, env, command, args); err != nil {
if exitErr, ok := err.(wsep.ExitError); ok {
os.Exit(exitErr.Code)
}
Expand Down Expand Up @@ -309,26 +314,23 @@ func sendResizeEvents(ctx context.Context, termFD uintptr, process wsep.Process)
}
}

func runCommand(ctx context.Context, client coder.Client, env *coder.Environment, command string, args []string) error {
termFD := os.Stdout.Fd()

isInteractive := terminal.IsTerminal(int(termFD))
if isInteractive {
func runCommand(cmd *cobra.Command, client coder.Client, env *coder.Environment, command string, args []string) error {
if showInteractiveOutput {
// If the client has a tty, take over it by setting the raw mode.
// This allows for all input to be directly forwarded to the remote process,
// otherwise, the local terminal would buffer input, interpret special keys, etc.
stdinState, err := xterminal.MakeRaw(os.Stdin.Fd())
stdinState, err := xterminal.MakeRaw(inputFd)
if err != nil {
return err
}
defer func() {
// Best effort. If this fails it will result in a broken terminal,
// but there is nothing we can do about it.
_ = xterminal.Restore(os.Stdin.Fd(), stdinState)
_ = xterminal.Restore(inputFd, stdinState)
}()
}

ctx, cancel := context.WithCancel(ctx)
ctx, cancel := context.WithCancel(cmd.Context())
defer cancel()

conn, err := coderutil.DialEnvWsep(ctx, client, env)
Expand All @@ -338,7 +340,7 @@ func runCommand(ctx context.Context, client coder.Client, env *coder.Environment
go heartbeat(ctx, conn, 15*time.Second)

var cmdEnv []string
if isInteractive {
if showInteractiveOutput {
term := os.Getenv("TERM")
if term == "" {
term = "xterm"
Expand All @@ -350,7 +352,7 @@ func runCommand(ctx context.Context, client coder.Client, env *coder.Environment
process, err := execer.Start(ctx, wsep.Command{
Command: command,
Args: args,
TTY: isInteractive,
TTY: showInteractiveOutput,
Stdin: true,
Env: cmdEnv,
})
Expand All @@ -363,8 +365,8 @@ func runCommand(ctx context.Context, client coder.Client, env *coder.Environment
}

// Now that the remote process successfully started, if we have a tty, start the resize event watcher.
if isInteractive {
go sendResizeEvents(ctx, termFD, process)
if showInteractiveOutput {
go sendResizeEvents(ctx, outputFd, process)
}

go func() {
Expand All @@ -373,17 +375,17 @@ func runCommand(ctx context.Context, client coder.Client, env *coder.Environment

ap := activity.NewPusher(client, env.ID, sshActivityName)
wr := ap.Writer(stdin)
if _, err := io.Copy(wr, os.Stdin); err != nil {
if _, err := io.Copy(wr, cmd.InOrStdin()); err != nil {
cancel()
}
}()
go func() {
if _, err := io.Copy(os.Stdout, process.Stdout()); err != nil {
if _, err := io.Copy(cmd.OutOrStdout(), process.Stdout()); err != nil {
cancel()
}
}()
go func() {
if _, err := io.Copy(os.Stderr, process.Stderr()); err != nil {
if _, err := io.Copy(cmd.ErrOrStderr(), process.Stderr()); err != nil {
cancel()
}
}()
Expand Down
14 changes: 9 additions & 5 deletions internal/cmd/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,15 @@ func makeRunSync(init *bool) func(cmd *cobra.Command, args []string) error {
}

s := sync.Sync{
Init: *init,
Env: *env,
RemoteDir: remoteDir,
LocalDir: absLocal,
Client: client,
Init: *init,
Env: *env,
RemoteDir: remoteDir,
LocalDir: absLocal,
Client: client,
OutW: cmd.OutOrStdout(),
ErrW: cmd.ErrOrStderr(),
InputReader: cmd.InOrStdin(),
IsInteractiveOutput: showInteractiveOutput,
}

localVersion := rsyncVersion()
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

import (
"encoding/json"
"os"

"github.com/spf13/cobra"
"golang.org/x/xerrors"
Expand Down Expand Up @@ -113,7 +112,7 @@ func tagsLsCmd() *cobra.Command {
return err
}
case jsonOutput:
err := json.NewEncoder(os.Stdout).Encode(tags)
err := json.NewEncoder(cmd.OutOrStdout()).Encode(tags)
if err != nil {
return err
}
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cmd
import (
"encoding/json"
"fmt"
"os"

"github.com/spf13/cobra"
"golang.org/x/xerrors"
Expand Down Expand Up @@ -56,7 +55,7 @@ func lsTokensCmd() *cobra.Command {
return xerrors.Errorf("write table: %w", err)
}
case jsonOutput:
err := json.NewEncoder(os.Stdout).Encode(tokens)
err := json.NewEncoder(cmd.OutOrStdout()).Encode(tokens)
if err != nil {
return xerrors.Errorf("write tokens as JSON: %w", err)
}
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/urls.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -107,7 +106,7 @@ func listDevURLsCmd(outputFmt *string) func(cmd *cobra.Command, args []string) e
return xerrors.Errorf("write table: %w", err)
}
case jsonOutput:
if err := json.NewEncoder(os.Stdout).Encode(devURLs); err != nil {
if err := json.NewEncoder(cmd.OutOrStdout()).Encode(devURLs); err != nil {
return xerrors.Errorf("encode DevURLs as json: %w", err)
}
default:
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

import (
"encoding/json"
"os"

"github.com/spf13/cobra"
"golang.org/x/xerrors"
Expand Down Expand Up @@ -51,7 +50,7 @@ func listUsers(outputFmt *string) func(cmd *cobra.Command, args []string) error
return xerrors.Errorf("write table: %w", err)
}
case "json":
if err := json.NewEncoder(os.Stdout).Encode(users); err != nil {
if err := json.NewEncoder(cmd.OutOrStdout()).Encode(users); err != nil {
return xerrors.Errorf("encode users as json: %w", err)
}
default:
Expand Down
Loading