mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: Add support for executing processes with Windows ConPty (#311)
* Initial agent * fix: Use buffered reader in peer to fix ShortBuffer This prevents a io.ErrShortBuffer from occurring when the byte slice being read is smaller than the chunks sent from the opposite pipe. This makes sense for unordered connections, where transmission is not guarunteed, but does not make sense for TCP-like connections. We use a bufio.Reader when ordered to ensure data isn't lost. * SSH server works! * Start Windows support * Something works * Refactor pty package to support Windows spawn * SSH server now works on Windows * Fix non-Windows * Fix Linux PTY render * FIx linux build tests * Remove agent and wintest * Add test for Windows resize * Fix linting errors * Add Windows environment variables * Add strings import * Add comment for attrs * Add goleak * Add require import
This commit is contained in:
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/coder/coder/cli/clitest"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/console"
|
||||
"github.com/coder/coder/pty/ptytest"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -21,11 +21,12 @@ func TestCli(t *testing.T) {
|
||||
client := coderdtest.New(t)
|
||||
cmd, config := clitest.New(t)
|
||||
clitest.SetupConfig(t, client, config)
|
||||
cons := console.New(t, cmd)
|
||||
pty := ptytest.New(t)
|
||||
cmd.SetIn(pty.Input())
|
||||
cmd.SetOut(pty.Output())
|
||||
go func() {
|
||||
err := cmd.Execute()
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
_, err := cons.ExpectString("coder")
|
||||
require.NoError(t, err)
|
||||
pty.ExpectMatch("coder")
|
||||
}
|
||||
|
||||
+9
-9
@@ -3,10 +3,11 @@ package cli_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/cli/clitest"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/console"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/coder/coder/pty/ptytest"
|
||||
)
|
||||
|
||||
func TestLogin(t *testing.T) {
|
||||
@@ -26,7 +27,9 @@ func TestLogin(t *testing.T) {
|
||||
// accurately detect Windows ptys when they are not attached to a process:
|
||||
// https://github.com/mattn/go-isatty/issues/59
|
||||
root, _ := clitest.New(t, "login", client.URL.String(), "--force-tty")
|
||||
cons := console.New(t, root)
|
||||
pty := ptytest.New(t)
|
||||
root.SetIn(pty.Input())
|
||||
root.SetOut(pty.Output())
|
||||
go func() {
|
||||
err := root.Execute()
|
||||
require.NoError(t, err)
|
||||
@@ -42,12 +45,9 @@ func TestLogin(t *testing.T) {
|
||||
for i := 0; i < len(matches); i += 2 {
|
||||
match := matches[i]
|
||||
value := matches[i+1]
|
||||
_, err := cons.ExpectString(match)
|
||||
require.NoError(t, err)
|
||||
_, err = cons.SendLine(value)
|
||||
require.NoError(t, err)
|
||||
pty.ExpectMatch(match)
|
||||
pty.WriteLine(value)
|
||||
}
|
||||
_, err := cons.ExpectString("Welcome to Coder")
|
||||
require.NoError(t, err)
|
||||
pty.ExpectMatch("Welcome to Coder")
|
||||
})
|
||||
}
|
||||
|
||||
+11
-11
@@ -7,10 +7,10 @@ import (
|
||||
|
||||
"github.com/coder/coder/cli/clitest"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/console"
|
||||
"github.com/coder/coder/database"
|
||||
"github.com/coder/coder/provisioner/echo"
|
||||
"github.com/coder/coder/provisionersdk/proto"
|
||||
"github.com/coder/coder/pty/ptytest"
|
||||
)
|
||||
|
||||
func TestProjectCreate(t *testing.T) {
|
||||
@@ -26,7 +26,9 @@ func TestProjectCreate(t *testing.T) {
|
||||
cmd, root := clitest.New(t, "projects", "create", "--directory", source, "--provisioner", string(database.ProvisionerTypeEcho))
|
||||
clitest.SetupConfig(t, client, root)
|
||||
_ = coderdtest.NewProvisionerDaemon(t, client)
|
||||
console := console.New(t, cmd)
|
||||
pty := ptytest.New(t)
|
||||
cmd.SetIn(pty.Input())
|
||||
cmd.SetOut(pty.Output())
|
||||
closeChan := make(chan struct{})
|
||||
go func() {
|
||||
err := cmd.Execute()
|
||||
@@ -43,10 +45,8 @@ func TestProjectCreate(t *testing.T) {
|
||||
for i := 0; i < len(matches); i += 2 {
|
||||
match := matches[i]
|
||||
value := matches[i+1]
|
||||
_, err := console.ExpectString(match)
|
||||
require.NoError(t, err)
|
||||
_, err = console.SendLine(value)
|
||||
require.NoError(t, err)
|
||||
pty.ExpectMatch(match)
|
||||
pty.WriteLine(value)
|
||||
}
|
||||
<-closeChan
|
||||
})
|
||||
@@ -73,7 +73,9 @@ func TestProjectCreate(t *testing.T) {
|
||||
cmd, root := clitest.New(t, "projects", "create", "--directory", source, "--provisioner", string(database.ProvisionerTypeEcho))
|
||||
clitest.SetupConfig(t, client, root)
|
||||
coderdtest.NewProvisionerDaemon(t, client)
|
||||
cons := console.New(t, cmd)
|
||||
pty := ptytest.New(t)
|
||||
cmd.SetIn(pty.Input())
|
||||
cmd.SetOut(pty.Output())
|
||||
closeChan := make(chan struct{})
|
||||
go func() {
|
||||
err := cmd.Execute()
|
||||
@@ -91,10 +93,8 @@ func TestProjectCreate(t *testing.T) {
|
||||
for i := 0; i < len(matches); i += 2 {
|
||||
match := matches[i]
|
||||
value := matches[i+1]
|
||||
_, err := cons.ExpectString(match)
|
||||
require.NoError(t, err)
|
||||
_, err = cons.SendLine(value)
|
||||
require.NoError(t, err)
|
||||
pty.ExpectMatch(match)
|
||||
pty.WriteLine(value)
|
||||
}
|
||||
<-closeChan
|
||||
})
|
||||
|
||||
+10
-9
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/cli/config"
|
||||
"github.com/coder/coder/coderd"
|
||||
@@ -138,14 +137,9 @@ func isTTY(cmd *cobra.Command) bool {
|
||||
}
|
||||
|
||||
func prompt(cmd *cobra.Command, prompt *promptui.Prompt) (string, error) {
|
||||
var ok bool
|
||||
prompt.Stdin, ok = cmd.InOrStdin().(io.ReadCloser)
|
||||
if !ok {
|
||||
return "", xerrors.New("stdin must be a readcloser")
|
||||
}
|
||||
prompt.Stdout, ok = cmd.OutOrStdout().(io.WriteCloser)
|
||||
if !ok {
|
||||
return "", xerrors.New("stdout must be a readcloser")
|
||||
prompt.Stdin = io.NopCloser(cmd.InOrStdin())
|
||||
prompt.Stdout = readWriteCloser{
|
||||
Writer: cmd.OutOrStdout(),
|
||||
}
|
||||
|
||||
// The prompt library displays defaults in a jarring way for the user
|
||||
@@ -199,3 +193,10 @@ func prompt(cmd *cobra.Command, prompt *promptui.Prompt) (string, error) {
|
||||
|
||||
return value, err
|
||||
}
|
||||
|
||||
// readWriteCloser fakes reads, writes, and closing!
|
||||
type readWriteCloser struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
io.Closer
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@ package cli_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/cli/clitest"
|
||||
"github.com/coder/coder/coderd/coderdtest"
|
||||
"github.com/coder/coder/console"
|
||||
"github.com/coder/coder/provisioner/echo"
|
||||
"github.com/coder/coder/provisionersdk/proto"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/coder/coder/pty/ptytest"
|
||||
)
|
||||
|
||||
func TestWorkspaceCreate(t *testing.T) {
|
||||
@@ -36,7 +37,9 @@ func TestWorkspaceCreate(t *testing.T) {
|
||||
cmd, root := clitest.New(t, "workspaces", "create", project.Name)
|
||||
clitest.SetupConfig(t, client, root)
|
||||
|
||||
cons := console.New(t, cmd)
|
||||
pty := ptytest.New(t)
|
||||
cmd.SetIn(pty.Input())
|
||||
cmd.SetOut(pty.Output())
|
||||
closeChan := make(chan struct{})
|
||||
go func() {
|
||||
err := cmd.Execute()
|
||||
@@ -51,13 +54,10 @@ func TestWorkspaceCreate(t *testing.T) {
|
||||
for i := 0; i < len(matches); i += 2 {
|
||||
match := matches[i]
|
||||
value := matches[i+1]
|
||||
_, err := cons.ExpectString(match)
|
||||
require.NoError(t, err)
|
||||
_, err = cons.SendLine(value)
|
||||
require.NoError(t, err)
|
||||
pty.ExpectMatch(match)
|
||||
pty.WriteLine(value)
|
||||
}
|
||||
_, err := cons.ExpectString("Create")
|
||||
require.NoError(t, err)
|
||||
pty.ExpectMatch("Create")
|
||||
<-closeChan
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user