diff --git a/.travis.yml b/.travis.yml index 4fc1614..1d9f6af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: go go: - 1.7 - 1.8 + - 1.9 - tip matrix: allow_failures: diff --git a/realize.go b/realize.go index 60b3bf7..4787066 100644 --- a/realize.go +++ b/realize.go @@ -7,87 +7,43 @@ import ( "time" "github.com/fatih/color" + "github.com/tockins/interact" "github.com/tockins/realize/server" "github.com/tockins/realize/settings" "github.com/tockins/realize/style" "github.com/tockins/realize/watcher" - "github.com/tockins/interact" cli "gopkg.in/urfave/cli.v2" ) const ( - appVersion = "1.4.1" - config = "realize.yaml" - outputs = "outputs.log" - errs = "errors.log" - logs = "logs.log" - host = "localhost" - port = 3001 - interval = 200 + version = "1.4.1" + config = "realize.yaml" + directory = ".realize" + outputs = "outputs.log" + errs = "errors.log" + logs = "logs.log" + host = "localhost" + port = 3001 + interval = 200 ) +// Realize struct contains the general app informations +type realize struct { + settings.Settings `yaml:"settings,omitempty"` + Sync chan string `yaml:"-"` + Blueprint watcher.Blueprint `yaml:"-"` + Server server.Server `yaml:"-"` + Projects *[]watcher.Project `yaml:"projects" json:"projects"` +} + +// New realize instance +var r realize + // Cli commands func main() { - // Realize struct contains the general app informations - type realize struct { - settings.Settings `yaml:"settings,omitempty"` - Sync chan string `yaml:"-"` - Blueprint watcher.Blueprint `yaml:"-"` - Server server.Server `yaml:"-"` - Projects *[]watcher.Project `yaml:"projects" json:"projects"` - } - var r realize - // Before of every exec of a cli method - before := func(*cli.Context) error { - gopath := os.Getenv("GOPATH") - if gopath == "" { - return errors.New("$GOPATH isn't set properly") - } - r = realize{ - Sync: make(chan string), - Settings: settings.Settings{ - Config: settings.Config{ - Create: true, - }, - Resources: settings.Resources{ - Config: config, - Outputs: outputs, - Logs: logs, - Errors: errs, - }, - Server: settings.Server{ - Status: false, - Open: false, - Host: host, - Port: port, - }, - }, - } - r.Blueprint = watcher.Blueprint{ - Settings: &r.Settings, - Sync: r.Sync, - } - r.Server = server.Server{ - Blueprint: &r.Blueprint, - Settings: &r.Settings, - Sync: r.Sync, - } - r.Projects = &r.Blueprint.Projects - - // read if exist - r.Read(&r) - - // increase the file limit - if r.Config.Flimit != 0 { - if err := r.Flimit(); err != nil { - return err - } - } - return nil - } app := &cli.App{ Name: "Realize", - Version: appVersion, + Version: version, Authors: []*cli.Author{ { Name: "Alessio Pracchia", @@ -118,29 +74,18 @@ func main() { &cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."}, }, Action: func(p *cli.Context) error { - if p.Bool("legacy") { - r.Config.Legacy = settings.Legacy{ - Status: p.Bool("legacy"), - Interval: interval, - } + polling(p, &r.Config.Legacy) + noconf(p, &r.Settings.Config) + if err := insert(p, &r.Blueprint); err != nil { + return err } - if p.Bool("no-config") || len(r.Blueprint.Projects) <= 0 { - if p.Bool("no-config") { - r.Config.Create = false - } - r.Blueprint.Projects = []watcher.Project{} - if err := r.Blueprint.Add(p); err != nil { - return err - } - } - if err := r.Server.Start(p); err != nil { return err } if err := r.Blueprint.Run(p); err != nil { return err } - if !p.Bool("no-config") { + if r.Config.Create { if err := r.Record(r); err != nil { return err } @@ -167,14 +112,13 @@ func main() { &cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."}, }, Action: func(p *cli.Context) error { - fmt.Fprintln(style.Output, p.String("path")) if err := r.Blueprint.Add(p); err != nil { return err } if err := r.Record(r); err != nil { return err } - fmt.Fprintln(style.Output, style.Yellow.Bold("[")+"REALIZE"+style.Yellow.Bold("]"), style.Green.Bold("Your project was successfully added.")) + fmt.Fprintln(style.Output,prefix(style.Green.Bold("Your project was successfully added."))) return nil }, Before: before, @@ -194,7 +138,7 @@ func main() { Questions: []*interact.Question{ { Before: func(d interact.Context) error { - if _, err := os.Stat(settings.Directory + config); err != nil { + if _, err := os.Stat(directory + "/" + config); err != nil { d.Skip() } d.SetDef(false, style.Green.Regular("(n)")) @@ -214,10 +158,7 @@ func main() { Create: true, }, Resources: settings.Resources{ - Config: config, - Outputs: outputs, - Logs: logs, - Errors: errs, + Config: config, }, Server: settings.Server{ Status: false, @@ -733,7 +674,7 @@ func main() { if err != nil { return d.Err() } - r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Watcher.Scripts = append(r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Watcher.Scripts, watcher.Command{Type: "before", Command: val, Changed: true, Startup: true}) + r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Watcher.Scripts = append(r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Watcher.Scripts, watcher.Command{Type: "before", Command: val}) d.Reload() return nil }, @@ -775,7 +716,7 @@ func main() { if err != nil { return d.Err() } - r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Watcher.Scripts = append(r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Watcher.Scripts, watcher.Command{Type: "after", Command: val, Changed: true, Startup: true}) + r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Watcher.Scripts = append(r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Watcher.Scripts, watcher.Command{Type: "after", Command: val}) d.Reload() return nil }, @@ -807,60 +748,6 @@ func main() { return nil }, }, - { - Before: func(d interact.Context) error { - d.SetDef(false, style.Green.Regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: style.Yellow.Regular("[y/n]"), - Msg: "Enable file output history", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Streams.FileOut = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, style.Green.Regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: style.Yellow.Regular("[y/n]"), - Msg: "Enable file logs history", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Streams.FileLog = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, style.Green.Regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: style.Yellow.Regular("[y/n]"), - Msg: "Enable file errors history", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Blueprint.Projects[len(r.Blueprint.Projects)-1].Streams.FileErr = val - return nil - }, - }, { Before: func(d interact.Context) error { d.SetDef("", style.Green.Regular("(none)")) @@ -892,7 +779,7 @@ func main() { }, After: func(d interact.Context) error { if val, _ := d.Qns().Get(0).Ans().Bool(); val { - actErr = r.Settings.Remove(settings.Directory) + actErr = r.Settings.Remove(directory) if actErr != nil { return actErr } @@ -903,7 +790,7 @@ func main() { if err := r.Record(r); err != nil { return err } - fmt.Fprintln(style.Output, style.Yellow.Bold("[")+"REALIZE"+style.Yellow.Bold("]"), style.Green.Bold("Your configuration was successful.")) + fmt.Fprintln(style.Output,prefix(style.Green.Bold("Your configuration was successful."))) return nil }, Before: before, @@ -923,7 +810,7 @@ func main() { if err := r.Record(r); err != nil { return err } - fmt.Fprintln(style.Output, style.Yellow.Bold("[")+"REALIZE"+style.Yellow.Bold("]"), style.Green.Bold("Your project was successfully removed.")) + fmt.Fprintln(style.Output,prefix(style.Green.Bold("Your project was successfully removed."))) return nil }, Before: before, @@ -944,10 +831,10 @@ func main() { Aliases: []string{"c"}, Description: "Remove realize folder.", Action: func(p *cli.Context) error { - if err := r.Settings.Remove(settings.Directory); err != nil { + if err := r.Settings.Remove(directory); err != nil { return err } - fmt.Fprintln(style.Output, style.Yellow.Bold("[")+"REALIZE"+style.Yellow.Bold("]"), style.Green.Bold("Realize folder successfully removed.")) + fmt.Fprintln(style.Output,prefix(style.Green.Bold("Realize folder successfully removed."))) return nil }, Before: before, @@ -955,7 +842,87 @@ func main() { }, } if err := app.Run(os.Args); err != nil { - fmt.Fprintln(style.Output, style.Red.Bold(err)) + print(style.Red.Bold(err)) os.Exit(1) } } + +// Prefix a given string +func prefix(s string) string { + if s != "" { + return fmt.Sprint(style.Yellow.Bold("[")+"REALIZE"+style.Yellow.Bold("]"), s) + } + return "" +} + +// Before is launched before each command +func before(*cli.Context) error { + // Before of every exec of a cli method + gopath := os.Getenv("GOPATH") + if gopath == "" { + return errors.New("$GOPATH isn't set properly") + } + r = realize{ + Sync: make(chan string), + Settings: settings.Settings{ + Config: settings.Config{ + Create: true, + }, + Resources: settings.Resources{ + Config: config, + }, + Server: settings.Server{ + Status: false, + Open: false, + Host: host, + Port: port, + }, + }, + } + r.Blueprint = watcher.Blueprint{ + Settings: &r.Settings, + Sync: r.Sync, + } + r.Server = server.Server{ + Blueprint: &r.Blueprint, + Settings: &r.Settings, + Sync: r.Sync, + } + r.Projects = &r.Blueprint.Projects + + // read if exist + r.Read(&r) + + // increase the file limit + if r.Config.Flimit != 0 { + if err := r.Flimit(); err != nil { + return err + } + } + return nil +} + +// Check for the noconf option +func noconf(c *cli.Context, s *settings.Config) { + if c.Bool("no-config") { + s.Create = false + } +} + +// Check for polling option +func polling(c *cli.Context, s *settings.Legacy) { + if c.Bool("legacy") { + s.Status = c.Bool("legacy") + s.Interval = interval + } +} + +// Insert a project if there isn't already one +func insert(c *cli.Context, b *watcher.Blueprint) error { + if len(b.Projects) <= 0 { + if err := b.Add(c); err != nil { + return err + } + } + return nil +} diff --git a/realize_test.go b/realize_test.go new file mode 100644 index 0000000..1de4326 --- /dev/null +++ b/realize_test.go @@ -0,0 +1,68 @@ +package main + +import ( + "flag" + "fmt" + "github.com/tockins/realize/settings" + "github.com/tockins/realize/style" + "github.com/tockins/realize/watcher" + "gopkg.in/urfave/cli.v2" + "testing" +) + +func TestPrefix(t *testing.T) { + input := settings.Rand(10) + value := fmt.Sprint(style.Yellow.Bold("[")+"REALIZE"+style.Yellow.Bold("]"), input) + result := prefix(input) + if result == "" { + t.Fatal("Expected a string") + } + if result != value { + t.Fatal("Expected", value, "Instead", result) + } +} + +func TestBefore(t *testing.T) { + context := cli.Context{} + if err := before(&context); err != nil { + t.Fatal(err) + } +} + +func TestNoConf(t *testing.T) { + settings := settings.Config{Create: true} + set := flag.NewFlagSet("test", 0) + set.Bool("no-config", true, "") + params := cli.NewContext(nil, set, nil) + noconf(params, &settings) + if settings.Create == true { + t.Fatal("Expected", false, "Instead", true) + } +} + +func TestPolling(t *testing.T) { + settings := settings.Legacy{} + set := flag.NewFlagSet("test", 0) + set.Bool("legacy", true, "") + params := cli.NewContext(nil, set, nil) + polling(params, &settings) + if settings.Interval == 0 || settings.Status == false { + t.Fatal("Expected status", true, "Instead", false) + t.Fatal("Expected interval", interval, "Instead", 0) + } +} + +func TestInsert(t *testing.T) { + b := watcher.Blueprint{} + b.Settings = &settings.Settings{} + set := flag.NewFlagSet("test", 0) + set.String("name", settings.Rand(5), "") + set.String("path", settings.Rand(5), "") + params := cli.NewContext(nil, set, nil) + if err := insert(params, &b); err != nil { + t.Fatal(err) + } + if len(b.Projects) == 0 { + t.Error("Expected one project") + } +} diff --git a/server/open.go b/server/open.go index 57cc62f..a343c24 100644 --- a/server/open.go +++ b/server/open.go @@ -20,7 +20,7 @@ func init() { } } -// Open a url in the default browser +// OpenURL is used for open an url in the default browser func (s *Server) OpenURL(url string) (io.Writer, error) { if s.Open { open, err := cmd[runtime.GOOS] diff --git a/settings/io.go b/settings/io.go index 2124117..f59e6db 100644 --- a/settings/io.go +++ b/settings/io.go @@ -19,19 +19,19 @@ func (s Settings) Stream(file string) ([]byte, error) { // Write a file func (s Settings) Write(name string, data []byte) error { - err := ioutil.WriteFile(name, data, Permission) + err := ioutil.WriteFile(name, data, permission) return s.Validate(err) } // Create a new file and return its pointer func (s Settings) Create(path string, name string) *os.File { var file string - if _, err := os.Stat(Directory); err == nil { - file = filepath.Join(path, Directory, name) + if _, err := os.Stat(directory); err == nil { + file = filepath.Join(path, directory, name) } else { file = filepath.Join(path, name) } - out, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY|os.O_CREATE|os.O_SYNC, Permission) + out, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY|os.O_CREATE|os.O_SYNC, permission) s.Validate(err) return out } diff --git a/settings/io_test.go b/settings/io_test.go index a45d6e0..9224ba4 100755 --- a/settings/io_test.go +++ b/settings/io_test.go @@ -1,7 +1,6 @@ package settings import ( - "github.com/labstack/gommon/random" "io/ioutil" "os" "testing" @@ -9,7 +8,7 @@ import ( func TestSettings_Stream(t *testing.T) { s := Settings{} - filename := random.String(4) + filename := Rand(4) if _, err := s.Stream(filename); err == nil { t.Fatal("Error expected, none found", filename, err) } diff --git a/settings/settings.go b/settings/settings.go index 2812352..ad4baa2 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -3,13 +3,14 @@ package settings import ( yaml "gopkg.in/yaml.v2" "os" + "path/filepath" "time" ) // settings const const ( - Permission = 0775 - Directory = ".realize/" + permission = 0775 + directory = ".realize" ) // Settings defines a group of general settings @@ -52,8 +53,9 @@ type Resources struct { func (s *Settings) Read(out interface{}) error { localConfigPath := s.Resources.Config // backward compatibility - if _, err := os.Stat(Directory + s.Resources.Config); err == nil { - localConfigPath = Directory + s.Resources.Config + path := filepath.Join(directory, s.Resources.Config) + if _, err := os.Stat(path); err == nil { + localConfigPath = path } content, err := s.Stream(localConfigPath) if err == nil { @@ -70,12 +72,12 @@ func (s *Settings) Record(out interface{}) error { if err != nil { return err } - if _, err := os.Stat(Directory); os.IsNotExist(err) { - if err = os.Mkdir(Directory, Permission); err != nil { + if _, err := os.Stat(directory); os.IsNotExist(err) { + if err = os.Mkdir(directory, permission); err != nil { return s.Write(s.Resources.Config, y) } } - return s.Write(Directory+s.Resources.Config, y) + return s.Write(filepath.Join(directory, s.Resources.Config), y) } return nil } diff --git a/settings/settings_test.go b/settings/settings_test.go index 17a2c77..c4d41a8 100644 --- a/settings/settings_test.go +++ b/settings/settings_test.go @@ -47,5 +47,5 @@ func TestSettings_Record(t *testing.T) { if err := s.Record(a); err != nil { t.Fatal(err) } - s.Remove(filepath.Join(Directory, s.Resources.Config)) + s.Remove(filepath.Join(directory, s.Resources.Config)) } diff --git a/settings/utils.go b/settings/utils.go index bf2a41a..3aa9519 100644 --- a/settings/utils.go +++ b/settings/utils.go @@ -2,11 +2,20 @@ package settings import ( "log" + "math/rand" "os" "path/filepath" "strings" "github.com/tockins/realize/style" + "time" +) + +const ( + letterIdxBits = 6 // 6 bits to represent a letter index + letterIdxMask = 1<= 0; { + if remain == 0 { + cache, remain = src.Int63(), letterIdxMax + } + if idx := int(cache & letterIdxMask); idx < len(letterBytes) { + b[i] = letterBytes[idx] + i-- + } + cache >>= letterIdxBits + remain-- + } + return string(b) +} diff --git a/settings/utils_test.go b/settings/utils_test.go index 5a00f45..612c502 100644 --- a/settings/utils_test.go +++ b/settings/utils_test.go @@ -2,7 +2,6 @@ package settings import ( "errors" - "github.com/labstack/gommon/random" "os" "path/filepath" "strings" @@ -32,8 +31,8 @@ func TestSettings_Validate(t *testing.T) { func TestSettings_Name(t *testing.T) { s := Settings{} - name := random.String(8) - path := random.String(5) + name := Rand(8) + path := Rand(5) dir, err := os.Getwd() if err != nil { t.Fatal(err) @@ -47,7 +46,7 @@ func TestSettings_Name(t *testing.T) { func TestSettings_Path(t *testing.T) { s := Settings{} - path := random.String(5) + path := Rand(5) expected := strings.Replace(filepath.Clean(path), "\\", "/", -1) result := s.Path(path) if result != expected { diff --git a/watcher/cmd.go b/watcher/cmd.go index d18ab8d..d2c078b 100644 --- a/watcher/cmd.go +++ b/watcher/cmd.go @@ -15,14 +15,17 @@ func (h *Blueprint) Run(p *cli.Context) error { err := h.check() if err == nil { // loop projects - wg.Add(len(h.Projects)) + if p.String("name") != "" { + wg.Add(1) + } else { + wg.Add(len(h.Projects)) + } for k, element := range h.Projects { if p.String("name") != "" && h.Projects[k].Name != p.String("name") { continue } - tools := tools{} if element.Cmds.Fmt { - tools.Fmt = tool{ + h.Projects[k].tools.Fmt = tool{ status: &h.Projects[k].Cmds.Fmt, cmd: "gofmt", options: []string{"-s", "-w", "-e"}, @@ -30,7 +33,7 @@ func (h *Blueprint) Run(p *cli.Context) error { } } if element.Cmds.Generate { - tools.Generate = tool{ + h.Projects[k].tools.Generate = tool{ status: &h.Projects[k].Cmds.Generate, cmd: "go", options: []string{"generate"}, @@ -38,7 +41,7 @@ func (h *Blueprint) Run(p *cli.Context) error { } } if element.Cmds.Test { - tools.Test = tool{ + h.Projects[k].tools.Test = tool{ status: &h.Projects[k].Cmds.Test, cmd: "go", options: []string{"test"}, @@ -46,14 +49,13 @@ func (h *Blueprint) Run(p *cli.Context) error { } } if element.Cmds.Vet { - tools.Vet = tool{ + h.Projects[k].tools.Vet = tool{ status: &h.Projects[k].Cmds.Vet, cmd: "go", options: []string{"vet"}, name: "Go Vet", } } - h.Projects[k].tools = tools h.Projects[k].parent = h h.Projects[k].path = h.Projects[k].Path @@ -127,7 +129,7 @@ func (h *Blueprint) Remove(p *cli.Context) error { return nil } } - return errors.New("no project found") + return errors.New("No project found.") } // List of all the projects @@ -189,5 +191,5 @@ func (h *Blueprint) check() error { h.Clean() return nil } - return errors.New("There are no projects") + return errors.New("There are no projects.") } diff --git a/watcher/exec.go b/watcher/exec.go index d619bc9..35123fd 100644 --- a/watcher/exec.go +++ b/watcher/exec.go @@ -27,7 +27,7 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup) 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"} - p.print("error", out, msg, "") + p.stamp("error", out, msg, "") } else { isErrorText = func(t string) bool { return errRegexp.MatchString(t) @@ -63,7 +63,7 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup) } msg := fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular("Ended")) out := BufferOut{Time: time.Now(), Text: "Ended", Type: "Go Run"} - p.print("log", out, msg, "") + p.stamp("log", out, msg, "") wr.Done() }() @@ -87,10 +87,10 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup) msg := fmt.Sprintln(p.pname(p.Name, 3), ":", style.Blue.Regular(text)) if isError && !isErrorText(text) { out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"} - p.print("error", out, msg, "") + p.stamp("error", out, msg, "") } else { out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"} - p.print("out", out, msg, "") + p.stamp("out", out, msg, "") } } close(stop) @@ -153,6 +153,9 @@ func (p *Project) goInstall() (string, error) { // GoTools is used for run go methods such as fmt, test, generate... func (p *Project) goTools(dir string, name string, cmd ...string) (string, error) { + if s := filepath.Ext(dir); s != "" && s != ".go" { + return "", nil + } var out, stderr bytes.Buffer build := exec.Command(name, cmd...) build.Dir = dir diff --git a/watcher/main.go b/watcher/main.go index fd57bd8..17540d8 100644 --- a/watcher/main.go +++ b/watcher/main.go @@ -90,8 +90,7 @@ type Command struct { Type string `yaml:"type" json:"type"` Command string `yaml:"command" json:"command"` Path string `yaml:"path,omitempty" json:"path,omitempty"` - Changed bool `yaml:"changed,omitempty" json:"changed,omitempty"` - Startup bool `yaml:"startup,omitempty" json:"startup,omitempty"` + Global bool `yaml:"global,omitempty" json:"changed,global"` } // Streams is a collection of names and values for the logs functionality diff --git a/watcher/watcher.go b/watcher/watcher.go index 7f370f6..70ca1e3 100644 --- a/watcher/watcher.go +++ b/watcher/watcher.go @@ -72,7 +72,7 @@ func (p *Project) watchByPolling() { // repeat the initial cycle msg = fmt.Sprintln(p.pname(p.Name, 4), ":", style.Magenta.Bold(strings.ToUpper(ext[1:])+" changed"), style.Magenta.Bold(file)) out = BufferOut{Time: time.Now(), Text: strings.ToUpper(ext[1:]) + " changed " + file} - p.print("log", out, msg, "") + p.stamp("log", out, msg, "") go p.routines(&wr, channel, watcher, file) } return nil @@ -84,16 +84,15 @@ func (p *Project) watchByPolling() { if err := filepath.Walk(base, walk); err != nil { msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular(err.Error())) out = BufferOut{Time: time.Now(), Text: err.Error()} - p.print("error", out, msg, "") + p.stamp("error", out, msg, "") } } else { msg = fmt.Sprintln(p.pname(p.Name, 2), ":", base, "path doesn't exist") out = BufferOut{Time: time.Now(), Text: base + " path doesn't exist"} - p.print("error", out, msg, "") + p.stamp("error", out, msg, "") } select { case <-exit: - p.cmd("after", false) return case <-time.After(p.parent.Legacy.Interval / time.Duration(len(p.Watcher.Paths))): } @@ -138,7 +137,7 @@ func (p *Project) watchByNotify() { // repeat the initial cycle msg = fmt.Sprintln(p.pname(p.Name, 4), ":", style.Magenta.Bold(strings.ToUpper(ext[1:])+" changed"), style.Magenta.Bold(file)) out = BufferOut{Time: time.Now(), Text: strings.ToUpper(ext[1:]) + " changed " + file} - p.print("log", out, msg, "") + p.stamp("log", out, msg, "") go p.routines(&wr, channel, watcher, file) p.LastChangedOn = time.Now().Truncate(time.Second) } @@ -147,9 +146,8 @@ func (p *Project) watchByNotify() { case err := <-watcher.Errors: msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular(err.Error())) out = BufferOut{Time: time.Now(), Text: err.Error()} - p.print("error", out, msg, "") + p.stamp("error", out, msg, "") case <-exit: - p.cmd("after", false) return } } @@ -161,7 +159,7 @@ func (p *Project) watch(watcher watcher) error { wd, _ := os.Getwd() walk := func(path string, info os.FileInfo, err error) error { if !p.ignore(path) { - if (info.IsDir() && len(filepath.Ext(path)) == 0 && !strings.HasPrefix(path, ".")) && !strings.Contains(path, "/.") || (inArray(filepath.Ext(path), p.Watcher.Exts)) { + if ((info.IsDir() && len(filepath.Ext(path)) == 0 && !strings.HasPrefix(path, ".")) && !strings.Contains(path, "/.")) || (inArray(filepath.Ext(path), p.Watcher.Exts)) { if p.Watcher.Preview { log.Println(p.pname(p.Name, 1), ":", path) } @@ -201,7 +199,7 @@ func (p *Project) watch(watcher watcher) error { } msg = fmt.Sprintln(p.pname(p.Name, 1), ":", style.Blue.Bold("Watching"), style.Magenta.Bold(files), "file/s", style.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, "") + p.stamp("log", out, msg, "") return nil } @@ -214,11 +212,11 @@ func (p *Project) install() error { if err != nil { msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Bold("Go Install"), style.Red.Regular(err.Error())) out = BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Install", Stream: stream} - p.print("error", out, msg, stream) + p.stamp("error", out, msg, stream) } else { msg = fmt.Sprintln(p.pname(p.Name, 5), ":", style.Green.Regular("Installed")+" after", style.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) 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.stamp("log", out, msg, stream) } return err } @@ -237,7 +235,7 @@ func (p *Project) run(channel chan bool, wr *sync.WaitGroup) { case <-runner: msg = fmt.Sprintln(p.pname(p.Name, 5), ":", style.Green.Regular("Started")+" after", style.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) out = BufferOut{Time: time.Now(), Text: "Started after " + big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3) + " s"} - p.print("log", out, msg, "") + p.stamp("log", out, msg, "") return } } @@ -253,11 +251,11 @@ func (p *Project) build() error { if err != nil { msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Bold("Go Build"), style.Red.Regular(err.Error())) out = BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Build", Stream: stream} - p.print("error", out, msg, stream) + p.stamp("error", out, msg, stream) } else { msg = fmt.Sprintln(p.pname(p.Name, 5), ":", style.Green.Regular("Built")+" after", style.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) out = BufferOut{Time: time.Now(), Text: "Built after " + big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3) + " s"} - p.print("log", out, msg, stream) + p.stamp("log", out, msg, stream) } return err } @@ -275,7 +273,7 @@ func (p *Project) tool(path string, tool tool) error { if stream, err := p.goTools(path, tool.cmd, tool.options...); err != nil { msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Bold(tool.name), style.Red.Regular("there are some errors in"), ":", style.Magenta.Bold(path)) out = BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: tool.name, Stream: stream} - p.print("error", out, msg, stream) + p.stamp("error", out, msg, stream) return err } } @@ -284,29 +282,27 @@ func (p *Project) tool(path string, tool tool) error { } // Cmd calls an wrapper for execute the commands after/before -func (p *Project) cmd(flag string, changed bool) { +func (p *Project) cmd(flag string, global bool) { for _, cmd := range p.Watcher.Scripts { if strings.ToLower(cmd.Type) == flag { - if changed && cmd.Changed || !changed && cmd.Startup { - errors, logs := p.command(cmd) - msg = fmt.Sprintln(p.pname(p.Name, 5), ":", style.Green.Bold("Command"), style.Green.Bold("\"")+cmd.Command+style.Green.Bold("\"")) - out = BufferOut{Time: time.Now(), Text: cmd.Command, Type: flag} - if logs != "" { - p.print("log", out, msg, "") - } - if errors != "" { - p.print("error", out, msg, "") - } - if logs != "" { - msg = fmt.Sprintln(logs) - out = BufferOut{Time: time.Now(), Text: logs, Type: flag} - p.print("log", out, "", msg) - } - if errors != "" { - msg = fmt.Sprintln(style.Red.Regular(errors)) - out = BufferOut{Time: time.Now(), Text: errors, Type: flag} - p.print("error", out, "", msg) - } + err, logs := p.command(cmd) + msg = fmt.Sprintln(p.pname(p.Name, 5), ":", style.Green.Bold("Command"), style.Green.Bold("\"")+cmd.Command+style.Green.Bold("\"")) + out = BufferOut{Time: time.Now(), Text: cmd.Command, Type: flag} + if logs != "" { + p.stamp("log", out, msg, "") + } + if err != "" { + p.stamp("error", out, msg, "") + } + if logs != "" { + msg = fmt.Sprintln(logs) + out = BufferOut{Time: time.Now(), Text: logs, Type: flag} + p.stamp("log", out, "", msg) + } + if err != "" { + msg = fmt.Sprintln(style.Red.Regular(err)) + out = BufferOut{Time: time.Now(), Text: err, Type: flag} + p.stamp("error", out, "", msg) } } } @@ -325,14 +321,13 @@ func (p *Project) ignore(str string) bool { // Routines launches the toolchain run, build, install func (p *Project) routines(wr *sync.WaitGroup, channel chan bool, watcher watcher, file string) { if len(file) > 0 { - p.cmd("before", true) + p.cmd("before", false) path := filepath.Dir(file) p.tool(file, p.tools.Fmt) p.tool(path, p.tools.Vet) p.tool(path, p.tools.Test) p.tool(path, p.tools.Generate) } else { - p.cmd("before", false) p.Fatal(p.watch(watcher)) } install := p.install() @@ -343,7 +338,7 @@ func (p *Project) routines(wr *sync.WaitGroup, channel chan bool, watcher watche } wr.Wait() if len(file) > 0 { - p.cmd("after", true) + p.cmd("after", false) } } @@ -371,7 +366,7 @@ func (p *Project) pname(name string, color int) string { } // Print on files, cli, ws -func (p *Project) print(t string, o BufferOut, msg string, stream string) { +func (p *Project) stamp(t string, o BufferOut, msg string, stream string) { switch t { case "out": p.Buffer.StdOut = append(p.Buffer.StdOut, o)