commit
7f02f5256c
28
cmd.go
28
cmd.go
|
@ -9,12 +9,9 @@ import (
|
|||
|
||||
// Tool options customizable, should be moved in Cmd
|
||||
type tool struct {
|
||||
dir bool
|
||||
status bool
|
||||
name string
|
||||
err string
|
||||
cmd []string
|
||||
options []string
|
||||
name, err, out string
|
||||
cmd, options []string
|
||||
dir, status bool
|
||||
}
|
||||
|
||||
// Cmds list of go commands
|
||||
|
@ -32,11 +29,11 @@ type Cmds struct {
|
|||
|
||||
// Cmd single command fields and options
|
||||
type Cmd struct {
|
||||
Status bool `yaml:"status,omitempty" json:"status,omitempty"`
|
||||
Method string `yaml:"method,omitempty" json:"method,omitempty"`
|
||||
Args []string `yaml:"args,omitempty" json:"args,omitempty"`
|
||||
method []string
|
||||
Status bool `yaml:"status,omitempty" json:"status,omitempty"`
|
||||
tool bool
|
||||
method []string
|
||||
name, startTxt, endTxt string
|
||||
}
|
||||
|
||||
|
@ -46,6 +43,8 @@ func (r *realize) clean() error {
|
|||
arr := r.Schema
|
||||
for key, val := range arr {
|
||||
if _, err := duplicates(val, arr[key+1:]); err != nil {
|
||||
// path validation
|
||||
|
||||
r.Schema = append(arr[:key], arr[key+1:]...)
|
||||
break
|
||||
}
|
||||
|
@ -56,14 +55,15 @@ func (r *realize) clean() error {
|
|||
}
|
||||
|
||||
// Add a new project
|
||||
func (r *realize) add(p *cli.Context) error {
|
||||
path, err := filepath.Abs(p.String("path"))
|
||||
if err != nil {
|
||||
return err
|
||||
func (r *realize) add(p *cli.Context) (err error) {
|
||||
// project init
|
||||
name := filepath.Base(p.String("path"))
|
||||
if name == "." {
|
||||
name = filepath.Base(wdir())
|
||||
}
|
||||
project := Project{
|
||||
Name: filepath.Base(filepath.Clean(p.String("path"))),
|
||||
Path: path,
|
||||
Name: name,
|
||||
Path: p.String("path"),
|
||||
Cmds: Cmds{
|
||||
Vet: Cmd{
|
||||
Status: p.Bool("vet"),
|
||||
|
|
33
exec.go
33
exec.go
|
@ -39,6 +39,7 @@ func (p *Project) goCompile(stop <-chan bool, method []string, args []string) (s
|
|||
if err != nil {
|
||||
return stderr.String(), err
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
@ -47,7 +48,6 @@ func (p *Project) goCompile(stop <-chan bool, method []string, args []string) (s
|
|||
func (p *Project) goRun(stop <-chan bool, runner chan bool) {
|
||||
var build *exec.Cmd
|
||||
var args []string
|
||||
|
||||
// custom error pattern
|
||||
isErrorText := func(string) bool {
|
||||
return false
|
||||
|
@ -72,13 +72,16 @@ func (p *Project) goRun(stop <-chan bool, runner chan bool) {
|
|||
}
|
||||
|
||||
gobin := os.Getenv("GOBIN")
|
||||
path := filepath.Join(gobin, p.name)
|
||||
dirPath := filepath.Base(p.Path)
|
||||
if p.Path == "." {
|
||||
dirPath = filepath.Base(wdir())
|
||||
}
|
||||
path := filepath.Join(gobin, dirPath)
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
build = exec.Command(path, args...)
|
||||
} else if _, err := os.Stat(path + extWindows); err == nil {
|
||||
build = exec.Command(path+extWindows, args...)
|
||||
} else {
|
||||
path := filepath.Join(p.Path, p.name)
|
||||
if _, err = os.Stat(path); err == nil {
|
||||
build = exec.Command(path, args...)
|
||||
} else if _, err = os.Stat(path + extWindows); err == nil {
|
||||
|
@ -148,26 +151,26 @@ func (p *Project) command(stop <-chan bool, cmd Command) (string, string) {
|
|||
var stderr bytes.Buffer
|
||||
done := make(chan error)
|
||||
args := strings.Split(strings.Replace(strings.Replace(cmd.Command, "'", "", -1), "\"", "", -1), " ")
|
||||
exec := exec.Command(args[0], args[1:]...)
|
||||
exec.Dir = p.Path
|
||||
ex := exec.Command(args[0], args[1:]...)
|
||||
ex.Dir = p.Path
|
||||
// make cmd path
|
||||
if cmd.Path != "" {
|
||||
if strings.Contains(cmd.Path, p.Path) {
|
||||
exec.Dir = cmd.Path
|
||||
ex.Dir = cmd.Path
|
||||
} else {
|
||||
exec.Dir = filepath.Join(p.Path, cmd.Path)
|
||||
ex.Dir = filepath.Join(p.Path, cmd.Path)
|
||||
}
|
||||
}
|
||||
exec.Stdout = &stdout
|
||||
exec.Stderr = &stderr
|
||||
ex.Stdout = &stdout
|
||||
ex.Stderr = &stderr
|
||||
// Start command
|
||||
exec.Start()
|
||||
go func() { done <- exec.Wait() }()
|
||||
ex.Start()
|
||||
go func() { done <- ex.Wait() }()
|
||||
// Wait a result
|
||||
select {
|
||||
case <-stop:
|
||||
// Stop running command
|
||||
exec.Process.Kill()
|
||||
ex.Process.Kill()
|
||||
return "", ""
|
||||
case err := <-done:
|
||||
// Command completed
|
||||
|
@ -206,15 +209,17 @@ func (p *Project) goTool(wg *sync.WaitGroup, stop <-chan bool, result chan<- too
|
|||
case <-stop:
|
||||
// Stop running command
|
||||
cmd.Process.Kill()
|
||||
break
|
||||
return
|
||||
case err := <-done:
|
||||
// Command completed
|
||||
if err != nil {
|
||||
tool.err = stderr.String() + out.String()
|
||||
// send command result
|
||||
result <- tool
|
||||
} else {
|
||||
tool.out = out.String()
|
||||
}
|
||||
break
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
|
37
notify.go
37
notify.go
|
@ -95,6 +95,7 @@ func (w *fsNotifyWatcher) Events() <-chan fsnotify.Event {
|
|||
return w.Watcher.Events
|
||||
}
|
||||
|
||||
// Walk fsnotify
|
||||
func (w *fsNotifyWatcher) Walk(path string, init bool) string {
|
||||
if err := w.Add(path); err != nil {
|
||||
return ""
|
||||
|
@ -106,9 +107,8 @@ func (w *fsNotifyWatcher) Walk(path string, init bool) string {
|
|||
// All watches are stopped, removed, and the poller cannot be added to
|
||||
func (w *filePoller) Close() error {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if w.closed {
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,7 @@ func (w *filePoller) Close() error {
|
|||
w.remove(name)
|
||||
delete(w.watches, name)
|
||||
}
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -157,6 +158,7 @@ func (w *filePoller) Add(name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Remove poller
|
||||
func (w *filePoller) remove(name string) error {
|
||||
if w.closed {
|
||||
return errPollerClosed
|
||||
|
@ -184,6 +186,7 @@ func (w *filePoller) Events() <-chan fsnotify.Event {
|
|||
return w.events
|
||||
}
|
||||
|
||||
// Walk poller
|
||||
func (w *filePoller) Walk(path string, init bool) string {
|
||||
check := w.watches[path]
|
||||
if err := w.Add(path); err != nil {
|
||||
|
@ -232,12 +235,8 @@ func (w *filePoller) watch(f *os.File, lastFi os.FileInfo, chClose chan struct{}
|
|||
}
|
||||
|
||||
fi, err := os.Stat(f.Name())
|
||||
if err != nil {
|
||||
// if we got an error here and lastFi is not set, we can presume that nothing has changed
|
||||
// This should be safe since before `watch()` is called, a stat is performed, there is any error `watch` is not called
|
||||
if lastFi == nil {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case err != nil && lastFi != nil:
|
||||
// If it doesn't exist at this point, it must have been removed
|
||||
// no need to send the error here since this is a valid operation
|
||||
if os.IsNotExist(err) {
|
||||
|
@ -245,37 +244,25 @@ func (w *filePoller) watch(f *os.File, lastFi os.FileInfo, chClose chan struct{}
|
|||
return
|
||||
}
|
||||
lastFi = nil
|
||||
continue
|
||||
}
|
||||
// at this point, send the error
|
||||
if err := w.sendErr(err, chClose); err != nil {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if lastFi == nil {
|
||||
w.sendErr(err, chClose)
|
||||
return
|
||||
case lastFi == nil:
|
||||
if err := w.sendEvent(fsnotify.Event{Op: fsnotify.Create, Name: f.Name()}, chClose); err != nil {
|
||||
return
|
||||
}
|
||||
lastFi = fi
|
||||
continue
|
||||
}
|
||||
|
||||
if fi.Mode() != lastFi.Mode() {
|
||||
case fi.Mode() != lastFi.Mode():
|
||||
if err := w.sendEvent(fsnotify.Event{Op: fsnotify.Chmod, Name: f.Name()}, chClose); err != nil {
|
||||
return
|
||||
}
|
||||
lastFi = fi
|
||||
continue
|
||||
}
|
||||
|
||||
if fi.ModTime() != lastFi.ModTime() || fi.Size() != lastFi.Size() {
|
||||
case fi.ModTime() != lastFi.ModTime() || fi.Size() != lastFi.Size():
|
||||
if err := w.sendEvent(fsnotify.Event{Op: fsnotify.Write, Name: f.Name()}, chClose); err != nil {
|
||||
return
|
||||
}
|
||||
lastFi = fi
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
32
realize.go
32
realize.go
|
@ -15,7 +15,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
version = "1.5.1r2"
|
||||
version = "1.5.2"
|
||||
)
|
||||
|
||||
// New realize instance
|
||||
|
@ -35,26 +35,16 @@ type realize struct {
|
|||
// Cli commands
|
||||
func main() {
|
||||
app := &cli.App{
|
||||
Name: "Realize",
|
||||
Version: version,
|
||||
Authors: []*cli.Author{
|
||||
{
|
||||
Name: "Alessio Pracchia",
|
||||
Email: "pracchia@hastega.it",
|
||||
},
|
||||
{
|
||||
Name: "Daniele Conventi",
|
||||
Email: "conventi@hastega.it",
|
||||
},
|
||||
},
|
||||
Name: "Realize",
|
||||
Version: version,
|
||||
Description: "Go build system with file watchers, output streams and live reload. Run, build and watch file changes with custom paths",
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "start",
|
||||
Aliases: []string{"r"},
|
||||
Aliases: []string{"s"},
|
||||
Description: "Start a toolchain on a project or a list of projects. If not exist a config file it creates a new one",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "path", Aliases: []string{"p"}, Value: wdir(), Usage: "Project base path"},
|
||||
&cli.StringFlag{Name: "path", Aliases: []string{"p"}, Value: ".", Usage: "Project base path"},
|
||||
&cli.StringFlag{Name: "name", Aliases: []string{"n"}, Value: "", Usage: "Run a project by its name"},
|
||||
&cli.BoolFlag{Name: "fmt", Aliases: []string{"f"}, Value: false, Usage: "Enable go fmt"},
|
||||
&cli.BoolFlag{Name: "vet", Aliases: []string{"v"}, Value: false, Usage: "Enable go vet"},
|
||||
|
@ -172,7 +162,7 @@ func main() {
|
|||
if err != nil {
|
||||
return d.Err()
|
||||
}
|
||||
r.Settings.FileLimit = val
|
||||
r.Settings.FileLimit = int32(val)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@ -1217,11 +1207,11 @@ func prefix(s string) string {
|
|||
if s != "" {
|
||||
return fmt.Sprint(yellow.bold("["), "REALIZE", yellow.bold("]"), " : ", s)
|
||||
}
|
||||
return ""
|
||||
return s
|
||||
}
|
||||
|
||||
// Before is launched before each command
|
||||
func before(*cli.Context) error {
|
||||
func before(*cli.Context) (err error) {
|
||||
// custom log
|
||||
log.SetFlags(0)
|
||||
log.SetOutput(logWriter{})
|
||||
|
@ -1230,7 +1220,7 @@ func before(*cli.Context) error {
|
|||
if gopath == "" {
|
||||
return errors.New("$GOPATH isn't set properly")
|
||||
}
|
||||
if err := os.Setenv("GOPATH", gopath); err != nil {
|
||||
if err = os.Setenv("GOPATH", gopath); err != nil {
|
||||
return err
|
||||
}
|
||||
// new realize instance
|
||||
|
@ -1239,11 +1229,11 @@ func before(*cli.Context) error {
|
|||
r.Settings.read(&r)
|
||||
// increase the file limit
|
||||
if r.Settings.FileLimit != 0 {
|
||||
if err := r.Settings.flimit(); err != nil {
|
||||
if err = r.Settings.flimit(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
// Rewrite the layout of the log timestamp
|
||||
|
|
14
server.go
14
server.go
|
@ -26,16 +26,15 @@ type Server struct {
|
|||
parent *realize
|
||||
Status bool `yaml:"status" json:"status"`
|
||||
Open bool `yaml:"open" json:"open"`
|
||||
Host string `yaml:"host" json:"host"`
|
||||
Port int `yaml:"port" json:"port"`
|
||||
Host string `yaml:"host" json:"host"`
|
||||
}
|
||||
|
||||
// Websocket projects
|
||||
func (s *Server) projects(c echo.Context) error {
|
||||
func (s *Server) projects(c echo.Context) (err error) {
|
||||
websocket.Handler(func(ws *websocket.Conn) {
|
||||
defer ws.Close()
|
||||
msg, _ := json.Marshal(s.parent)
|
||||
err := websocket.Message.Send(ws, string(msg))
|
||||
err = websocket.Message.Send(ws, string(msg))
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
|
@ -51,7 +50,7 @@ func (s *Server) projects(c echo.Context) error {
|
|||
for {
|
||||
// Read
|
||||
text := ""
|
||||
err := websocket.Message.Receive(ws, &text)
|
||||
err = websocket.Message.Receive(ws, &text)
|
||||
if err != nil {
|
||||
break
|
||||
} else {
|
||||
|
@ -62,6 +61,7 @@ func (s *Server) projects(c echo.Context) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
ws.Close()
|
||||
}).ServeHTTP(c.Response(), c.Request())
|
||||
return nil
|
||||
}
|
||||
|
@ -69,7 +69,9 @@ func (s *Server) projects(c echo.Context) error {
|
|||
// Start the web server
|
||||
func (s *Server) start(p *cli.Context) (err error) {
|
||||
if p.Bool("server") {
|
||||
s.parent.Server.Status = p.Bool("server")
|
||||
s.parent.Server.Status = true
|
||||
}
|
||||
if p.Bool("open") {
|
||||
s.parent.Server.Open = true
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ const (
|
|||
type Settings struct {
|
||||
file string
|
||||
Files `yaml:"files,omitempty" json:"files,omitempty"`
|
||||
FileLimit int64 `yaml:"flimit,omitempty" json:"flimit,omitempty"`
|
||||
Legacy Legacy `yaml:"legacy" json:"legacy"`
|
||||
FileLimit int32 `yaml:"flimit,omitempty" json:"flimit,omitempty"`
|
||||
Recovery bool `yaml:"recovery,omitempty" json:"recovery,omitempty"`
|
||||
}
|
||||
|
||||
|
|
177
watcher.go
177
watcher.go
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
|
@ -12,8 +13,6 @@ import (
|
|||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -54,12 +53,12 @@ type Project struct {
|
|||
parent *realize
|
||||
watcher FileWatcher
|
||||
init bool
|
||||
Settings `yaml:"-" json:"-"`
|
||||
files, folders int64
|
||||
name, lastFile string
|
||||
tools []tool
|
||||
paths []string
|
||||
lastTime time.Time
|
||||
Settings `yaml:"-" json:"-"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Path string `yaml:"path" json:"path"`
|
||||
Environment map[string]string `yaml:"environment,omitempty" json:"environment,omitempty"`
|
||||
|
@ -119,16 +118,27 @@ L:
|
|||
select {
|
||||
case event := <-p.watcher.Events():
|
||||
if time.Now().Truncate(time.Second).After(p.lastTime) || event.Name != p.lastFile {
|
||||
// event time
|
||||
eventTime := time.Now()
|
||||
// file extension
|
||||
ext := ext(event.Name)
|
||||
if ext == "" {
|
||||
ext = "DIR"
|
||||
}
|
||||
// change message
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 4), ":", magenta.bold(strings.ToUpper(ext)), "changed", magenta.bold(event.Name))
|
||||
out = BufferOut{Time: time.Now(), Text: ext + " changed " + event.Name}
|
||||
// switch event type
|
||||
switch event.Op {
|
||||
case fsnotify.Chmod:
|
||||
case fsnotify.Remove:
|
||||
ext := ext(event.Name)
|
||||
p.watcher.Remove(event.Name)
|
||||
if !strings.Contains(ext, "_") && !strings.Contains(ext, ".") && array(ext, p.Watcher.Exts) {
|
||||
close(stop)
|
||||
stop = make(chan bool)
|
||||
p.changed(event, stop) // stop
|
||||
p.stamp("log", out, msg, "")
|
||||
go p.routines(stop, p.watcher, "")
|
||||
}
|
||||
p.watcher.Remove(event.Name)
|
||||
default:
|
||||
file, err := os.Stat(event.Name)
|
||||
if err != nil {
|
||||
|
@ -137,15 +147,20 @@ L:
|
|||
if file.IsDir() {
|
||||
filepath.Walk(event.Name, p.walk)
|
||||
} else if file.Size() > 0 {
|
||||
// used only for test and debug
|
||||
if p.parent.Settings.Recovery {
|
||||
log.Println(event)
|
||||
}
|
||||
ext := ext(event.Name)
|
||||
if !strings.Contains(ext, "_") && !strings.Contains(ext, ".") && array(ext, p.Watcher.Exts) {
|
||||
// change watched
|
||||
close(stop)
|
||||
stop = make(chan bool)
|
||||
p.changed(event, stop)
|
||||
// check if a file is still writing #119
|
||||
if event.Op != fsnotify.Write || eventTime.Truncate(time.Millisecond).After(file.ModTime().Truncate(time.Millisecond)) {
|
||||
close(stop)
|
||||
stop = make(chan bool)
|
||||
// stop and start again
|
||||
p.stamp("log", out, msg, "")
|
||||
go p.routines(stop, p.watcher, event.Name)
|
||||
}
|
||||
}
|
||||
p.lastTime = time.Now().Truncate(time.Second)
|
||||
p.lastFile = event.Name
|
||||
|
@ -172,12 +187,6 @@ func (p *Project) err(err error) {
|
|||
|
||||
// Config project init
|
||||
func (p *Project) config(r *realize) {
|
||||
// validate project path, if invalid get wdir or clean current
|
||||
if !filepath.IsAbs(p.Path) {
|
||||
p.Path = wdir()
|
||||
} else {
|
||||
p.Path = filepath.Clean(p.Path)
|
||||
}
|
||||
// get basepath name
|
||||
p.name = filepath.Base(p.Path)
|
||||
// env variables
|
||||
|
@ -190,24 +199,12 @@ func (p *Project) config(r *realize) {
|
|||
if len(p.Cmds.Fmt.Args) == 0 {
|
||||
p.Cmds.Fmt.Args = []string{"-s", "-w", "-e", "./"}
|
||||
}
|
||||
p.tools = append(p.tools, tool{
|
||||
status: p.Cmds.Fix.Status,
|
||||
cmd: replace([]string{"go fix"}, p.Cmds.Fix.Method),
|
||||
options: split([]string{}, p.Cmds.Fix.Args),
|
||||
name: "Fix",
|
||||
})
|
||||
p.tools = append(p.tools, tool{
|
||||
status: p.Cmds.Clean.Status,
|
||||
cmd: replace([]string{"go clean"}, p.Cmds.Clean.Method),
|
||||
options: split([]string{}, p.Cmds.Clean.Args),
|
||||
name: "Clean",
|
||||
})
|
||||
p.tools = append(p.tools, tool{
|
||||
status: p.Cmds.Fmt.Status,
|
||||
cmd: replace([]string{"gofmt"}, p.Cmds.Fmt.Method),
|
||||
options: split([]string{}, p.Cmds.Fmt.Args),
|
||||
name: "Fmt",
|
||||
})
|
||||
p.tools = append(p.tools, tool{
|
||||
status: p.Cmds.Generate.Status,
|
||||
cmd: replace([]string{"go", "generate"}, p.Cmds.Generate.Method),
|
||||
|
@ -216,11 +213,16 @@ func (p *Project) config(r *realize) {
|
|||
dir: true,
|
||||
})
|
||||
p.tools = append(p.tools, tool{
|
||||
status: p.Cmds.Test.Status,
|
||||
cmd: replace([]string{"go", "test"}, p.Cmds.Test.Method),
|
||||
options: split([]string{}, p.Cmds.Test.Args),
|
||||
name: "Test",
|
||||
dir: true,
|
||||
status: p.Cmds.Fix.Status,
|
||||
cmd: replace([]string{"go fix"}, p.Cmds.Fix.Method),
|
||||
options: split([]string{}, p.Cmds.Fix.Args),
|
||||
name: "Fix",
|
||||
})
|
||||
p.tools = append(p.tools, tool{
|
||||
status: p.Cmds.Fmt.Status,
|
||||
cmd: replace([]string{"gofmt"}, p.Cmds.Fmt.Method),
|
||||
options: split([]string{}, p.Cmds.Fmt.Args),
|
||||
name: "Fmt",
|
||||
})
|
||||
p.tools = append(p.tools, tool{
|
||||
status: p.Cmds.Vet.Status,
|
||||
|
@ -229,6 +231,13 @@ func (p *Project) config(r *realize) {
|
|||
name: "Vet",
|
||||
dir: true,
|
||||
})
|
||||
p.tools = append(p.tools, tool{
|
||||
status: p.Cmds.Test.Status,
|
||||
cmd: replace([]string{"go", "test"}, p.Cmds.Test.Method),
|
||||
options: split([]string{}, p.Cmds.Test.Args),
|
||||
name: "Test",
|
||||
dir: true,
|
||||
})
|
||||
p.Cmds.Install = Cmd{
|
||||
Status: p.Cmds.Install.Status,
|
||||
Args: append([]string{}, p.Cmds.Install.Args...),
|
||||
|
@ -292,10 +301,11 @@ func (p *Project) cmd(stop <-chan bool, flag string, global bool) {
|
|||
// Compile is used for run and display the result of a compiling
|
||||
func (p *Project) compile(stop <-chan bool, cmd Cmd) error {
|
||||
if cmd.Status {
|
||||
start := time.Now()
|
||||
var start time.Time
|
||||
channel := make(chan Result)
|
||||
go func() {
|
||||
log.Println(p.pname(p.Name, 1), ":", cmd.startTxt)
|
||||
start = time.Now()
|
||||
stream, err := p.goCompile(stop, cmd.method, cmd.Args)
|
||||
if stream != msgStop {
|
||||
channel <- Result{stream, err}
|
||||
|
@ -349,10 +359,12 @@ func (p *Project) tool(stop <-chan bool, path string) error {
|
|||
result := make(chan tool)
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(p.tools))
|
||||
for _, element := range p.tools {
|
||||
// no need a sequence, these commands can be asynchronous
|
||||
go p.goTool(&wg, stop, result, path, element)
|
||||
if element.status {
|
||||
wg.Add(1)
|
||||
p.goTool(&wg, stop, result, path, element)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
close(done)
|
||||
|
@ -361,9 +373,15 @@ func (p *Project) tool(stop <-chan bool, path string) error {
|
|||
for {
|
||||
select {
|
||||
case tool := <-result:
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 2), ":", red.bold(tool.name), red.regular("there are some errors in"), ":", magenta.bold(path))
|
||||
buff := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: tool.name, Stream: tool.err}
|
||||
p.stamp("error", buff, msg, tool.err)
|
||||
if tool.err != "" {
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 2), ":", red.bold(tool.name), red.regular("there are some errors in"), ":", magenta.bold(path))
|
||||
buff := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: tool.name, Stream: tool.err}
|
||||
p.stamp("error", buff, msg, tool.err)
|
||||
} else if tool.out != "" {
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 3), ":", red.bold(tool.name), red.regular("outputs"), ":", blue.bold(path))
|
||||
buff := BufferOut{Time: time.Now(), Text: "outputs", Path: path, Type: tool.name, Stream: tool.out}
|
||||
p.stamp("out", buff, msg, tool.out)
|
||||
}
|
||||
case <-done:
|
||||
break loop
|
||||
case <-stop:
|
||||
|
@ -374,19 +392,6 @@ func (p *Project) tool(stop <-chan bool, path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Changed detect a file/directory change
|
||||
func (p *Project) changed(event fsnotify.Event, stop chan bool) {
|
||||
e := ext(event.Name)
|
||||
if e == "" {
|
||||
e = "DIR"
|
||||
}
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 4), ":", magenta.bold(strings.ToUpper(e)), "changed", magenta.bold(event.Name))
|
||||
out = BufferOut{Time: time.Now(), Text: ext(event.Name) + " changed " + event.Name}
|
||||
p.stamp("log", out, msg, "")
|
||||
//stop running process
|
||||
go p.routines(stop, p.watcher, event.Name)
|
||||
}
|
||||
|
||||
// Watch the files tree of a project
|
||||
func (p *Project) walk(path string, info os.FileInfo, err error) error {
|
||||
for _, v := range p.Watcher.Ignore {
|
||||
|
@ -475,45 +480,53 @@ func (p *Project) routines(stop <-chan bool, watcher FileWatcher, path string) {
|
|||
}
|
||||
}
|
||||
}()
|
||||
if !done {
|
||||
// before command
|
||||
p.cmd(stop, "before", false)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
if !done {
|
||||
// Go supported tools
|
||||
p.tool(stop, path)
|
||||
// Prevent fake events on polling startup
|
||||
p.init = true
|
||||
// before command
|
||||
p.cmd(stop, "before", false)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
// Go supported tools
|
||||
p.tool(stop, path)
|
||||
// Prevent fake events on polling startup
|
||||
p.init = true
|
||||
// prevent errors using realize without config with only run flag
|
||||
if p.Cmds.Run && !p.Cmds.Install.Status && !p.Cmds.Build.Status {
|
||||
p.Cmds.Install.Status = true
|
||||
}
|
||||
if !done {
|
||||
install = p.compile(stop, p.Cmds.Install)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
if !done {
|
||||
build = p.compile(stop, p.Cmds.Build)
|
||||
install = p.compile(stop, p.Cmds.Install)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
if !done && (install == nil && build == nil) {
|
||||
if p.Cmds.Run {
|
||||
start := time.Now()
|
||||
runner := make(chan bool, 1)
|
||||
go func() {
|
||||
log.Println(p.pname(p.Name, 1), ":", "Running..")
|
||||
p.goRun(stop, runner)
|
||||
}()
|
||||
select {
|
||||
case <-runner:
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 5), ":", green.regular("Started"), "in", magenta.regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
|
||||
out = BufferOut{Time: time.Now(), Text: "Started in " + big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3) + " s"}
|
||||
p.stamp("log", out, msg, "")
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
build = p.compile(stop, p.Cmds.Build)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
if install == nil && build == nil && p.Cmds.Run {
|
||||
var start time.Time
|
||||
runner := make(chan bool, 1)
|
||||
go func() {
|
||||
log.Println(p.pname(p.Name, 1), ":", "Running..")
|
||||
start = time.Now()
|
||||
p.goRun(stop, runner)
|
||||
}()
|
||||
select {
|
||||
case <-runner:
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 5), ":", green.regular("Started"), "in", magenta.regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
|
||||
out = BufferOut{Time: time.Now(), Text: "Started in " + big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3) + " s"}
|
||||
p.stamp("log", out, msg, "")
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
if !done {
|
||||
p.cmd(stop, "after", false)
|
||||
if done {
|
||||
return
|
||||
}
|
||||
p.cmd(stop, "after", false)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue