realize/watcher/exec.go

193 lines
5.3 KiB
Go
Raw Normal View History

package watcher
2016-08-03 08:28:58 +00:00
import (
2016-08-04 19:57:19 +00:00
"bufio"
2016-08-17 23:35:37 +00:00
"bytes"
2016-12-18 23:29:50 +00:00
"fmt"
2017-06-16 09:15:56 +00:00
"github.com/tockins/realize/style"
2016-08-04 19:57:19 +00:00
"log"
2016-08-17 23:35:37 +00:00
"os"
"os/exec"
2016-08-23 00:07:07 +00:00
"path/filepath"
"regexp"
2016-09-05 15:53:37 +00:00
"strings"
2016-08-17 23:35:37 +00:00
"sync"
"time"
2016-08-03 08:28:58 +00:00
)
2016-08-18 07:29:36 +00:00
// GoRun is an implementation of the bin execution
2016-11-14 07:59:47 +00:00
func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup) error {
2016-11-01 09:56:12 +00:00
var build *exec.Cmd
var args []string
2016-12-16 22:54:07 +00:00
var path = ""
isErrorText := func(string) bool {
return false
}
errRegexp, err := regexp.Compile(p.ErrorOutputPattern)
if err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 3), ":", style.Blue.Regular(err.Error()))
out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Run"}
2017-08-28 08:49:38 +00:00
p.stamp("error", out, msg, "")
} else {
isErrorText = func(t string) bool {
return errRegexp.MatchString(t)
}
}
for _, arg := range p.Args {
arr := strings.Fields(arg)
args = append(args, arr...)
2016-12-16 22:54:07 +00:00
}
if _, err := os.Stat(filepath.Join(p.base, p.path)); err == nil {
path = filepath.Join(p.base, p.path)
}
if _, err := os.Stat(filepath.Join(p.base, p.path+".exe")); err == nil {
path = filepath.Join(p.base, p.path+".exe")
}
if path != "" {
build = exec.Command(path, args...)
2016-08-27 13:07:00 +00:00
} else {
if _, err := os.Stat(filepath.Join(getEnvPath("GOBIN"), filepath.Base(p.path))); err == nil {
2017-06-19 10:13:21 +00:00
build = exec.Command(filepath.Join(getEnvPath("GOBIN"), filepath.Base(p.path)), args...)
} else if _, err := os.Stat(filepath.Join(getEnvPath("GOBIN"), filepath.Base(p.path)) + ".exe"); err == nil {
2017-06-19 10:13:21 +00:00
build = exec.Command(filepath.Join(getEnvPath("GOBIN"), filepath.Base(p.path))+".exe", args...)
2016-12-16 22:54:07 +00:00
} else {
p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Can't run a not compiled project"})
p.Fatal(err, "Can't run a not compiled project", ":")
}
2016-08-26 12:52:27 +00:00
}
2016-08-16 10:20:55 +00:00
defer func() {
2016-08-16 16:36:54 +00:00
if err := build.Process.Kill(); err != nil {
2016-10-14 08:47:43 +00:00
p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Failed to stop: " + err.Error()})
2016-12-16 22:54:07 +00:00
p.Fatal(err, "Failed to stop", ":")
2016-08-16 16:36:54 +00:00
}
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular("Ended"))
2016-12-18 23:29:50 +00:00
out := BufferOut{Time: time.Now(), Text: "Ended", Type: "Go Run"}
2017-08-28 08:49:38 +00:00
p.stamp("log", out, msg, "")
2016-08-16 10:20:55 +00:00
wr.Done()
}()
2016-08-04 19:57:19 +00:00
stdout, err := build.StdoutPipe()
2016-08-23 12:42:01 +00:00
stderr, err := build.StderrPipe()
2016-08-04 19:57:19 +00:00
if err != nil {
log.Println(style.Red.Bold(err.Error()))
2016-08-20 10:47:32 +00:00
return err
2016-08-04 19:57:19 +00:00
}
if err := build.Start(); err != nil {
log.Println(style.Red.Bold(err.Error()))
2016-08-20 10:47:32 +00:00
return err
2016-08-04 19:57:19 +00:00
}
2016-08-17 22:24:06 +00:00
close(runner)
2016-08-04 19:57:19 +00:00
2016-09-17 19:07:22 +00:00
execOutput, execError := bufio.NewScanner(stdout), bufio.NewScanner(stderr)
stopOutput, stopError := make(chan bool, 1), make(chan bool, 1)
scanner := func(stop chan bool, output *bufio.Scanner, isError bool) {
for output.Scan() {
text := output.Text()
msg := fmt.Sprintln(p.pname(p.Name, 3), ":", style.Blue.Regular(text))
2017-08-08 21:56:19 +00:00
if isError && !isErrorText(text) {
out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"}
2017-08-28 08:49:38 +00:00
p.stamp("error", out, msg, "")
} else {
2017-08-07 23:33:31 +00:00
out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"}
2017-08-28 08:49:38 +00:00
p.stamp("out", out, msg, "")
2016-08-17 14:56:06 +00:00
}
}
2016-08-17 19:34:06 +00:00
close(stop)
}
go scanner(stopOutput, execOutput, false)
go scanner(stopError, execError, true)
2016-08-17 23:35:37 +00:00
for {
2016-08-04 19:57:19 +00:00
select {
2016-08-17 23:35:37 +00:00
case <-channel:
2016-08-17 19:34:06 +00:00
return nil
case <-stopOutput:
return nil
case <-stopError:
2016-08-04 22:59:41 +00:00
return nil
2016-08-04 19:57:19 +00:00
}
}
2016-08-03 08:28:58 +00:00
}
2016-08-21 15:12:11 +00:00
// GoBuild is an implementation of the "go build"
2016-11-14 07:59:47 +00:00
func (p *Project) goBuild() (string, error) {
2016-08-03 08:28:58 +00:00
var out bytes.Buffer
2016-08-24 14:13:14 +00:00
var stderr bytes.Buffer
args := []string{"build"}
2017-09-03 18:00:40 +00:00
args = arguments(args, p.Cmds.Build.Args)
build := exec.Command("go", args...)
2016-08-20 10:47:32 +00:00
build.Dir = p.base
2016-08-03 08:28:58 +00:00
build.Stdout = &out
2016-08-24 14:13:14 +00:00
build.Stderr = &stderr
2016-08-03 08:28:58 +00:00
if err := build.Run(); err != nil {
2016-08-27 21:57:26 +00:00
return stderr.String(), err
2016-08-03 08:28:58 +00:00
}
2016-08-27 21:57:26 +00:00
return "", nil
2016-08-03 08:28:58 +00:00
}
2016-08-21 15:12:11 +00:00
// GoInstall is an implementation of the "go install"
2016-11-14 07:59:47 +00:00
func (p *Project) goInstall() (string, error) {
2016-08-03 16:49:17 +00:00
var out bytes.Buffer
2016-08-24 14:11:13 +00:00
var stderr bytes.Buffer
err := os.Setenv("GOBIN", filepath.Join(getEnvPath("GOPATH"), "bin"))
2016-08-20 10:47:32 +00:00
if err != nil {
2016-11-11 16:22:25 +00:00
return "", err
2016-08-20 10:47:32 +00:00
}
args := []string{"install"}
for _, arg := range p.Cmds.Bin.Args {
arr := strings.Fields(arg)
args = append(args, arr...)
}
build := exec.Command("go", args...)
2016-08-23 00:07:07 +00:00
build.Dir = p.base
2016-08-03 16:49:17 +00:00
build.Stdout = &out
2016-08-24 14:11:13 +00:00
build.Stderr = &stderr
2016-08-03 16:49:17 +00:00
if err := build.Run(); err != nil {
2016-08-27 21:57:26 +00:00
return stderr.String(), err
2016-08-03 16:49:17 +00:00
}
2016-08-27 21:57:26 +00:00
return "", nil
2016-08-21 13:38:00 +00:00
}
2016-08-21 15:12:11 +00:00
2016-12-17 16:15:56 +00:00
// GoTools is used for run go methods such as fmt, test, generate...
func (p *Project) goTools(dir string, name string, cmd ...string) (string, error) {
2017-08-25 10:51:41 +00:00
if s := filepath.Ext(dir); s != "" && s != ".go" {
return "", nil
}
2016-11-15 19:44:28 +00:00
var out, stderr bytes.Buffer
2016-12-17 16:15:56 +00:00
build := exec.Command(name, cmd...)
build.Dir = dir
2016-11-11 16:22:25 +00:00
build.Stdout = &out
2016-11-15 19:44:28 +00:00
build.Stderr = &stderr
2016-11-11 16:22:25 +00:00
if err := build.Run(); err != nil {
2017-08-31 07:43:11 +00:00
return stderr.String() + out.String(), err
2016-08-27 21:57:26 +00:00
}
2016-11-15 19:44:28 +00:00
return "", nil
2016-08-27 21:57:26 +00:00
}
2016-09-05 15:53:37 +00:00
// Exec an additional command from a defined path if specified
2016-12-25 17:08:22 +00:00
func (p *Project) command(cmd Command) (errors string, logs string) {
2016-12-18 17:26:10 +00:00
var stdout bytes.Buffer
var stderr bytes.Buffer
2016-12-25 17:08:22 +00:00
command := strings.Replace(strings.Replace(cmd.Command, "'", "", -1), "\"", "", -1)
2016-12-18 17:26:10 +00:00
c := strings.Split(command, " ")
build := exec.Command(c[0], c[1:]...)
build.Dir = p.base
2016-12-25 17:08:22 +00:00
if cmd.Path != "" {
if strings.Contains(cmd.Path, p.base) {
build.Dir = cmd.Path
} else {
build.Dir = filepath.Join(p.base, cmd.Path)
}
}
2016-12-18 17:26:10 +00:00
build.Stdout = &stdout
build.Stderr = &stderr
err := build.Run()
// check if log
logs = stdout.String()
if err != nil {
errors = stderr.String()
return errors, logs
2016-09-05 15:53:37 +00:00
}
2016-12-18 17:26:10 +00:00
return "", logs
2016-11-14 07:59:47 +00:00
}