Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove dependency on github.com/hpcloud/tail #627

Closed
wants to merge 6 commits into from
Closed
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
115 changes: 114 additions & 1 deletion internal/remote/output_interceptor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package remote

import "os"
import (
"bufio"
"errors"
"io/ioutil"
"os"
)

/*
The OutputInterceptor is used by the ForwardingReporter to
Expand All @@ -11,3 +16,111 @@ type OutputInterceptor interface {
StopInterceptingAndReturnOutput() (string, error)
StreamTo(*os.File)
}

func NewOutputInterceptor() OutputInterceptor {
return &outputInterceptor{}
}

type tailing struct {
src *os.File
dest *os.File
doneTailing chan bool
}

type outputInterceptor struct {
redirectFile *os.File
intercepting bool
tail *tailing
}

func (interceptor *outputInterceptor) StartInterceptingOutput() error {
if interceptor.intercepting {
return errors.New("Already intercepting output!")
}
interceptor.intercepting = true

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

defer func() {
if err != nil {
// in all of our scenarios, if we're exiting with an error
// the redirectFile shouldn't stay.
os.Remove(interceptor.redirectFile.Name())
}
}()
// 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
}

if interceptor.tail != nil {
interceptor.tail.src, err = os.Open(interceptor.redirectFile.Name())
if err != nil {
return err
}
scanner := bufio.NewScanner(interceptor.tail.src)
interceptor.tail.doneTailing = make(chan bool)
go func() {
for {
select {
case <-interceptor.tail.doneTailing:
// drain the scanner into the streamed-to file
for scanner.Scan() {
interceptor.tail.dest.WriteString(scanner.Text() + "\n")
}
interceptor.tail.src.Close()
return
default:
if scanner.Scan() {
interceptor.tail.dest.WriteString(scanner.Text() + "\n")
}
}
}
}()
}

return nil
}

func (interceptor *outputInterceptor) StopInterceptingAndReturnOutput() (string, error) {
if !interceptor.intercepting {
return "", errors.New("Not intercepting output!")
}

interceptor.redirectFile.Close()
output, err := ioutil.ReadFile(interceptor.redirectFile.Name())
os.Remove(interceptor.redirectFile.Name())

interceptor.intercepting = false

if interceptor.tail != nil {
// reading the redirectFile causes the io.TeeReader to write to streamTarget,
// so we just need to sync.
close(interceptor.tail.doneTailing)
er := interceptor.tail.dest.Sync()
if er != nil {
err = er
}
}

return string(output), err
}

func (interceptor *outputInterceptor) StreamTo(out *os.File) {
interceptor.tail = &tailing{
dest: out,
}
}
83 changes: 0 additions & 83 deletions internal/remote/output_interceptor_unix.go

This file was deleted.

36 changes: 0 additions & 36 deletions internal/remote/output_interceptor_win.go

This file was deleted.

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
}
1 change: 1 addition & 0 deletions internal/remote/syscall_dup_unix.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// +build !linux !arm64
// +build !windows
// +build !solaris
// +build !plan9

package remote

Expand Down
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))
}