Skip to content

Commit

Permalink
retracing steps by re-adding syscallDup along with variations for mor…
Browse files Browse the repository at this point in the history
…e GOOS
  • Loading branch information
mohammed90 committed Nov 22, 2019
1 parent 37c2426 commit 7d237fd
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 43 deletions.
77 changes: 34 additions & 43 deletions internal/remote/output_interceptor.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package remote

import (
"bytes"
"errors"
"io"
"io/ioutil"
Expand All @@ -19,46 +18,45 @@ type OutputInterceptor interface {
}

func NewOutputInterceptor() OutputInterceptor {
return &outputInterceptor{buffer: &bytes.Buffer{}}
return &outputInterceptor{}
}

type outputInterceptor struct {
origStdout *os.File
origStderr *os.File
readSources [2]io.ReadCloser // stores the reader pipes form os.Pipe() for closure.
streamTarget *os.File
combinedReader io.Reader
intercepting bool
tailer io.Reader
buffer *bytes.Buffer
redirectFile *os.File
streamTarget *os.File
intercepting bool
tailer io.Reader
}

func (interceptor *outputInterceptor) StartInterceptingOutput() error {
if interceptor.intercepting {
return errors.New("Already intercepting output!")
}
interceptor.origStdout = os.Stdout
interceptor.origStderr = os.Stderr
stdoutRead, stdoutWrite, err := os.Pipe()
interceptor.intercepting = true

var err error
interceptor.redirectFile, err = ioutil.TempFile("", "ginkgo-output")
if err != nil {
return err
}
stderrRead, stderrWrite, err := os.Pipe()
if err != nil {

// Call a function in ./syscall_dup_*.go
// If building for plan9, use Dup. If building for Windows, use SetStdHandle. If building everything
// other than linux_arm64 or plan9 or Windows, use a "normal" syscall.Dup2(oldfd, newfd) call.
// If building for linux_arm64 (which doesn't have syscall.Dup2), call syscall.Dup3(oldfd, newfd, 0).
// They are nearly identical, see: http://linux.die.net/man/2/dup3
if err := syscallDup(int(interceptor.redirectFile.Fd()), 1); err != nil {
os.Remove(interceptor.redirectFile.Name())
return err
}
if err := syscallDup(int(interceptor.redirectFile.Fd()), 2); err != nil {
os.Remove(interceptor.redirectFile.Name())
return err
}

os.Stdout = stdoutWrite
os.Stderr = stderrWrite

interceptor.intercepting = true

interceptor.readSources = [2]io.ReadCloser{stderrRead, stderrRead}
interceptor.combinedReader = io.TeeReader(io.MultiReader(stderrRead, stdoutRead), interceptor.buffer)

// if interceptor.streamTarget != nil {
// interceptor.tailer = io.TeeReader(interceptor.combinedReader, interceptor.streamTarget)
// }
if interceptor.streamTarget != nil {
interceptor.tailer = io.TeeReader(interceptor.redirectFile, interceptor.streamTarget)
}

return nil
}
Expand All @@ -68,28 +66,21 @@ func (interceptor *outputInterceptor) StopInterceptingAndReturnOutput() (string,
return "", errors.New("Not intercepting output!")
}

output, err := ioutil.ReadAll(interceptor.buffer)

currStdout := os.Stdout
currStdout.Close()
currStderr := os.Stderr
currStderr.Close()
interceptor.redirectFile.Close()
output, err := ioutil.ReadFile(interceptor.redirectFile.Name())
//os.Remove(interceptor.redirectFile.Name())

os.Stdout = interceptor.origStdout
os.Stderr = interceptor.origStderr
interceptor.intercepting = false

for _, r := range interceptor.readSources {
if closerErr := r.Close(); closerErr != nil {
err = closerErr
if interceptor.streamTarget != nil {
// reading the redirectFile causes the io.TeeReader to write to streamTarget,
// so we just need to sync.
er := interceptor.streamTarget.Sync()
if er != nil {
err = er
}
}

interceptor.intercepting = false

// if interceptor.streamTarget != nil {
// interceptor.streamTarget.Sync()
// }

return string(output), err
}

Expand Down
11 changes: 11 additions & 0 deletions internal/remote/syscall_dup_linux_arm64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// +build linux,arm64

package remote

import "syscall"

// linux_arm64 doesn't have syscall.Dup2 which ginkgo uses, so
// use the nearly identical syscall.Dup3 instead
func syscallDup(oldfd int, newfd int) (err error) {
return syscall.Dup3(oldfd, newfd, 0)
}
14 changes: 14 additions & 0 deletions internal/remote/syscall_dup_plan9.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// +build plan9

package remote

import (
"syscall"
)

// Plan9 doesn't have syscall.Dup2 which ginkgo uses, so
// use the identical syscall.Dup instead
func syscallDup(oldfd int, newfd int) (err error) {
_, err := syscall.Dup(oldfd, newfd, 0)
return err
}
9 changes: 9 additions & 0 deletions internal/remote/syscall_dup_solaris.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// +build solaris

package remote

import "golang.org/x/sys/unix"

func syscallDup(oldfd int, newfd int) (err error) {
return unix.Dup2(oldfd, newfd)
}
12 changes: 12 additions & 0 deletions internal/remote/syscall_dup_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// +build !linux !arm64
// +build !windows
// +build !solaris
// +build !plan9

package remote

import "syscall"

func syscallDup(oldfd int, newfd int) (err error) {
return syscall.Dup2(oldfd, newfd)
}
22 changes: 22 additions & 0 deletions internal/remote/syscall_dup_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// +build windows

package remote

import (
"errors"

"golang.org/x/sys/windows"
)

func syscallDup(oldfd int, newfd int) (err error) {
var stdfd uint32
switch newfd {
case 1:
stdfd = windows.STD_OUTPUT_HANDLE
case 2:
stdfd = windows.STD_ERROR_HANDLE
default:
return errors.New("unrecognized newfd: %d", newfd)
}
return windows.SetStdHandle(stdfd, windows.Handle(oldfd))
}

0 comments on commit 7d237fd

Please sign in to comment.