Skip to content

Commit

Permalink
Merge 4d6a1e2 into b3671a7
Browse files Browse the repository at this point in the history
  • Loading branch information
zabawaba99 committed Jan 29, 2016
2 parents b3671a7 + 4d6a1e2 commit 96b3e70
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 21 deletions.
38 changes: 28 additions & 10 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ type Bob struct {
watchDir string

depWarning string
cmds [][]string
buildCmds [][]string
runCmds [][]string
ignoredItems []string

verbose bool
Expand All @@ -40,21 +41,32 @@ func NewBuilder(c config) (*Bob, error) {
return nil, err
}

cmds := make([][]string, len(c.Build))
for i, s := range c.Build {
cmds[i] = strings.Split(s, " ")
parseCmd := func(cmd string) []string {
c := strings.Split(cmd, " ")

// check for environment variables inside script
if strings.Contains(s, "$$") {
replaceEnv(cmds[i])
if strings.Contains(cmd, "$$") {
replaceEnv(c)
}
return c
}

buildCmds := make([][]string, len(c.Build))
for i, s := range c.Build {
buildCmds[i] = parseCmd(s)
}

runCmds := make([][]string, len(c.Run))
for i, s := range c.Run {
runCmds[i] = parseCmd(s)
}

return &Bob{
w: w,
done: make(chan struct{}),
watching: map[string]struct{}{},
cmds: cmds,
buildCmds: buildCmds,
runCmds: runCmds,
depWarning: c.DepWarnning,
ignoredItems: c.IgnoredItems,
verbose: c.Verbose,
Expand Down Expand Up @@ -153,14 +165,20 @@ func (b *Bob) execute() {
}

// setup the first command
firstCmd := b.cmds[0]
firstCmd := b.buildCmds[0]
b.curVow = vow.To(firstCmd[0], firstCmd[1:]...)

// setup the remaining commands
for i := 1; i < len(b.cmds); i++ {
cmd := b.cmds[i]
for i := 1; i < len(b.buildCmds); i++ {
cmd := b.buildCmds[i]
b.curVow = b.curVow.Then(cmd[0], cmd[1:]...)
}

// setup all parallel commands
for i := 0; i < len(b.runCmds); i++ {
cmd := b.runCmds[i]
b.curVow = b.curVow.ThenAsync(cmd[0], cmd[1:]...)
}
b.curVow.Verbose = b.verbose
go b.curVow.Exec(ansicolor.NewAnsiColorWriter(os.Stdout))

Expand Down
28 changes: 17 additions & 11 deletions builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,35 @@ package main

import (
"os"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestNewBuilder(t *testing.T) {
b, err := NewBuilder(config{})
assert.NoError(t, err)
assert.NotNil(t, b)
}

func TestNewBuilder_EnvScript(t *testing.T) {
testEnv := "foobar"
os.Setenv("TEST_ENV", testEnv)
b, err := NewBuilder(config{
Build: []string{"echo $$TEST_ENV"},
})
c := config{
Build: []string{"echo Hello World", "echo $$TEST_ENV"},
Run: []string{"echo async here"},
IgnoredItems: []string{"foo", "bar"},
Verbose: true,
}
b, err := NewBuilder(c)
assert.NoError(t, err)
assert.NotNil(t, b)

require.Len(t, b.cmds, 1)
assert.Equal(t, testEnv, b.cmds[0][1])
require.Len(t, b.buildCmds, 2)
assert.Equal(t, c.Build[0], strings.Join(b.buildCmds[0], " "))
assert.Equal(t, testEnv, b.buildCmds[1][1])

require.Len(t, b.runCmds, 1)
assert.Equal(t, c.Run[0], strings.Join(b.runCmds[0], " "))

assert.Equal(t, c.Verbose, b.verbose)
assert.Equal(t, c.IgnoredItems, b.ignoredItems)
}

func TestClose(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type config struct {
DepWarnning string
Script []string `yaml:"script"`
Build []string `yaml:"build"`
Run []string `yaml:"run"`
IgnoredItems []string `yaml:"ignore"`
Verbose bool `yaml:"verbose"`
}
Expand Down
27 changes: 27 additions & 0 deletions vow/promise.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"sync"
"sync/atomic"
"syscall"
"time"
)

var errKilled = errors.New("promise has already been killed")
Expand All @@ -23,6 +24,7 @@ var (
type promise struct {
cmdMtx sync.Mutex
cmd *exec.Cmd
async bool
killed *int32
}

Expand All @@ -33,6 +35,12 @@ func newPromise(name string, args ...string) *promise {
}
}

func newAsyncPromise(name string, args ...string) *promise {
p := newPromise(name, args...)
p.async = true
return p
}

func (p *promise) Run(w io.Writer, verbose bool) (err error) {
if p.isKilled() {
return errKilled
Expand All @@ -58,6 +66,13 @@ func (p *promise) Run(w io.Writer, verbose bool) (err error) {
}
p.cmdMtx.Unlock()

// if the process is async we don't need to do anything else
if p.async {
go p.fowardOutput(p.cmd.Process.Pid, w, &buf)
go p.cmd.Wait()
return nil
}

err = p.cmd.Wait()

status := statusPassed
Expand All @@ -72,6 +87,18 @@ func (p *promise) Run(w io.Writer, verbose bool) (err error) {
return err
}

func (p *promise) fowardOutput(pid int, w io.Writer, buf *bytes.Buffer) {
prefix := []byte(fmt.Sprintf("pid %d : ", pid))
for t := time.Tick(time.Second); !p.isKilled(); <-t {
b := buf.Next(1024)
if len(b) == 0 {
continue
}

p.writeIfAlive(w, append(prefix, b...))
}
}

func (p *promise) writeIfAlive(w io.Writer, b []byte) {
if p.isKilled() {
return
Expand Down
5 changes: 5 additions & 0 deletions vow/to.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ func (vow *Vow) Then(name string, args ...string) *Vow {
return vow
}

func (vow *Vow) ThenAsync(name string, args ...string) *Vow {
vow.cmds = append(vow.cmds, newAsyncPromise(name, args...))
return vow
}

// Stop terminates the active command and stops the execution of any future commands
func (vow *Vow) Stop() {
atomic.StoreInt32(vow.canceled, 1)
Expand Down
22 changes: 22 additions & 0 deletions vow/to_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io/ioutil"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -38,6 +39,14 @@ func TestThen(t *testing.T) {
assert.Len(t, vow.cmds, totalCmds+2)
}

func TestThenAsync(t *testing.T) {
var vow Vow
vow.ThenAsync("foo", "bar", "baz")

require.Len(t, vow.cmds, 1)
assert.True(t, vow.cmds[0].async)
}

func TestStop(t *testing.T) {
vow := To(echoScript)
for i := 0; i < 50; i++ {
Expand All @@ -61,6 +70,19 @@ func TestStop(t *testing.T) {
assert.False(t, r)
}

func TestStopAsync(t *testing.T) {
vow := To(echoScript)
vow.ThenAsync(echoScript)

require.True(t, vow.Exec(ioutil.Discard))
<-time.After(10 * time.Millisecond)

vow.Stop()
for _, cmd := range vow.cmds {
assert.True(t, cmd.cmd.ProcessState.Exited())
}
}

func TestExec(t *testing.T) {
var testBuf bytes.Buffer

Expand Down

0 comments on commit 96b3e70

Please sign in to comment.