Merge pull request #35 from tockins/dev

1.2.2
This commit is contained in:
Alessio Pracchia 2016-12-19 00:38:54 +01:00 committed by GitHub
commit e18815df46
13 changed files with 212 additions and 197 deletions

View File

@ -38,11 +38,11 @@ A Go build system with file watchers, output streams and live reload. Run, build
$ realize add $ realize add
``` ```
It will create a realize.yaml file if it doesn't exist already and adds the working directory as the project. It will create a realize.yaml file if it doesn't exist already and adds the working directory as project.
Otherwise if a config file already exists it adds the working project to the existing config file. Otherwise if a config file already exists it adds the working project to the existing config file.
The add command supports the following custom parameters: The Add command supports the following custom parameters:
``` ```
--name="Project Name" -> Name, if not specified takes the working directory name --name="Project Name" -> Name, if not specified takes the working directory name

View File

@ -15,10 +15,11 @@ const (
version = "1.2.1" version = "1.2.1"
description = "A Go build system with file watchers, output streams and live reload. Run, build and watch file changes with custom paths" description = "A Go build system with file watchers, output streams and live reload. Run, build and watch file changes with custom paths"
config = "realize.yaml" config = "realize.yaml"
output = "outputs.log" streams = "streams.log"
log = "logs.log" errs = "errors.log"
logs = "logs.log"
host = "localhost" host = "localhost"
port = 5000 port = 5001
server = true server = true
open = false open = false
) )
@ -48,8 +49,9 @@ func init() {
}, },
Resources: c.Resources{ Resources: c.Resources{
Config: config, Config: config,
Output: output, Streams: streams,
Log: log, Logs: logs,
Errors: errs,
}, },
Server: c.Server{ Server: c.Server{
Enabled: server, Enabled: server,
@ -138,8 +140,9 @@ func main() {
}, },
Resources: c.Resources{ Resources: c.Resources{
Config: config, Config: config,
Output: output, Streams: streams,
Log: log, Logs: logs,
Errors: errs,
}, },
Server: c.Server{ Server: c.Server{
Enabled: server, Enabled: server,

File diff suppressed because one or more lines are too long

View File

@ -12,13 +12,14 @@ import (
"strconv" "strconv"
) )
// Server struct contains server informations // Server settings
type Server struct { type Server struct {
*c.Settings `yaml:"-"` *c.Settings `yaml:"-"`
*w.Blueprint `yaml:"-"` *w.Blueprint `yaml:"-"`
Sync chan string `yaml:"-"` Sync chan string `yaml:"-"`
} }
// Render return a web pages defined in bindata
func render(c echo.Context, path string, mime int) error { func render(c echo.Context, path string, mime int) error {
data, err := Asset(path) data, err := Asset(path)
if err != nil { if err != nil {
@ -45,7 +46,7 @@ func render(c echo.Context, path string, mime int) error {
return nil return nil
} }
// Server starting // Start the web server
func (s *Server) Start(p *cli.Context) (err error) { func (s *Server) Start(p *cli.Context) (err error) {
if !p.Bool("no-server") && s.Enabled { if !p.Bool("no-server") && s.Enabled {
e := echo.New() e := echo.New()
@ -82,8 +83,7 @@ func (s *Server) Start(p *cli.Context) (err error) {
}) })
//websocket //websocket
//e.GET("/ws", echo.WrapHandler(s.projects())) e.GET("/ws", s.projects)
e.GET("/ws", s.hello)
go e.Start(string(s.Settings.Server.Host) + ":" + strconv.Itoa(s.Settings.Server.Port)) go e.Start(string(s.Settings.Server.Host) + ":" + strconv.Itoa(s.Settings.Server.Port))
if s.Open || p.Bool("open") { if s.Open || p.Bool("open") {
@ -98,22 +98,24 @@ func (s *Server) Start(p *cli.Context) (err error) {
return nil return nil
} }
func (s *Server) hello(c echo.Context) error { func (s *Server) projects(c echo.Context) error {
websocket.Handler(func(ws *websocket.Conn) { websocket.Handler(func(ws *websocket.Conn) {
defer ws.Close() defer ws.Close()
msg, _ := json.Marshal(s.Blueprint.Projects) msg, _ := json.Marshal(s.Blueprint.Projects)
err := websocket.Message.Send(ws, string(msg)) err := websocket.Message.Send(ws, string(msg))
go func() {
for { for {
select { select {
case <-s.Sync: case <-s.Sync:
msg, _ := json.Marshal(s.Blueprint.Projects) msg, _ := json.Marshal(s.Blueprint.Projects)
err = websocket.Message.Send(ws, string(msg)) err = websocket.Message.Send(ws, string(msg))
if err != nil { if err != nil {
//log.Println(err)
break break
} }
} }
}
}()
for {
// Read // Read
text := "" text := ""
err := websocket.Message.Receive(ws, &text) err := websocket.Message.Receive(ws, &text)
@ -123,7 +125,6 @@ func (s *Server) hello(c echo.Context) error {
} else { } else {
err := json.Unmarshal([]byte(text), &s.Blueprint.Projects) err := json.Unmarshal([]byte(text), &s.Blueprint.Projects)
if err != nil { if err != nil {
//log.Println(err)
break break
} }
} }

View File

@ -11,6 +11,7 @@ import (
var cmd map[string]string var cmd map[string]string
var stderr bytes.Buffer var stderr bytes.Buffer
// Init an associative array with the os supported
func init() { func init() {
cmd = map[string]string{ cmd = map[string]string{
"windows": "start", "windows": "start",
@ -19,15 +20,17 @@ func init() {
} }
} }
// Open a url in the default browser
func Open(url string) (io.Writer, error) { func Open(url string) (io.Writer, error) {
if open, err := cmd[runtime.GOOS]; !err { open, err := cmd[runtime.GOOS]
if !err {
return nil, errors.New("This operating system is not supported.") return nil, errors.New("This operating system is not supported.")
} else { }
cmd := exec.Command(open, url) cmd := exec.Command(open, url)
cmd.Stderr = &stderr cmd.Stderr = &stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return cmd.Stderr, err return cmd.Stderr, err
} }
}
return nil, nil return nil, nil
} }

View File

@ -4,6 +4,7 @@ import (
"github.com/fatih/color" "github.com/fatih/color"
) )
// Colors allowed
type Colors struct { type Colors struct {
Red Red
Blue Blue
@ -11,57 +12,77 @@ type Colors struct {
Magenta Magenta
Green Green
} }
// Red color
type Red struct{} type Red struct{}
// Blue color
type Blue struct{} type Blue struct{}
// Yellow color
type Yellow struct{} type Yellow struct{}
// Magenta color
type Magenta struct{} type Magenta struct{}
// Green color
type Green struct{} type Green struct{}
// Regular font in red
func (c Red) Regular(t ...interface{}) string { func (c Red) Regular(t ...interface{}) string {
r := color.New(color.FgRed).SprintFunc() r := color.New(color.FgRed).SprintFunc()
return r(t...) return r(t...)
} }
// Bold font in red
func (c Red) Bold(t ...interface{}) string { func (c Red) Bold(t ...interface{}) string {
r := color.New(color.FgRed, color.Bold).SprintFunc() r := color.New(color.FgRed, color.Bold).SprintFunc()
return r(t...) return r(t...)
} }
// Regular font in blue
func (c Blue) Regular(t ...interface{}) string { func (c Blue) Regular(t ...interface{}) string {
r := color.New(color.FgBlue).SprintFunc() r := color.New(color.FgBlue).SprintFunc()
return r(t...) return r(t...)
} }
// Bold font in blue
func (c Blue) Bold(t ...interface{}) string { func (c Blue) Bold(t ...interface{}) string {
r := color.New(color.FgBlue, color.Bold).SprintFunc() r := color.New(color.FgBlue, color.Bold).SprintFunc()
return r(t...) return r(t...)
} }
// Regular font in yellow
func (c Yellow) Regular(t ...interface{}) string { func (c Yellow) Regular(t ...interface{}) string {
r := color.New(color.FgYellow).SprintFunc() r := color.New(color.FgYellow).SprintFunc()
return r(t...) return r(t...)
} }
// Bold font in red
func (c Yellow) Bold(t ...interface{}) string { func (c Yellow) Bold(t ...interface{}) string {
r := color.New(color.FgYellow, color.Bold).SprintFunc() r := color.New(color.FgYellow, color.Bold).SprintFunc()
return r(t...) return r(t...)
} }
// Regular font in magenta
func (c Magenta) Regular(t ...interface{}) string { func (c Magenta) Regular(t ...interface{}) string {
r := color.New(color.FgMagenta).SprintFunc() r := color.New(color.FgMagenta).SprintFunc()
return r(t...) return r(t...)
} }
// Bold font in magenta
func (c Magenta) Bold(t ...interface{}) string { func (c Magenta) Bold(t ...interface{}) string {
r := color.New(color.FgMagenta, color.Bold).SprintFunc() r := color.New(color.FgMagenta, color.Bold).SprintFunc()
return r(t...) return r(t...)
} }
// Regular font in green
func (c Green) Regular(t ...interface{}) string { func (c Green) Regular(t ...interface{}) string {
r := color.New(color.FgGreen).SprintFunc() r := color.New(color.FgGreen).SprintFunc()
return r(t...) return r(t...)
} }
// Bold font in red
func (c Green) Bold(t ...interface{}) string { func (c Green) Bold(t ...interface{}) string {
r := color.New(color.FgGreen, color.Bold).SprintFunc() r := color.New(color.FgGreen, color.Bold).SprintFunc()
return r(t...) return r(t...)

View File

@ -6,7 +6,7 @@ import (
"path/filepath" "path/filepath"
) )
// Scan return a byte stream of a given file // Stream return a byte stream of a given file
func (s Settings) Stream(file string) ([]byte, error) { func (s Settings) Stream(file string) ([]byte, error) {
_, err := os.Stat(file) _, err := os.Stat(file)
if err == nil { if err == nil {

View File

@ -5,6 +5,7 @@ import (
"os" "os"
) )
// Settings defines a group of general settings
type Settings struct { type Settings struct {
Colors `yaml:"-"` Colors `yaml:"-"`
Resources `yaml:"resources" json:"resources"` Resources `yaml:"resources" json:"resources"`
@ -12,10 +13,12 @@ type Settings struct {
Config `yaml:"config" json:"config"` Config `yaml:"config" json:"config"`
} }
// Config defines structural options
type Config struct { type Config struct {
Flimit uint64 `yaml:"flimit" json:"flimit"` Flimit uint64 `yaml:"flimit" json:"flimit"`
} }
// Server settings, used for the web panel
type Server struct { type Server struct {
Enabled bool `yaml:"enable" json:"enable"` Enabled bool `yaml:"enable" json:"enable"`
Open bool `yaml:"open" json:"open"` Open bool `yaml:"open" json:"open"`
@ -23,10 +26,12 @@ type Server struct {
Port int `yaml:"port" json:"port"` Port int `yaml:"port" json:"port"`
} }
// Resources defines the files generated by realize
type Resources struct { type Resources struct {
Config string `yaml:"-" json:"-"` Config string `yaml:"-" json:"-"`
Output string `yaml:"output" json:"output"` Streams string `yaml:"streams" json:"output"`
Log string `yaml:"log" json:"log"` Logs string `yaml:"logs" json:"log"`
Errors string `yaml:"errors" json:"error"`
} }
// Read from config file // Read from config file

View File

@ -6,12 +6,14 @@ import (
"path/filepath" "path/filepath"
) )
// Wdir return the current working directory
func (s Settings) Wdir() string { func (s Settings) Wdir() string {
dir, err := os.Getwd() dir, err := os.Getwd()
s.Validate(err) s.Validate(err)
return filepath.Base(dir) return filepath.Base(dir)
} }
// Validate checks a fatal error
func (s Settings) Validate(err error) error { func (s Settings) Validate(err error) error {
if err != nil { if err != nil {
s.Fatal(err, "") s.Fatal(err, "")
@ -19,6 +21,7 @@ func (s Settings) Validate(err error) error {
return nil return nil
} }
// Fatal prints a fatal error with its additional messages
func (s Settings) Fatal(err error, msg ...interface{}) { func (s Settings) Fatal(err error, msg ...interface{}) {
if len(msg) > 0 { if len(msg) > 0 {
log.Fatalln(s.Red.Regular(msg...), err.Error()) log.Fatalln(s.Red.Regular(msg...), err.Error())

View File

@ -8,7 +8,7 @@ import (
"strings" "strings"
) )
// Watch method adds the given paths on the Watcher // Run launches the toolchain for each project
func (h *Blueprint) Run() error { func (h *Blueprint) Run() error {
err := h.check() err := h.check()
if err == nil { if err == nil {
@ -68,7 +68,7 @@ func (h *Blueprint) Clean() {
} }
} }
// Inserts a new project in the list // Insert a new project in projects list
func (h *Blueprint) Insert(p *cli.Context) error { func (h *Blueprint) Insert(p *cli.Context) error {
err := h.Add(p) err := h.Add(p)
return err return err
@ -134,9 +134,8 @@ func (h *Blueprint) check() error {
if len(h.Projects) > 0 { if len(h.Projects) > 0 {
h.Clean() h.Clean()
return nil return nil
} else {
return errors.New("There are no projects. The config file is empty.")
} }
return errors.New("There are no projects. The config file is empty.")
} }
// NameParam check the project name presence. If empty takes the working directory name // NameParam check the project name presence. If empty takes the working directory name

View File

@ -3,6 +3,7 @@ package cli
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"fmt"
"log" "log"
"os" "os"
"os/exec" "os/exec"
@ -14,11 +15,9 @@ import (
// GoRun is an implementation of the bin execution // GoRun is an implementation of the bin execution
func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup) error { func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup) error {
var build *exec.Cmd var build *exec.Cmd
var params []string var params []string
var path = "" var path = ""
for _, param := range p.Params { for _, param := range p.Params {
arr := strings.Fields(param) arr := strings.Fields(param)
params = append(params, arr...) params = append(params, arr...)
@ -45,15 +44,14 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Failed to stop: " + err.Error()}) p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Failed to stop: " + err.Error()})
p.Fatal(err, "Failed to stop", ":") p.Fatal(err, "Failed to stop", ":")
} }
p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Ended"}) msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Regular("Ended"))
log.Println(p.pname(p.Name, 2), ":", p.Red.Regular("Ended")) out := BufferOut{Time: time.Now(), Text: "Ended", Type: "Go Run"}
p.sync() p.print("log", out, msg, "")
wr.Done() wr.Done()
}() }()
stdout, err := build.StdoutPipe() stdout, err := build.StdoutPipe()
stderr, err := build.StderrPipe() stderr, err := build.StderrPipe()
if err != nil { if err != nil {
log.Println(p.Red.Bold(err.Error())) log.Println(p.Red.Bold(err.Error()))
return err return err
@ -66,35 +64,24 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
execOutput, execError := bufio.NewScanner(stdout), bufio.NewScanner(stderr) execOutput, execError := bufio.NewScanner(stdout), bufio.NewScanner(stderr)
stopOutput, stopError := make(chan bool, 1), make(chan bool, 1) stopOutput, stopError := make(chan bool, 1), make(chan bool, 1)
scanner := func(stop chan bool, output *bufio.Scanner, isError bool) { scanner := func(stop chan bool, output *bufio.Scanner, isError bool) {
for output.Scan() { for output.Scan() {
select { select {
default: default:
msg := fmt.Sprintln(p.pname(p.Name, 3), ":", p.Blue.Regular(output.Text()))
if isError { if isError {
p.Buffer.StdErr = append(p.Buffer.StdErr, BufferOut{Time: time.Now(), Text: output.Text(), Type: "Go Run"}) out := BufferOut{Time: time.Now(), Text: output.Text(), Type: "Go Run"}
p.print("error", out, msg, "")
} else { } else {
p.Buffer.StdOut = append(p.Buffer.StdOut, BufferOut{Time: time.Now(), Text: output.Text()}) out := BufferOut{Time: time.Now(), Text: output.Text()}
} p.print("out", out, msg, "")
p.sync()
if p.Cli.Streams {
log.Println(p.pname(p.Name, 3), ":", p.Blue.Regular(output.Text()))
}
if p.File.Streams {
f := p.Create(p.base, p.parent.Resources.Output)
t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + output.Text() + "\r\n"); err != nil {
p.Fatal(err, "")
}
} }
} }
} }
close(stop) close(stop)
} }
p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Started"})
go scanner(stopOutput, execOutput, false) go scanner(stopOutput, execOutput, false)
go scanner(stopError, execError, true) go scanner(stopError, execError, true)
for { for {
select { select {
case <-channel: case <-channel:
@ -109,9 +96,6 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
// GoBuild is an implementation of the "go build" // GoBuild is an implementation of the "go build"
func (p *Project) goBuild() (string, error) { func (p *Project) goBuild() (string, error) {
defer func() {
p.sync()
}()
var out bytes.Buffer var out bytes.Buffer
var stderr bytes.Buffer var stderr bytes.Buffer
build := exec.Command("go", "build") build := exec.Command("go", "build")
@ -126,9 +110,6 @@ func (p *Project) goBuild() (string, error) {
// GoInstall is an implementation of the "go install" // GoInstall is an implementation of the "go install"
func (p *Project) goInstall() (string, error) { func (p *Project) goInstall() (string, error) {
defer func() {
p.sync()
}()
var out bytes.Buffer var out bytes.Buffer
var stderr bytes.Buffer var stderr bytes.Buffer
err := os.Setenv("GOBIN", filepath.Join(os.Getenv("GOPATH"), "bin")) err := os.Setenv("GOBIN", filepath.Join(os.Getenv("GOPATH"), "bin"))
@ -145,37 +126,11 @@ func (p *Project) goInstall() (string, error) {
return "", nil return "", nil
} }
// GoFmt is an implementation of the gofmt // GoTools is used for run go methods such as fmt, test, generate...
func (p *Project) goFmt(path string) (string, error) { func (p *Project) goTools(dir string, name string, cmd ...string) (string, error) {
var out, stderr bytes.Buffer var out, stderr bytes.Buffer
build := exec.Command("gofmt", "-s", "-w", "-e", path) build := exec.Command(name, cmd...)
build.Dir = p.base build.Dir = dir
build.Stdout = &out
build.Stderr = &stderr
if err := build.Run(); err != nil {
return stderr.String(), err
}
return "", nil
}
// GoTest is an implementation of the go test
func (p *Project) goTest(path string) (string, error) {
var out, stderr bytes.Buffer
build := exec.Command("go", "test")
build.Dir = path
build.Stdout = &out
build.Stderr = &stderr
if err := build.Run(); err != nil {
return stderr.String(), err
}
return "", nil
}
// GoGenerate is an implementation of the go test
func (p *Project) goGenerate(path string) (string, error) {
var out, stderr bytes.Buffer
build := exec.Command("go", "generate")
build.Dir = path
build.Stdout = &out build.Stdout = &out
build.Stderr = &stderr build.Stderr = &stderr
if err := build.Run(); err != nil { if err := build.Run(); err != nil {
@ -185,30 +140,21 @@ func (p *Project) goGenerate(path string) (string, error) {
} }
// Cmds exec a list of defined commands // Cmds exec a list of defined commands
func (p *Project) cmds(cmds []string) (errors []string) { func (p *Project) afterBefore(command string) (errors string, logs string) {
defer func() { var stdout bytes.Buffer
p.sync()
}()
for _, cmd := range cmds {
var out bytes.Buffer
var stderr bytes.Buffer var stderr bytes.Buffer
cmd := strings.Replace(strings.Replace(cmd, "'", "", -1), "\"", "", -1) command = strings.Replace(strings.Replace(command, "'", "", -1), "\"", "", -1)
c := strings.Split(cmd, " ") c := strings.Split(command, " ")
build := exec.Command(c[0], c[1:]...) build := exec.Command(c[0], c[1:]...)
build.Dir = p.base build.Dir = p.base
build.Stdout = &out build.Stdout = &stdout
build.Stderr = &stderr build.Stderr = &stderr
if err := build.Run(); err != nil { err := build.Run()
errors = append(errors, stderr.String()) // check if log
return errors logs = stdout.String()
if err != nil {
errors = stderr.String()
return errors, logs
} }
} return "", logs
return nil
}
// Sync datas with the web server
func (p *Project) sync() {
go func() {
p.parent.Sync <- "sync"
}()
} }

View File

@ -14,7 +14,7 @@ type logWriter struct {
c.Colors c.Colors
} }
// Projects struct contains a projects list // Blueprint struct contains a projects list
type Blueprint struct { type Blueprint struct {
*c.Settings `yaml:"-"` *c.Settings `yaml:"-"`
Projects []Project `yaml:"projects,omitempty" json:"projects,omitempty"` Projects []Project `yaml:"projects,omitempty" json:"projects,omitempty"`
@ -28,12 +28,12 @@ type Project struct {
base string base string
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Path string `yaml:"path" json:"path"` Path string `yaml:"path" json:"path"`
Run bool `yaml:"run" json:"run"`
Bin bool `yaml:"bin" json:"bin"`
Generate bool `yaml:"generate" json:"generate"`
Build bool `yaml:"build" json:"build"`
Fmt bool `yaml:"fmt" json:"fmt"` Fmt bool `yaml:"fmt" json:"fmt"`
Test bool `yaml:"test" json:"test"` Test bool `yaml:"test" json:"test"`
Generate bool `yaml:"generate" json:"generate"`
Bin bool `yaml:"bin" json:"bin"`
Build bool `yaml:"build" json:"build"`
Run bool `yaml:"run" json:"run"`
Params []string `yaml:"params" json:"params"` Params []string `yaml:"params" json:"params"`
Watcher Watcher `yaml:"watcher" json:"watcher"` Watcher Watcher `yaml:"watcher" json:"watcher"`
Cli Cli `yaml:"cli" json:"cli"` Cli Cli `yaml:"cli" json:"cli"`
@ -54,23 +54,26 @@ type Watcher struct {
Preview bool `yaml:"preview" json:"preview"` Preview bool `yaml:"preview" json:"preview"`
} }
// Cli output status, enables or disables
type Cli struct { type Cli struct {
Streams bool `yaml:"streams" json:"streams"` Streams bool `yaml:"streams" json:"streams"`
} }
// File determinates the status of each log files (streams, logs, errors)
type File struct { type File struct {
Streams bool `yaml:"streams" json:"streams"` Streams bool `yaml:"streams" json:"streams"`
Logs bool `yaml:"logs" json:"logs"` Logs bool `yaml:"logs" json:"logs"`
Errors bool `yaml:"errors" json:"errors"` Errors bool `yaml:"errors" json:"errors"`
} }
// Buffer struct for buffering outputs // Buffer define an array buffer for each log files
type Buffer struct { type Buffer struct {
StdOut []BufferOut `json:"stdOut"` StdOut []BufferOut `json:"stdOut"`
StdLog []BufferOut `json:"stdLog"` StdLog []BufferOut `json:"stdLog"`
StdErr []BufferOut `json:"stdErr"` StdErr []BufferOut `json:"stdErr"`
} }
// BufferOut is used for exchange information between "realize cli" and "web realize"
type BufferOut struct { type BufferOut struct {
Time time.Time `json:"time"` Time time.Time `json:"time"`
Text string `json:"text"` Text string `json:"text"`

View File

@ -8,6 +8,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"sync" "sync"
"syscall" "syscall"
@ -56,11 +57,9 @@ func (p *Project) watching() {
file := event.Name[:i] + ext file := event.Name[:i] + ext
path := filepath.Dir(event.Name[:i]) path := filepath.Dir(event.Name[:i])
if event.Name[:i] != "" && inArray(ext, p.Watcher.Exts) { if event.Name[:i] != "" && inArray(ext, p.Watcher.Exts) {
p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: strings.ToUpper(ext[1:]) + " changed " + file}) msg := fmt.Sprintln(p.pname(p.Name, 4), ":", p.Magenta.Bold(strings.ToUpper(ext[1:])+" changed"), p.Magenta.Bold(file))
go func() { out := BufferOut{Time: time.Now(), Text: strings.ToUpper(ext[1:]) + " changed " + file}
p.parent.Sync <- "sync" p.print("log", out, msg, "")
}()
log.Println(p.pname(p.Name, 4), ":", p.Magenta.Bold(strings.ToUpper(ext[1:])+" changed"), p.Magenta.Bold(file))
// stop and run again // stop and run again
if p.Run { if p.Run {
close(channel) close(channel)
@ -83,25 +82,27 @@ func (p *Project) watching() {
} }
} }
// Install calls an implementation of the "go install" // Install calls an implementation of "go install"
func (p *Project) install() { func (p *Project) install() error {
if p.Bin { if p.Bin {
start := time.Now() start := time.Now()
log.Println(p.pname(p.Name, 1), ":", "Installing..") log.Println(p.pname(p.Name, 1), ":", "Installing..")
if stream, err := p.goInstall(); err != nil { stream, err := p.goInstall()
if err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Install"), p.Red.Regular(err.Error())) msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Install"), p.Red.Regular(err.Error()))
out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Install", Stream: stream} out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Install", Stream: stream}
p.print("error", out, msg, stream) p.print("error", out, msg, stream)
} else { } else {
msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Installed")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Installed")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
out := BufferOut{Time: time.Now(), Text: "Installed"} out := BufferOut{Time: time.Now(), Text: "Installed after " + big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3) + " s"}
p.print("log", out, msg, stream) p.print("log", out, msg, stream)
} }
p.sync() return err
} }
return return nil
} }
// Install calls an implementation of "go run"
func (p *Project) run(channel chan bool, wr *sync.WaitGroup) { func (p *Project) run(channel chan bool, wr *sync.WaitGroup) {
if p.Run { if p.Run {
start := time.Now() start := time.Now()
@ -112,7 +113,7 @@ func (p *Project) run(channel chan bool, wr *sync.WaitGroup) {
select { select {
case <-runner: case <-runner:
msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Has been run")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Has been run")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
out := BufferOut{Time: time.Now(), Text: "Has been run"} out := BufferOut{Time: time.Now(), Text: "Has been run after " + big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3) + " s"}
p.print("log", out, msg, "") p.print("log", out, msg, "")
return return
} }
@ -121,31 +122,29 @@ func (p *Project) run(channel chan bool, wr *sync.WaitGroup) {
} }
// Build calls an implementation of the "go build" // Build calls an implementation of the "go build"
func (p *Project) build() { func (p *Project) build() error {
if p.Build { if p.Build {
start := time.Now() start := time.Now()
log.Println(p.pname(p.Name, 1), ":", "Building..") log.Println(p.pname(p.Name, 1), ":", "Building..")
if stream, err := p.goBuild(); err != nil { stream, err := p.goBuild()
if err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Build"), p.Red.Regular(err.Error())) msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Build"), p.Red.Regular(err.Error()))
out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Build", Stream: stream} out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Build", Stream: stream}
p.print("error", out, msg, stream) p.print("error", out, msg, stream)
} else { } else {
msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Builded")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Builded")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
out := BufferOut{Time: time.Now(), Text: "Builded"} out := BufferOut{Time: time.Now(), Text: "Builded after " + big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3) + " s"}
p.print("log", out, msg, stream) p.print("log", out, msg, stream)
} }
p.sync() return err
} }
return return nil
} }
// Fmt calls an implementation of the "go fmt" // Fmt calls an implementation of the "go fmt"
func (p *Project) fmt(path string) error { func (p *Project) fmt(path string) error {
defer func() { if p.Fmt {
p.sync() if stream, err := p.goTools(p.base, "gofmt", "-s", "-w", "-e", path); err != nil {
}()
if p.Fmt && strings.HasSuffix(path, ".go") {
if stream, err := p.goFmt(path); err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Fmt"), p.Red.Regular("there are some errors in"), ":", p.Magenta.Bold(path)) msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Fmt"), p.Red.Regular("there are some errors in"), ":", p.Magenta.Bold(path))
out := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: "Go Fmt", Stream: stream} out := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: "Go Fmt", Stream: stream}
p.print("error", out, msg, stream) p.print("error", out, msg, stream)
@ -157,11 +156,8 @@ func (p *Project) fmt(path string) error {
// Generate calls an implementation of the "go generate" // Generate calls an implementation of the "go generate"
func (p *Project) generate(path string) error { func (p *Project) generate(path string) error {
defer func() {
p.sync()
}()
if p.Generate { if p.Generate {
if stream, err := p.goGenerate(path); err != nil { if stream, err := p.goTools(path, "go", "generate"); err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Generate"), p.Red.Regular("there are some errors in"), ":", p.Magenta.Bold(path)) msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Generate"), p.Red.Regular("there are some errors in"), ":", p.Magenta.Bold(path))
out := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: "Go Generate", Stream: stream} out := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: "Go Generate", Stream: stream}
p.print("error", out, msg, stream) p.print("error", out, msg, stream)
@ -171,17 +167,44 @@ func (p *Project) generate(path string) error {
return nil return nil
} }
// Test calls an implementation of the "go test"
func (p *Project) test(path string) error {
if p.Test {
if stream, err := p.goTools(path, "go", "test"); err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Test"), p.Red.Regular("there are some errors in "), ":", p.Magenta.Bold(path))
out := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: "Go Test", Stream: stream}
p.print("error", out, msg, stream)
return err
}
}
return nil
}
// Cmd calls an wrapper for execute the commands after/before // Cmd calls an wrapper for execute the commands after/before
func (p *Project) cmd(exit chan bool) { func (p *Project) cmd(exit chan bool) {
c := make(chan os.Signal, 2) c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
cast := func(commands []string) { cast := func(commands []string) {
if errs := p.cmds(commands); errs != nil { for _, command := range commands {
for _, err := range errs { errors, logs := p.afterBefore(command)
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold(err)) msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Bold("Command"), p.Green.Bold("\"")+command+p.Green.Bold("\""))
out := BufferOut{Time: time.Now(), Text: err, Type: "After/Before"} out := BufferOut{Time: time.Now(), Text: command, Type: "After/Before"}
if logs != "" {
p.print("log", out, msg, "")
}
if errors != "" {
p.print("error", out, msg, "") p.print("error", out, msg, "")
} }
if logs != "" {
msg = fmt.Sprintln(logs)
out = BufferOut{Time: time.Now(), Text: logs, Type: "After/Before"}
p.print("log", out, "", msg)
}
if errors != "" {
msg = fmt.Sprintln(p.Red.Regular(errors))
out = BufferOut{Time: time.Now(), Text: errors, Type: "After/Before"}
p.print("error", out, "", msg)
}
} }
} }
@ -202,22 +225,6 @@ func (p *Project) cmd(exit chan bool) {
}() }()
} }
// Test calls an implementation of the "go test"
func (p *Project) test(path string) error {
defer func() {
p.sync()
}()
if p.Test {
if stream, err := p.goTest(path); err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Test"), p.Red.Regular("there are some errors in "), ":", p.Magenta.Bold(path))
out := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: "Go Test", Stream: stream}
p.print("error", out, msg, stream)
return err
}
}
return nil
}
// Walks the file tree of a project // Walks the file tree of a project
func (p *Project) walks(watcher *fsnotify.Watcher) error { func (p *Project) walks(watcher *fsnotify.Watcher) error {
var files, folders int64 var files, folders int64
@ -262,11 +269,13 @@ func (p *Project) walks(watcher *fsnotify.Watcher) error {
return errors.New(base + " path doesn't exist") return errors.New(base + " path doesn't exist")
} }
} }
log.Println(p.pname(p.Name, 1), ":", p.Blue.Bold("Watching"), p.Magenta.Bold(files), "file/s", p.Magenta.Bold(folders), "folder/s") msg := fmt.Sprintln(p.pname(p.Name, 1), ":", p.Blue.Bold("Watching"), p.Magenta.Bold(files), "file/s", p.Magenta.Bold(folders), "folder/s")
out := BufferOut{Time: time.Now(), Text: "Watching " + strconv.FormatInt(files, 10) + " files/s " + strconv.FormatInt(folders, 10) + " folder/s"}
p.print("log", out, msg, "")
return nil return nil
} }
// Ignore validates a path // Ignore and validate a path
func (p *Project) ignore(str string) bool { func (p *Project) ignore(str string) bool {
for _, v := range p.Watcher.Ignore { for _, v := range p.Watcher.Ignore {
if strings.Contains(str, filepath.Join(p.base, v)) { if strings.Contains(str, filepath.Join(p.base, v)) {
@ -276,12 +285,14 @@ func (p *Project) ignore(str string) bool {
return false return false
} }
// Routines launches the following methods: run, build, install // Routines launches the toolchain run, build, install
func (p *Project) routines(channel chan bool, wr *sync.WaitGroup) { func (p *Project) routines(channel chan bool, wr *sync.WaitGroup) {
p.install() install := p.install()
p.build() build := p.build()
wr.Add(1) wr.Add(1)
if install == nil && build == nil {
go p.run(channel, wr) go p.run(channel, wr)
}
wr.Wait() wr.Wait()
} }
@ -307,39 +318,59 @@ func (p *Project) pname(name string, color int) string {
return name return name
} }
// Print on files, cli, ws
func (p *Project) print(t string, o BufferOut, msg string, stream string) { func (p *Project) print(t string, o BufferOut, msg string, stream string) {
switch t { switch t {
case "out": case "out":
p.Buffer.StdOut = append(p.Buffer.StdOut, o) p.Buffer.StdOut = append(p.Buffer.StdOut, o)
if p.File.Streams { if p.File.Streams {
f := p.Create(p.base, p.parent.Resources.Output) f := p.Create(p.base, p.parent.Resources.Streams)
t := time.Now() t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil { s := []string{t.Format("2006-01-02 15:04:05"), strings.ToUpper(p.Name), ":", o.Text, "\r\n"}
if _, err := f.WriteString(strings.Join(s, " ")); err != nil {
p.Fatal(err, "") p.Fatal(err, "")
} }
} }
if msg != "" && p.Cli.Streams {
log.Print(msg)
}
case "log": case "log":
p.Buffer.StdLog = append(p.Buffer.StdLog, o) p.Buffer.StdLog = append(p.Buffer.StdLog, o)
if p.File.Logs { if p.File.Logs {
f := p.Create(p.base, p.parent.Resources.Log) f := p.Create(p.base, p.parent.Resources.Logs)
t := time.Now() t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil { s := []string{t.Format("2006-01-02 15:04:05"), strings.ToUpper(p.Name), ":", o.Text, "\r\n"}
if stream != "" {
s = []string{t.Format("2006-01-02 15:04:05"), strings.ToUpper(p.Name), ":", o.Text, "\r\n", stream}
}
if _, err := f.WriteString(strings.Join(s, " ")); err != nil {
p.Fatal(err, "") p.Fatal(err, "")
} }
} }
if msg != "" {
log.Print(msg)
}
case "error": case "error":
p.Buffer.StdErr = append(p.Buffer.StdErr, o) p.Buffer.StdErr = append(p.Buffer.StdErr, o)
if p.File.Errors { if p.File.Errors {
f := p.Create(p.base, p.parent.Resources.Log) f := p.Create(p.base, p.parent.Resources.Errors)
t := time.Now() t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil { s := []string{t.Format("2006-01-02 15:04:05"), strings.ToUpper(p.Name), ":", o.Type, o.Text, o.Path, "\r\n"}
if stream != "" {
s = []string{t.Format("2006-01-02 15:04:05"), strings.ToUpper(p.Name), ":", o.Type, o.Text, o.Path, "\r\n", stream}
}
if _, err := f.WriteString(strings.Join(s, " ")); err != nil {
p.Fatal(err, "") p.Fatal(err, "")
} }
} }
if msg != "" {
}
log.Print(msg) log.Print(msg)
if stream != "" {
fmt.Println(stream)
} }
}
if stream != "" {
fmt.Print(stream)
}
go func() {
p.parent.Sync <- "sync"
}()
} }