Skip to content

Commit

Permalink
Build for windows
Browse files Browse the repository at this point in the history
  • Loading branch information
cmoog committed Jul 28, 2020
1 parent 2888401 commit 97f3cea
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 93 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ jobs:
- name: test
uses: ./ci/image
with:
args: go test ./...
args: go test ./...
4 changes: 4 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
)

func TestRemoteStdin(t *testing.T) {
t.Parallel()
inputs := []string{
"pwd",
"echo 123\n456",
Expand Down Expand Up @@ -72,6 +73,7 @@ func mockConn(ctx context.Context, t *testing.T) (*websocket.Conn, *httptest.Ser
}

func TestRemoteExec(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()

Expand All @@ -83,6 +85,7 @@ func TestRemoteExec(t *testing.T) {
}

func TestRemoteExecFail(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()

Expand Down Expand Up @@ -111,6 +114,7 @@ func testExecerFail(ctx context.Context, t *testing.T, execer Execer) {
}

func TestStderrVsStdout(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()

Expand Down
7 changes: 5 additions & 2 deletions dev/client/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// +build !windows

package main

import (
Expand All @@ -9,10 +11,11 @@ import (

"cdr.dev/wsep"
"github.com/spf13/pflag"
"go.coder.com/cli"
"go.coder.com/flog"
"golang.org/x/crypto/ssh/terminal"
"nhooyr.io/websocket"

"go.coder.com/cli"
"go.coder.com/flog"
)

type notty struct {
Expand Down
87 changes: 0 additions & 87 deletions localexec.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
package wsep

import (
"bytes"
"context"
"io"
"io/ioutil"
"os"
"os/exec"
"syscall"

"github.com/creack/pty"
"golang.org/x/xerrors"
)

// LocalExecer executes command on the local system.
type LocalExecer struct {
}

type localProcess struct {
// tty may be nil
tty *os.File
cmd *exec.Cmd

stdin io.WriteCloser
stdout io.Reader
stderr io.Reader
}

func (l *localProcess) Stdin() io.WriteCloser {
return l.stdin
}
Expand All @@ -53,81 +37,10 @@ func (l *localProcess) Close() error {
return l.cmd.Process.Kill()
}

func (l *localProcess) Resize(ctx context.Context, rows, cols uint16) error {
if l.tty == nil {
return nil
}
return pty.Setsize(l.tty, &pty.Winsize{
Rows: rows,
Cols: cols,
})
}

func (l *localProcess) Pid() int {
return l.cmd.Process.Pid
}

// Start executes the given command locally
func (l LocalExecer) Start(ctx context.Context, c Command) (Process, error) {
var (
process localProcess
err error
)
process.cmd = exec.CommandContext(ctx, c.Command, c.Args...)
process.cmd.Env = append(os.Environ(), c.Env...)
process.cmd.Dir = c.WorkingDir

if c.GID != 0 || c.UID != 0 {
process.cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{},
}
}
if c.GID != 0 {
process.cmd.SysProcAttr.Credential.Gid = c.GID
}
if c.UID != 0 {
process.cmd.SysProcAttr.Credential.Uid = c.UID
}

if c.TTY {
// This special WSEP_TTY variable helps debug unexpected TTYs.
process.cmd.Env = append(process.cmd.Env, "WSEP_TTY=true")
process.tty, err = pty.Start(process.cmd)
if err != nil {
return nil, xerrors.Errorf("start command with pty: %w", err)
}
process.stdout = process.tty
process.stderr = ioutil.NopCloser(bytes.NewReader(nil))
process.stdin = process.tty
} else {
if c.Stdin {
process.stdin, err = process.cmd.StdinPipe()
if err != nil {
return nil, xerrors.Errorf("create pipe: %w", err)
}
} else {
process.stdin = disabledStdinWriter{}
}

process.stdout, err = process.cmd.StdoutPipe()
if err != nil {
return nil, xerrors.Errorf("create pipe: %w", err)
}

process.stderr, err = process.cmd.StderrPipe()
if err != nil {
return nil, xerrors.Errorf("create pipe: %w", err)
}

err = process.cmd.Start()
if err != nil {
return nil, xerrors.Errorf("start command: %w", err)
}
}

return &process, nil
}

type disabledStdinWriter struct{}

func (w disabledStdinWriter) Close() error {
Expand Down
5 changes: 4 additions & 1 deletion localexec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
)

func TestLocalExec(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()

Expand Down Expand Up @@ -58,11 +59,12 @@ func testExecer(ctx context.Context, t *testing.T, execer Execer) {
}

func TestExitCode(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

process, err := LocalExecer{}.Start(ctx, Command{
Command: "/bin/sh",
Command: "sh",
Args: []string{"-c", `"fakecommand"`},
})
assert.Success(t, "start local cmd", err)
Expand Down Expand Up @@ -97,6 +99,7 @@ func TestStdin(t *testing.T) {
}

func TestStdinFail(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Expand Down
97 changes: 97 additions & 0 deletions localexec_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// +build !windows

package wsep

import (
"bytes"
"context"
"io"
"io/ioutil"
"os"
"os/exec"
"syscall"

"github.com/creack/pty"
"golang.org/x/xerrors"
)

type localProcess struct {
// tty may be nil
tty *os.File
cmd *exec.Cmd

stdin io.WriteCloser
stdout io.Reader
stderr io.Reader
}

func (l *localProcess) Resize(_ context.Context, rows, cols uint16) error {
if l.tty == nil {
return nil
}
return pty.Setsize(l.tty, &pty.Winsize{
Rows: rows,
Cols: cols,
})
}

// Start executes the given command locally
func (l LocalExecer) Start(ctx context.Context, c Command) (Process, error) {
var (
process localProcess
err error
)
process.cmd = exec.CommandContext(ctx, c.Command, c.Args...)
process.cmd.Env = append(os.Environ(), c.Env...)
process.cmd.Dir = c.WorkingDir

if c.GID != 0 || c.UID != 0 {
process.cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{},
}
}
if c.GID != 0 {
process.cmd.SysProcAttr.Credential.Gid = c.GID
}
if c.UID != 0 {
process.cmd.SysProcAttr.Credential.Uid = c.UID
}

if c.TTY {
// This special WSEP_TTY variable helps debug unexpected TTYs.
process.cmd.Env = append(process.cmd.Env, "WSEP_TTY=true")
process.tty, err = pty.Start(process.cmd)
if err != nil {
return nil, xerrors.Errorf("start command with pty: %w", err)
}
process.stdout = process.tty
process.stderr = ioutil.NopCloser(bytes.NewReader(nil))
process.stdin = process.tty
} else {
if c.Stdin {
process.stdin, err = process.cmd.StdinPipe()
if err != nil {
return nil, xerrors.Errorf("create pipe: %w", err)
}
} else {
process.stdin = disabledStdinWriter{}
}

process.stdout, err = process.cmd.StdoutPipe()
if err != nil {
return nil, xerrors.Errorf("create pipe: %w", err)
}

process.stderr, err = process.cmd.StderrPipe()
if err != nil {
return nil, xerrors.Errorf("create pipe: %w", err)
}

err = process.cmd.Start()
if err != nil {
return nil, xerrors.Errorf("start command: %w", err)
}
}

return &process, nil
}
30 changes: 30 additions & 0 deletions localexec_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// +build windows

package wsep

import (
"context"
"io"
"os/exec"

"golang.org/x/xerrors"
)

type localProcess struct {
// tty may be nil
tty uintptr
cmd *exec.Cmd

stdin io.WriteCloser
stdout io.Reader
stderr io.Reader
}

func (l *localProcess) Resize(_ context.Context, rows, cols uint16) error {
return xerrors.Errorf("Windows local execution is not supported")
}

// Start executes the given command locally
func (l LocalExecer) Start(ctx context.Context, c Command) (Process, error) {
return nil, xerrors.Errorf("Windows local execution is not supported")
}
6 changes: 4 additions & 2 deletions tty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
)

func TestTTY(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

Expand All @@ -26,11 +28,11 @@ func TestTTY(t *testing.T) {

func testTTY(ctx context.Context, t *testing.T, e Execer) {
process, err := e.Start(ctx, Command{
Command: "bash",
Command: "sh",
TTY: true,
Stdin: true,
})
assert.Success(t, "start bash", err)
assert.Success(t, "start sh", err)
var wg sync.WaitGroup
wg.Add(1)
go func() {
Expand Down

0 comments on commit 97f3cea

Please sign in to comment.