Merge branch 'dev' into master

This commit is contained in:
Alessio Pracchia 2017-08-31 09:35:04 +02:00 committed by GitHub
commit 6000dbe0f8
14 changed files with 288 additions and 226 deletions

View File

@ -3,6 +3,7 @@ language: go
go: go:
- 1.7 - 1.7
- 1.8 - 1.8
- 1.9
- tip - tip
matrix: matrix:
allow_failures: allow_failures:

View File

@ -7,87 +7,43 @@ import (
"time" "time"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/tockins/interact"
"github.com/tockins/realize/server" "github.com/tockins/realize/server"
"github.com/tockins/realize/settings" "github.com/tockins/realize/settings"
"github.com/tockins/realize/style" "github.com/tockins/realize/style"
"github.com/tockins/realize/watcher" "github.com/tockins/realize/watcher"
"github.com/tockins/interact"
cli "gopkg.in/urfave/cli.v2" cli "gopkg.in/urfave/cli.v2"
) )
const ( const (
appVersion = "1.4.1" version = "1.4.1"
config = "realize.yaml" config = "realize.yaml"
outputs = "outputs.log" directory = ".realize"
errs = "errors.log" outputs = "outputs.log"
logs = "logs.log" errs = "errors.log"
host = "localhost" logs = "logs.log"
port = 3001 host = "localhost"
interval = 200 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 // Cli commands
func main() { 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{ app := &cli.App{
Name: "Realize", Name: "Realize",
Version: appVersion, Version: version,
Authors: []*cli.Author{ Authors: []*cli.Author{
{ {
Name: "Alessio Pracchia", Name: "Alessio Pracchia",
@ -118,29 +74,18 @@ func main() {
&cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."}, &cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."},
}, },
Action: func(p *cli.Context) error { Action: func(p *cli.Context) error {
if p.Bool("legacy") { polling(p, &r.Config.Legacy)
r.Config.Legacy = settings.Legacy{ noconf(p, &r.Settings.Config)
Status: p.Bool("legacy"), if err := insert(p, &r.Blueprint); err != nil {
Interval: interval, 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 { if err := r.Server.Start(p); err != nil {
return err return err
} }
if err := r.Blueprint.Run(p); err != nil { if err := r.Blueprint.Run(p); err != nil {
return err return err
} }
if !p.Bool("no-config") { if r.Config.Create {
if err := r.Record(r); err != nil { if err := r.Record(r); err != nil {
return err return err
} }
@ -167,14 +112,13 @@ func main() {
&cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."}, &cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."},
}, },
Action: func(p *cli.Context) error { Action: func(p *cli.Context) error {
fmt.Fprintln(style.Output, p.String("path"))
if err := r.Blueprint.Add(p); err != nil { if err := r.Blueprint.Add(p); err != nil {
return err return err
} }
if err := r.Record(r); err != nil { if err := r.Record(r); err != nil {
return err 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 return nil
}, },
Before: before, Before: before,
@ -194,7 +138,7 @@ func main() {
Questions: []*interact.Question{ Questions: []*interact.Question{
{ {
Before: func(d interact.Context) error { 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.Skip()
} }
d.SetDef(false, style.Green.Regular("(n)")) d.SetDef(false, style.Green.Regular("(n)"))
@ -214,10 +158,7 @@ func main() {
Create: true, Create: true,
}, },
Resources: settings.Resources{ Resources: settings.Resources{
Config: config, Config: config,
Outputs: outputs,
Logs: logs,
Errors: errs,
}, },
Server: settings.Server{ Server: settings.Server{
Status: false, Status: false,
@ -733,7 +674,7 @@ func main() {
if err != nil { if err != nil {
return d.Err() 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() d.Reload()
return nil return nil
}, },
@ -775,7 +716,7 @@ func main() {
if err != nil { if err != nil {
return d.Err() 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() d.Reload()
return nil return nil
}, },
@ -807,60 +748,6 @@ func main() {
return nil 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 { Before: func(d interact.Context) error {
d.SetDef("", style.Green.Regular("(none)")) d.SetDef("", style.Green.Regular("(none)"))
@ -892,7 +779,7 @@ func main() {
}, },
After: func(d interact.Context) error { After: func(d interact.Context) error {
if val, _ := d.Qns().Get(0).Ans().Bool(); val { if val, _ := d.Qns().Get(0).Ans().Bool(); val {
actErr = r.Settings.Remove(settings.Directory) actErr = r.Settings.Remove(directory)
if actErr != nil { if actErr != nil {
return actErr return actErr
} }
@ -903,7 +790,7 @@ func main() {
if err := r.Record(r); err != nil { if err := r.Record(r); err != nil {
return err 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 return nil
}, },
Before: before, Before: before,
@ -923,7 +810,7 @@ func main() {
if err := r.Record(r); err != nil { if err := r.Record(r); err != nil {
return err 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 return nil
}, },
Before: before, Before: before,
@ -944,10 +831,10 @@ func main() {
Aliases: []string{"c"}, Aliases: []string{"c"},
Description: "Remove realize folder.", Description: "Remove realize folder.",
Action: func(p *cli.Context) error { 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 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 return nil
}, },
Before: before, Before: before,
@ -955,7 +842,87 @@ func main() {
}, },
} }
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
fmt.Fprintln(style.Output, style.Red.Bold(err)) print(style.Red.Bold(err))
os.Exit(1) 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
}

68
realize_test.go Normal file
View File

@ -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")
}
}

View File

@ -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) { func (s *Server) OpenURL(url string) (io.Writer, error) {
if s.Open { if s.Open {
open, err := cmd[runtime.GOOS] open, err := cmd[runtime.GOOS]

View File

@ -19,19 +19,19 @@ func (s Settings) Stream(file string) ([]byte, error) {
// Write a file // Write a file
func (s Settings) Write(name string, data []byte) error { 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) return s.Validate(err)
} }
// Create a new file and return its pointer // Create a new file and return its pointer
func (s Settings) Create(path string, name string) *os.File { func (s Settings) Create(path string, name string) *os.File {
var file string var file string
if _, err := os.Stat(Directory); err == nil { if _, err := os.Stat(directory); err == nil {
file = filepath.Join(path, Directory, name) file = filepath.Join(path, directory, name)
} else { } else {
file = filepath.Join(path, name) 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) s.Validate(err)
return out return out
} }

View File

@ -1,7 +1,6 @@
package settings package settings
import ( import (
"github.com/labstack/gommon/random"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
@ -9,7 +8,7 @@ import (
func TestSettings_Stream(t *testing.T) { func TestSettings_Stream(t *testing.T) {
s := Settings{} s := Settings{}
filename := random.String(4) filename := Rand(4)
if _, err := s.Stream(filename); err == nil { if _, err := s.Stream(filename); err == nil {
t.Fatal("Error expected, none found", filename, err) t.Fatal("Error expected, none found", filename, err)
} }

View File

@ -3,13 +3,14 @@ package settings
import ( import (
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
"os" "os"
"path/filepath"
"time" "time"
) )
// settings const // settings const
const ( const (
Permission = 0775 permission = 0775
Directory = ".realize/" directory = ".realize"
) )
// Settings defines a group of general settings // Settings defines a group of general settings
@ -52,8 +53,9 @@ type Resources struct {
func (s *Settings) Read(out interface{}) error { func (s *Settings) Read(out interface{}) error {
localConfigPath := s.Resources.Config localConfigPath := s.Resources.Config
// backward compatibility // backward compatibility
if _, err := os.Stat(Directory + s.Resources.Config); err == nil { path := filepath.Join(directory, s.Resources.Config)
localConfigPath = Directory + s.Resources.Config if _, err := os.Stat(path); err == nil {
localConfigPath = path
} }
content, err := s.Stream(localConfigPath) content, err := s.Stream(localConfigPath)
if err == nil { if err == nil {
@ -70,12 +72,12 @@ func (s *Settings) Record(out interface{}) error {
if err != nil { if err != nil {
return err return err
} }
if _, err := os.Stat(Directory); os.IsNotExist(err) { if _, err := os.Stat(directory); os.IsNotExist(err) {
if err = os.Mkdir(Directory, Permission); err != nil { if err = os.Mkdir(directory, permission); err != nil {
return s.Write(s.Resources.Config, y) 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 return nil
} }

View File

@ -47,5 +47,5 @@ func TestSettings_Record(t *testing.T) {
if err := s.Record(a); err != nil { if err := s.Record(a); err != nil {
t.Fatal(err) t.Fatal(err)
} }
s.Remove(filepath.Join(Directory, s.Resources.Config)) s.Remove(filepath.Join(directory, s.Resources.Config))
} }

View File

@ -2,11 +2,20 @@ package settings
import ( import (
"log" "log"
"math/rand"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/tockins/realize/style" "github.com/tockins/realize/style"
"time"
)
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
) )
// Wdir return the current working Directory // Wdir return the current working Directory
@ -47,3 +56,21 @@ func (s Settings) Name(name string, path string) string {
func (s Settings) Path(path string) string { func (s Settings) Path(path string) string {
return strings.Replace(filepath.Clean(path), "\\", "/", -1) return strings.Replace(filepath.Clean(path), "\\", "/", -1)
} }
// Rand is used for generate a random string
func Rand(n int) string {
src := rand.NewSource(time.Now().UnixNano())
b := make([]byte, n)
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 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)
}

View File

@ -2,7 +2,6 @@ package settings
import ( import (
"errors" "errors"
"github.com/labstack/gommon/random"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -32,8 +31,8 @@ func TestSettings_Validate(t *testing.T) {
func TestSettings_Name(t *testing.T) { func TestSettings_Name(t *testing.T) {
s := Settings{} s := Settings{}
name := random.String(8) name := Rand(8)
path := random.String(5) path := Rand(5)
dir, err := os.Getwd() dir, err := os.Getwd()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -47,7 +46,7 @@ func TestSettings_Name(t *testing.T) {
func TestSettings_Path(t *testing.T) { func TestSettings_Path(t *testing.T) {
s := Settings{} s := Settings{}
path := random.String(5) path := Rand(5)
expected := strings.Replace(filepath.Clean(path), "\\", "/", -1) expected := strings.Replace(filepath.Clean(path), "\\", "/", -1)
result := s.Path(path) result := s.Path(path)
if result != expected { if result != expected {

View File

@ -15,14 +15,17 @@ func (h *Blueprint) Run(p *cli.Context) error {
err := h.check() err := h.check()
if err == nil { if err == nil {
// loop projects // 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 { for k, element := range h.Projects {
if p.String("name") != "" && h.Projects[k].Name != p.String("name") { if p.String("name") != "" && h.Projects[k].Name != p.String("name") {
continue continue
} }
tools := tools{}
if element.Cmds.Fmt { if element.Cmds.Fmt {
tools.Fmt = tool{ h.Projects[k].tools.Fmt = tool{
status: &h.Projects[k].Cmds.Fmt, status: &h.Projects[k].Cmds.Fmt,
cmd: "gofmt", cmd: "gofmt",
options: []string{"-s", "-w", "-e"}, options: []string{"-s", "-w", "-e"},
@ -30,7 +33,7 @@ func (h *Blueprint) Run(p *cli.Context) error {
} }
} }
if element.Cmds.Generate { if element.Cmds.Generate {
tools.Generate = tool{ h.Projects[k].tools.Generate = tool{
status: &h.Projects[k].Cmds.Generate, status: &h.Projects[k].Cmds.Generate,
cmd: "go", cmd: "go",
options: []string{"generate"}, options: []string{"generate"},
@ -38,7 +41,7 @@ func (h *Blueprint) Run(p *cli.Context) error {
} }
} }
if element.Cmds.Test { if element.Cmds.Test {
tools.Test = tool{ h.Projects[k].tools.Test = tool{
status: &h.Projects[k].Cmds.Test, status: &h.Projects[k].Cmds.Test,
cmd: "go", cmd: "go",
options: []string{"test"}, options: []string{"test"},
@ -46,14 +49,13 @@ func (h *Blueprint) Run(p *cli.Context) error {
} }
} }
if element.Cmds.Vet { if element.Cmds.Vet {
tools.Vet = tool{ h.Projects[k].tools.Vet = tool{
status: &h.Projects[k].Cmds.Vet, status: &h.Projects[k].Cmds.Vet,
cmd: "go", cmd: "go",
options: []string{"vet"}, options: []string{"vet"},
name: "Go Vet", name: "Go Vet",
} }
} }
h.Projects[k].tools = tools
h.Projects[k].parent = h h.Projects[k].parent = h
h.Projects[k].path = h.Projects[k].Path h.Projects[k].path = h.Projects[k].Path
@ -127,7 +129,7 @@ func (h *Blueprint) Remove(p *cli.Context) error {
return nil return nil
} }
} }
return errors.New("no project found") return errors.New("No project found.")
} }
// List of all the projects // List of all the projects
@ -189,5 +191,5 @@ func (h *Blueprint) check() error {
h.Clean() h.Clean()
return nil return nil
} }
return errors.New("There are no projects") return errors.New("There are no projects.")
} }

View File

@ -27,7 +27,7 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
if err != nil { if err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 3), ":", style.Blue.Regular(err.Error())) msg := fmt.Sprintln(p.pname(p.Name, 3), ":", style.Blue.Regular(err.Error()))
out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Run"} out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Run"}
p.print("error", out, msg, "") p.stamp("error", out, msg, "")
} else { } else {
isErrorText = func(t string) bool { isErrorText = func(t string) bool {
return errRegexp.MatchString(t) 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")) msg := fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular("Ended"))
out := BufferOut{Time: time.Now(), Text: "Ended", Type: "Go Run"} out := BufferOut{Time: time.Now(), Text: "Ended", Type: "Go Run"}
p.print("log", out, msg, "") p.stamp("log", out, msg, "")
wr.Done() 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)) msg := fmt.Sprintln(p.pname(p.Name, 3), ":", style.Blue.Regular(text))
if isError && !isErrorText(text) { if isError && !isErrorText(text) {
out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"} out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"}
p.print("error", out, msg, "") p.stamp("error", out, msg, "")
} else { } else {
out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"} out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"}
p.print("out", out, msg, "") p.stamp("out", out, msg, "")
} }
} }
close(stop) close(stop)
@ -153,6 +153,9 @@ func (p *Project) goInstall() (string, error) {
// GoTools is used for run go methods such as fmt, test, generate... // GoTools is used for run go methods such as fmt, test, generate...
func (p *Project) goTools(dir string, name string, cmd ...string) (string, error) { 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 var out, stderr bytes.Buffer
build := exec.Command(name, cmd...) build := exec.Command(name, cmd...)
build.Dir = dir build.Dir = dir

View File

@ -90,8 +90,7 @@ type Command struct {
Type string `yaml:"type" json:"type"` Type string `yaml:"type" json:"type"`
Command string `yaml:"command" json:"command"` Command string `yaml:"command" json:"command"`
Path string `yaml:"path,omitempty" json:"path,omitempty"` Path string `yaml:"path,omitempty" json:"path,omitempty"`
Changed bool `yaml:"changed,omitempty" json:"changed,omitempty"` Global bool `yaml:"global,omitempty" json:"changed,global"`
Startup bool `yaml:"startup,omitempty" json:"startup,omitempty"`
} }
// Streams is a collection of names and values for the logs functionality // Streams is a collection of names and values for the logs functionality

View File

@ -72,7 +72,7 @@ func (p *Project) watchByPolling() {
// repeat the initial cycle // repeat the initial cycle
msg = fmt.Sprintln(p.pname(p.Name, 4), ":", style.Magenta.Bold(strings.ToUpper(ext[1:])+" changed"), style.Magenta.Bold(file)) 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} 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) go p.routines(&wr, channel, watcher, file)
} }
return nil return nil
@ -84,16 +84,15 @@ func (p *Project) watchByPolling() {
if err := filepath.Walk(base, walk); err != nil { if err := filepath.Walk(base, walk); err != nil {
msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular(err.Error())) msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular(err.Error()))
out = BufferOut{Time: time.Now(), Text: err.Error()} out = BufferOut{Time: time.Now(), Text: err.Error()}
p.print("error", out, msg, "") p.stamp("error", out, msg, "")
} }
} else { } else {
msg = fmt.Sprintln(p.pname(p.Name, 2), ":", base, "path doesn't exist") msg = fmt.Sprintln(p.pname(p.Name, 2), ":", base, "path doesn't exist")
out = BufferOut{Time: time.Now(), Text: 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 { select {
case <-exit: case <-exit:
p.cmd("after", false)
return return
case <-time.After(p.parent.Legacy.Interval / time.Duration(len(p.Watcher.Paths))): 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 // repeat the initial cycle
msg = fmt.Sprintln(p.pname(p.Name, 4), ":", style.Magenta.Bold(strings.ToUpper(ext[1:])+" changed"), style.Magenta.Bold(file)) 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} 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) go p.routines(&wr, channel, watcher, file)
p.LastChangedOn = time.Now().Truncate(time.Second) p.LastChangedOn = time.Now().Truncate(time.Second)
} }
@ -147,9 +146,8 @@ func (p *Project) watchByNotify() {
case err := <-watcher.Errors: case err := <-watcher.Errors:
msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular(err.Error())) msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Regular(err.Error()))
out = BufferOut{Time: time.Now(), Text: err.Error()} out = BufferOut{Time: time.Now(), Text: err.Error()}
p.print("error", out, msg, "") p.stamp("error", out, msg, "")
case <-exit: case <-exit:
p.cmd("after", false)
return return
} }
} }
@ -161,7 +159,7 @@ func (p *Project) watch(watcher watcher) error {
wd, _ := os.Getwd() wd, _ := os.Getwd()
walk := func(path string, info os.FileInfo, err error) error { walk := func(path string, info os.FileInfo, err error) error {
if !p.ignore(path) { 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 { if p.Watcher.Preview {
log.Println(p.pname(p.Name, 1), ":", path) 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") 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"} 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 return nil
} }
@ -214,11 +212,11 @@ func (p *Project) install() error {
if err != nil { if err != nil {
msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Bold("Go Install"), style.Red.Regular(err.Error())) 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} 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 { } 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")) 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"} 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 return err
} }
@ -237,7 +235,7 @@ func (p *Project) run(channel chan bool, wr *sync.WaitGroup) {
case <-runner: 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")) 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"} 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 return
} }
} }
@ -253,11 +251,11 @@ func (p *Project) build() error {
if err != nil { if err != nil {
msg = fmt.Sprintln(p.pname(p.Name, 2), ":", style.Red.Bold("Go Build"), style.Red.Regular(err.Error())) 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} 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 { } 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")) 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"} 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 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 { 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)) 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} 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 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 // 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 { for _, cmd := range p.Watcher.Scripts {
if strings.ToLower(cmd.Type) == flag { if strings.ToLower(cmd.Type) == flag {
if changed && cmd.Changed || !changed && cmd.Startup { err, logs := p.command(cmd)
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("\""))
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}
out = BufferOut{Time: time.Now(), Text: cmd.Command, Type: flag} if logs != "" {
if logs != "" { p.stamp("log", out, msg, "")
p.print("log", out, msg, "") }
} if err != "" {
if errors != "" { p.stamp("error", out, msg, "")
p.print("error", out, msg, "") }
} if logs != "" {
if logs != "" { msg = fmt.Sprintln(logs)
msg = fmt.Sprintln(logs) out = BufferOut{Time: time.Now(), Text: logs, Type: flag}
out = BufferOut{Time: time.Now(), Text: logs, Type: flag} p.stamp("log", out, "", msg)
p.print("log", out, "", msg) }
} if err != "" {
if errors != "" { msg = fmt.Sprintln(style.Red.Regular(err))
msg = fmt.Sprintln(style.Red.Regular(errors)) out = BufferOut{Time: time.Now(), Text: err, Type: flag}
out = BufferOut{Time: time.Now(), Text: errors, Type: flag} p.stamp("error", out, "", msg)
p.print("error", out, "", msg)
}
} }
} }
} }
@ -325,14 +321,13 @@ func (p *Project) ignore(str string) bool {
// Routines launches the toolchain run, build, install // Routines launches the toolchain run, build, install
func (p *Project) routines(wr *sync.WaitGroup, channel chan bool, watcher watcher, file string) { func (p *Project) routines(wr *sync.WaitGroup, channel chan bool, watcher watcher, file string) {
if len(file) > 0 { if len(file) > 0 {
p.cmd("before", true) p.cmd("before", false)
path := filepath.Dir(file) path := filepath.Dir(file)
p.tool(file, p.tools.Fmt) p.tool(file, p.tools.Fmt)
p.tool(path, p.tools.Vet) p.tool(path, p.tools.Vet)
p.tool(path, p.tools.Test) p.tool(path, p.tools.Test)
p.tool(path, p.tools.Generate) p.tool(path, p.tools.Generate)
} else { } else {
p.cmd("before", false)
p.Fatal(p.watch(watcher)) p.Fatal(p.watch(watcher))
} }
install := p.install() install := p.install()
@ -343,7 +338,7 @@ func (p *Project) routines(wr *sync.WaitGroup, channel chan bool, watcher watche
} }
wr.Wait() wr.Wait()
if len(file) > 0 { 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 // 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 { switch t {
case "out": case "out":
p.Buffer.StdOut = append(p.Buffer.StdOut, o) p.Buffer.StdOut = append(p.Buffer.StdOut, o)