Skip to content
Open
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
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
GO_CMD=go
GOLINT_CMD=golint
GO_TEST=$(GO_CMD) test -v ./...
GO_VET=$(GO_CMD) vet ./...
GO_LINT=$(GOLINT_CMD) .

all:
$(GO_VET)
$(GO_LINT)
$(GO_TEST)
31 changes: 0 additions & 31 deletions _examples/gocraft-web/main.go

This file was deleted.

27 changes: 0 additions & 27 deletions _examples/martini/main.go

This file was deleted.

13 changes: 0 additions & 13 deletions _examples/pilu-martini/main.go

This file was deleted.

15 changes: 0 additions & 15 deletions _examples/traffic/main.go

This file was deleted.

6 changes: 6 additions & 0 deletions _test_fixtures/Freshfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[.go, .tpl, .tmpl, .html]
test: go test
build: go build -o hello

[stylesheets: .less]
less-compiler: lessc less/application.less > css/apllication.css
91 changes: 91 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package main

import (
"fmt"
"io"
"log"
"os/exec"
"strings"
)

type command struct {
Section *section
Name string
CmdString string
Cmd *exec.Cmd
Stdout io.ReadCloser
Stderr io.ReadCloser
Logger *customLogger
}

func newCommand(section *section, cmd string) *command {
var name string
parts := strings.Split(cmd, " ")

if len(parts) > 0 {
name = parts[0]
}

loggerPrefix := fmt.Sprintf("%s - %s", section.Name, name)
c := &command{
Section: section,
Name: name,
CmdString: cmd,
Logger: newLogger(loggerPrefix),
}

return c
}

func (c *command) build() error {
options := strings.Split(c.CmdString, " ")
c.Cmd = exec.Command(options[0], options[1:]...)

var err error
c.Stdout, err = c.Cmd.StdoutPipe()
if err != nil {
return err
}

c.Stderr, err = c.Cmd.StderrPipe()
if err != nil {
return err
}

return nil
}

func (c *command) Run() error {
c.Logger.log(c.CmdString)

err := c.build()
if err != nil {
log.Fatal(err)
}

go io.Copy(c.Logger, c.Stdout)
go io.Copy(c.Logger, c.Stderr)

err = c.Cmd.Start()
if err != nil {
logger.log("Errors on `%s - %s`: %v\n", c.Section.Name, c.Name, err)
}

logger.log(fmt.Sprintf("`%s - %s` started with pid %d", c.Section.Name, c.Name, c.Cmd.Process.Pid))

err = c.Cmd.Wait()
if err != nil {
logger.log("Errors on `%s - %s`: %v\n", c.Section.Name, c.Name, err)
}

logger.log("`%s - %s` ended\n", c.Section.Name, c.Name)

return err
}

func (c *command) Stop() {
if c.Cmd != nil && c.Cmd.Process != nil {
logger.log("Killing process `%s`\n", c.Name)
c.Cmd.Process.Kill()
}
}
19 changes: 19 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

// func TestNewCommand(t *testing.T) {
// s := newSection("foo")
// c := newCommand(s, "build", "./build all -o foo")
// assert.Equal(t, "build", c.Name)
// assert.Equal(t, "./build all -o foo", c.CmdString)
// }

// func TestCommand_Build(t *testing.T) {
// s := newSection("foo")
// c := newCommand(s, "build", "./build all -o foo")
// assert.Nil(t, c.Cmd)

// c.build()
// assert.NotNil(t, c.Cmd)
// assert.Equal(t, "./build", c.Cmd.Path)
// assert.Equal(t, []string{"./build", "all", "-o", "foo"}, c.Cmd.Args)
// }
162 changes: 162 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package main

import (
"bufio"
"fmt"
"text/scanner"
)

type config struct {
sections []*section
}

type stateFunc func(*config, *section) (stateFunc, *section, error)

type configScanner struct {
s scanner.Scanner
state stateFunc
commands map[string]stateFunc
}

func newConfigScanner(r *bufio.Reader) *configScanner {
var sc scanner.Scanner
sc.Init(r)

s := &configScanner{s: sc}
s.init()

return s
}

func (s *configScanner) init() {
s.commands = map[string]stateFunc{
"RUN": s.scanCMDRun,
"WATCH": s.scanCMDWatch,
}
}

func (s *configScanner) next() rune {
r := s.s.Next()
if r != '#' {
return r
}

for r != '\n' && r != scanner.EOF {
r = s.s.Next()
}

return r
}

func (s *configScanner) scan(c *config) error {
var err error

sec := &section{Name: "MAIN"}
c.sections = append(c.sections, sec)

for s.state = s.scanLine; s.state != nil; {
s.state, sec, err = s.state(c, sec)
if err != nil {
break
}
}

return err
}

func (s *configScanner) scanLine(c *config, sec *section) (stateFunc, *section, error) {
r := s.s.Peek()
for r != scanner.EOF {
if r != ' ' && r != '\t' && r != '\n' && r != '#' {
if r == '[' {
return s.scanSection, sec, nil
}

return s.scanCMD, sec, nil
}

s.next()
r = s.s.Peek()

}

return nil, sec, nil
}

func (s *configScanner) scanSection(c *config, sec *section) (stateFunc, *section, error) {
r := s.next()
if r != '[' {
return nil, sec, s.errorExpectedRune("[")
}

sec = &section{}
c.sections = append(c.sections, sec)

return s.scanSectionName, sec, nil
}

func (s *configScanner) scanSectionName(c *config, sec *section) (stateFunc, *section, error) {
var name string
r := s.s.Peek()
for r != ']' {
if r == scanner.EOF || r == '\n' || r == '#' {
return nil, sec, s.errorExpectedRune("]")
}

r = s.s.Next()
name += string(r)
r = s.s.Peek()
}
s.next()
sec.Name = name

return s.scanLine, sec, nil
}

func (s *configScanner) scanCMD(c *config, sec *section) (stateFunc, *section, error) {
var name string
r := s.next()
for r != scanner.EOF {
if r == ' ' || r == '\t' || r == '\n' {
break
}

name += string(r)
r = s.next()
}

if cmd, ok := s.commands[name]; ok {
return cmd, sec, nil
}

return nil, sec, fmt.Errorf("Unknown command `%s`", name)
}

func (s *configScanner) scanCMDRun(c *config, sec *section) (stateFunc, *section, error) {
var cmdString string
r := s.next()
for r != scanner.EOF && r != '\n' {
cmdString = cmdString + string(r)
r = s.next()
}

sec.NewCommand(cmdString)

return s.scanLine, sec, nil
}

func (s *configScanner) scanCMDWatch(c *config, sec *section) (stateFunc, *section, error) {
var cmd string
r := s.next()
for r != scanner.EOF && r != '\n' {
cmd = cmd + string(r)
r = s.next()
}

return s.scanLine, sec, nil
}

func (s *configScanner) errorExpectedRune(c string) error {
p := s.s.Pos()
return fmt.Errorf("Expected `%s` at line %d, col %d", c, p.Line, p.Column)
}
Loading