realize/realize/tools.go

204 lines
4.9 KiB
Go

package realize
import (
"bytes"
"errors"
"io/ioutil"
"log"
"os/exec"
"path/filepath"
"strings"
)
// Tool info
type Tool struct {
Args []string `yaml:"args,omitempty" json:"args,omitempty"`
Method string `yaml:"method,omitempty" json:"method,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
Dir string `yaml:"dir,omitempty" json:"dir,omitempty"` //wdir of the command
Status bool `yaml:"status,omitempty" json:"status,omitempty"`
Output bool `yaml:"output,omitempty" json:"output,omitempty"`
dir bool
isTool bool
method []string
cmd []string
name string
parent *Project
}
// Tools go
type Tools struct {
Clean Tool `yaml:"clean,omitempty" json:"clean,omitempty"`
Vet Tool `yaml:"vet,omitempty" json:"vet,omitempty"`
Fmt Tool `yaml:"fmt,omitempty" json:"fmt,omitempty"`
Test Tool `yaml:"test,omitempty" json:"test,omitempty"`
Generate Tool `yaml:"generate,omitempty" json:"generate,omitempty"`
Install Tool `yaml:"install,omitempty" json:"install,omitempty"`
Build Tool `yaml:"build,omitempty" json:"build,omitempty"`
Run Tool `yaml:"run,omitempty" json:"run,omitempty"`
vgo bool
}
// Setup go tools
func (t *Tools) Setup() {
var gocmd string
if t.vgo {
gocmd = "vgo"
} else {
gocmd = "go"
}
// go clean
if t.Clean.Status {
t.Clean.name = "Clean"
t.Clean.isTool = true
t.Clean.cmd = replace([]string{gocmd, "clean"}, t.Clean.Method)
t.Clean.Args = split([]string{}, t.Clean.Args)
}
// go generate
if t.Generate.Status {
t.Generate.dir = true
t.Generate.isTool = true
t.Generate.name = "Generate"
t.Generate.cmd = replace([]string{gocmd, "generate"}, t.Generate.Method)
t.Generate.Args = split([]string{}, t.Generate.Args)
}
// go fmt
if t.Fmt.Status {
if len(t.Fmt.Args) == 0 {
t.Fmt.Args = []string{"-s", "-w", "-e"}
}
t.Fmt.name = "Fmt"
t.Fmt.isTool = true
t.Fmt.cmd = replace([]string{"gofmt"}, t.Fmt.Method)
t.Fmt.Args = split([]string{}, t.Fmt.Args)
}
// go vet
if t.Vet.Status {
t.Vet.dir = true
t.Vet.name = "Vet"
t.Vet.isTool = true
t.Vet.cmd = replace([]string{gocmd, "vet"}, t.Vet.Method)
t.Vet.Args = split([]string{}, t.Vet.Args)
}
// go test
if t.Test.Status {
t.Test.dir = true
t.Test.isTool = true
t.Test.name = "Test"
t.Test.cmd = replace([]string{gocmd, "test"}, t.Test.Method)
t.Test.Args = split([]string{}, t.Test.Args)
}
// go install
t.Install.name = "Install"
t.Install.cmd = replace([]string{gocmd, "install"}, t.Install.Method)
t.Install.Args = split([]string{}, t.Install.Args)
// go build
if t.Build.Status {
t.Build.name = "Build"
t.Build.cmd = replace([]string{gocmd, "build"}, t.Build.Method)
t.Build.Args = split([]string{}, t.Build.Args)
}
}
// Exec a go tool
func (t *Tool) Exec(path string, stop <-chan bool) (response Response) {
if t.dir {
if filepath.Ext(path) != "" {
path = filepath.Dir(path)
}
// check if there is at least one go file
matched := false
files, _ := ioutil.ReadDir(path)
for _, f := range files {
matched, _ = filepath.Match("*.go", f.Name())
if matched {
break
}
}
if !matched {
return
}
} else if !strings.HasSuffix(path, ".go") {
return
}
args := t.Args
if strings.HasSuffix(path, ".go") {
args = append(args, path)
path = filepath.Dir(path)
}
if s := ext(path); s == "" || s == "go" {
if t.parent.parent.Settings.Recovery.Tools {
log.Println("Tool:", t.name, path, args)
}
var out, stderr bytes.Buffer
done := make(chan error)
args = append(t.cmd, args...)
cmd := exec.Command(args[0], args[1:]...)
if t.Dir != "" {
cmd.Dir, _ = filepath.Abs(t.Dir)
} else {
cmd.Dir = path
}
cmd.Stdout = &out
cmd.Stderr = &stderr
// Start command
err := cmd.Start()
if err != nil {
response.Name = t.name
response.Err = err
return
}
go func() { done <- cmd.Wait() }()
// Wait a result
select {
case <-stop:
// Stop running command
cmd.Process.Kill()
case err := <-done:
// Command completed
response.Name = t.name
if err != nil {
response.Err = errors.New(stderr.String() + out.String() + err.Error())
} else {
if t.Output {
response.Out = out.String()
}
}
}
}
return
}
// Compile is used for build and install
func (t *Tool) Compile(path string, stop <-chan bool) (response Response) {
var out bytes.Buffer
var stderr bytes.Buffer
done := make(chan error)
args := append(t.cmd, t.Args...)
cmd := exec.Command(args[0], args[1:]...)
if t.Dir != "" {
cmd.Dir, _ = filepath.Abs(t.Dir)
} else {
cmd.Dir = path
}
cmd.Stdout = &out
cmd.Stderr = &stderr
// Start command
cmd.Start()
go func() { done <- cmd.Wait() }()
// Wait a result
response.Name = t.name
select {
case <-stop:
// Stop running command
cmd.Process.Kill()
case err := <-done:
// Command completed
if err != nil {
response.Err = errors.New(stderr.String() + err.Error())
}
}
return
}