diff --git a/cli.go b/cli.go deleted file mode 100644 index 31a12f8..0000000 --- a/cli.go +++ /dev/null @@ -1,1138 +0,0 @@ -package main - -import ( - "github.com/fatih/color" - "github.com/tockins/interact" - "gopkg.in/urfave/cli.v2" - "log" - "os" - "path/filepath" - "strconv" - "strings" - "time" -) - -// Version print current version -func (r *Realize) version() { - log.Println(r.Prefix(green.bold(RVersion))) -} - -// Clean remove realize folder -func (r *Realize) clean() (err error) { - if err := r.Settings.Remove(RDir); err != nil { - return err - } - log.Println(r.Prefix(green.bold("folder successfully removed"))) - return nil -} - -// Add a project to an existing config or create a new one -func (r *Realize) add(c *cli.Context) (err error) { - // read a config if exist - err = r.Settings.Read(&r) - if err != nil { - return err - } - projects := len(r.Schema.Projects) - // create and add a new project - r.Schema.Add(r.Schema.New(c)) - if len(r.Schema.Projects) > projects { - // update config - err = r.Settings.Write(r) - if err != nil { - return err - } - log.Println(r.Prefix(green.bold("project successfully added"))) - } else { - log.Println(r.Prefix(green.bold("project can't be added"))) - } - return nil -} - -// Setup a new config step by step -func (r *Realize) setup(c *cli.Context) (err error) { - interact.Run(&interact.Interact{ - Before: func(context interact.Context) error { - context.SetErr(red.bold("INVALID INPUT")) - context.SetPrfx(color.Output, yellow.regular("[")+time.Now().Format("15:04:05")+yellow.regular("]")+yellow.bold("[")+strings.ToUpper(RPrefix)+yellow.bold("]")) - return nil - }, - Questions: []*interact.Question{ - { - Before: func(d interact.Context) error { - if _, err := os.Stat(RDir + "/" + RFile); err != nil { - d.Skip() - } - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Would you want to overwrite existing " + magenta.bold(RPrefix) + " config?", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } else if val { - r := Realize{} - r.Server = Server{&r, false, false, Port, Host} - } - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Would you want to customize settings?", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef(0, green.regular("(os default)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[int]"), - Msg: "Set max number of open files (root required)", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Int() - if err != nil { - return d.Err() - } - r.Settings.FileLimit = int32(val) - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Force polling watcher?", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef(100, green.regular("(100ms)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[int]"), - Msg: "Set polling interval", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Int() - if err != nil { - return d.Err() - } - r.Settings.Legacy.Interval = time.Duration(int(val)) * time.Millisecond - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Settings.Legacy.Force = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable logging files", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Settings.Files.Errors = Resource{Name: FileErr, Status: val} - r.Settings.Files.Outputs = Resource{Name: FileOut, Status: val} - r.Settings.Files.Logs = Resource{Name: FileLog, Status: val} - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable web server", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef(Port, green.regular("("+strconv.Itoa(Port)+")")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[int]"), - Msg: "Server port", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Int() - if err != nil { - return d.Err() - } - r.Server.Port = int(val) - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(Host, green.regular("("+Host+")")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Server host", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Server.Host = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Open in current browser", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Server.Open = val - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Server.Status = val - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - _, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(true, green.regular("(y)")) - d.SetEnd("!") - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Would you want to " + magenta.regular("add a new project") + "? (insert '!' to stop)", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - if val { - r.Schema.Add(r.Schema.New(c)) - } - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef(wdir(), green.regular("("+wdir()+")")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Project name", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Name = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - dir := wdir() - d.SetDef(dir, green.regular("("+dir+")")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Project path", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Path = filepath.Clean(val) - return nil - }, - }, - - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go vet", - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Vet additional arguments", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - if val != "" { - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Vet.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Vet.Args, val) - } - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Vet.Status = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go fmt", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Fmt additional arguments", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - if val != "" { - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fmt.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fmt.Args, val) - } - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fmt.Status = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go test", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Test additional arguments", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - if val != "" { - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Test.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Test.Args, val) - } - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Test.Status = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go fix", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Fix additional arguments", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - if val != "" { - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fix.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fix.Args, val) - } - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fix.Status = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go clean", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Clean additional arguments", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - if val != "" { - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Clean.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Clean.Args, val) - } - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Clean.Status = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go generate", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Generate additional arguments", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - if val != "" { - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Generate.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Generate.Args, val) - } - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Generate.Status = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(true, green.regular("(y)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go install", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Install additional arguments", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - if val != "" { - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Install.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Install.Args, val) - } - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Install.Status = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go build", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Build additional arguments", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - if val != "" { - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Build.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Build.Args, val) - } - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Build.Status = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(true, green.regular("(y)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Enable go run", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Run = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Customize watching paths", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - if val { - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths = r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths[:len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths)-1] - } - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetEnd("!") - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Insert a path to watch (insert '!' to stop)", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths = append(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths, val) - d.Reload() - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - _, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Customize ignore paths", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - if val { - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore = r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore[:len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore)-1] - } - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetEnd("!") - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Insert a path to ignore (insert '!' to stop)", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore = append(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore, val) - d.Reload() - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - _, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Add an additional argument", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - d.SetEnd("!") - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Add another argument (insert '!' to stop)", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Args, val) - d.Reload() - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - _, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(none)")) - d.SetEnd("!") - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Add a 'before' custom command (insert '!' to stop)", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Insert a command", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts = append(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts, Command{Type: "before", Cmd: val}) - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Launch from a specific path", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Path = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Tag as global command", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Global = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Display command output", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Output = val - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - if val { - d.Reload() - } - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(none)")) - d.SetEnd("!") - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Add an 'after' custom commands (insert '!' to stop)", - Resolve: func(d interact.Context) bool { - val, _ := d.Ans().Bool() - return val - }, - }, - Subs: []*interact.Question{ - { - Before: func(d interact.Context) error { - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Insert a command", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts = append(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts, Command{Type: "after", Cmd: val}) - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Launch from a specific path", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Path = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Tag as global command", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Global = val - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef(false, green.regular("(n)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[y/n]"), - Msg: "Display command output", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Output = val - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().Bool() - if err != nil { - return d.Err() - } - if val { - d.Reload() - } - return nil - }, - }, - { - Before: func(d interact.Context) error { - d.SetDef("", green.regular("(none)")) - return nil - }, - Quest: interact.Quest{ - Options: yellow.regular("[string]"), - Msg: "Set an error output pattern", - }, - Action: func(d interact.Context) interface{} { - val, err := d.Ans().String() - if err != nil { - return d.Err() - } - r.Schema.Projects[len(r.Schema.Projects)-1].ErrorOutputPattern = val - return nil - }, - }, - }, - Action: func(d interact.Context) interface{} { - if val, err := d.Ans().Bool(); err != nil { - return d.Err() - } else if val { - d.Reload() - } - return nil - }, - }, - }, - After: func(d interact.Context) error { - if val, _ := d.Qns().Get(0).Ans().Bool(); val { - err := r.Settings.Remove(RDir) - if err != nil { - return err - } - } - return nil - }, - }) - // create config - err = r.Settings.Write(r) - if err != nil { - return err - } - log.Println(r.Prefix(green.bold("Config successfully created"))) - return nil -} - -// Start realize workflow -func (r *Realize) start(c *cli.Context) (err error) { - r.Server = Server{r, false, false, Port, Host} - // check no-config and read - if !c.Bool("no-config") { - // read a config if exist - err = r.Settings.Read(&r) - if err != nil { - return err - } - if c.String("name") != "" { - // filter by name flag if exist - r.Schema.Filter("name", c.String("name")) - } - // increase file limit - if r.Settings.FileLimit != 0 { - if err = r.Settings.Flimit(); err != nil { - return err - } - } - - } - // check project list length - if len(r.Schema.Projects) <= 0 { - // create a new project based on given params - project := r.Schema.New(c) - // Add to projects list - r.Schema.Add(project) - // save config - if !c.Bool("no-config") { - err = r.Settings.Write(r) - if err != nil { - return err - } - } - } - // config and start server - if c.Bool("server") || r.Server.Status { - r.Server.Status = true - if c.Bool("open") || r.Server.Open { - r.Server.Open = true - r.Server.OpenURL() - } - err = r.Server.Start() - if err != nil { - return err - } - } - // start workflow - r.Start() - return -} - -// Remove a project from an existing config -func (r *Realize) remove(c *cli.Context) (err error) { - // read a config if exist - err = r.Settings.Read(&r) - if err != nil { - return err - } - if c.String("name") != "" { - err := r.Schema.Remove(c.String("name")) - if err != nil { - return err - } - // update config - err = r.Settings.Write(r) - if err != nil { - return err - } - log.Println(r.Prefix(green.bold("project successfully removed"))) - } else { - log.Println(r.Prefix(green.bold("project name not found"))) - } - return nil -} diff --git a/cli_test.go b/cli_test.go deleted file mode 100644 index f29d466..0000000 --- a/cli_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package main - -import ( - "bytes" - "log" - "strings" - "testing" - "errors" -) - -func (m *mockRealize) add() error{ - if mockResponse != nil { - return mockResponse.(error) - } - m.Projects = append(m.Projects, Project{Name:"One"}) - return nil -} - -func (m *mockRealize) setup() error{ - if mockResponse != nil { - return mockResponse.(error) - } - return nil -} - -func (m *mockRealize) start() error{ - if mockResponse != nil { - return mockResponse.(error) - } - return nil -} - -func (m *mockRealize) clean() error{ - if mockResponse != nil { - return mockResponse.(error) - } - return nil -} - -func (m *mockRealize) remove() error{ - if mockResponse != nil { - return mockResponse.(error) - } - m.Projects = []Project{} - return nil -} - -func TestAdd(t *testing.T) { - m := mockRealize{} - mockResponse = nil - if err := m.add(); err != nil{ - t.Fatal("Unexpected error") - } - if len(m.Projects) <= 0{ - t.Fatal("Unexpected error") - } - - m = mockRealize{} - m.Projects = []Project{{Name:"Default"}} - mockResponse = nil - if err := m.add(); err != nil{ - t.Fatal("Unexpected error") - } - if len(m.Projects) != 2{ - t.Fatal("Unexpected error") - } - - m = mockRealize{} - mockResponse = errors.New("error") - if err := m.clean(); err == nil{ - t.Fatal("Expected error") - } - if len(m.Projects) != 0{ - t.Fatal("Unexpected error") - } -} - -func TestStart(t *testing.T) { - m := mockRealize{} - mockResponse = nil - if err := m.add(); err != nil{ - t.Fatal("Unexpected error") - } -} - -func TestSetup(t *testing.T) { - m := mockRealize{} - mockResponse = nil - if err := m.setup(); err != nil{ - t.Fatal("Unexpected error") - } -} - -func TestClean(t *testing.T) { - m := mockRealize{} - mockResponse = nil - if err := m.clean(); err != nil{ - t.Fatal("Unexpected error") - } - mockResponse = errors.New("error") - if err := m.clean(); err == nil{ - t.Fatal("Expected error") - } -} - -func TestRemove(t *testing.T) { - m := mockRealize{} - mockResponse = nil - if err := m.remove(); err != nil{ - t.Fatal("Unexpected error") - } - - m = mockRealize{} - mockResponse = nil - m.Projects = []Project{{Name:"Default"},{Name:"Default"}} - if err := m.remove(); err != nil{ - t.Fatal("Unexpected error") - } - if len(m.Projects) != 0{ - t.Fatal("Unexpected error") - } - - mockResponse = errors.New("error") - if err := m.clean(); err == nil{ - t.Fatal("Expected error") - } -} - -func TestVersion(t *testing.T) { - var buf bytes.Buffer - log.SetOutput(&buf) - r.version() - if !strings.Contains(buf.String(), RVersion) { - t.Fatal("Version expted", RVersion) - } -} diff --git a/realize.go b/realize.go index 98caf72..b703e7f 100644 --- a/realize.go +++ b/realize.go @@ -1,64 +1,30 @@ package main import ( - "fmt" - "go/build" - "gopkg.in/urfave/cli.v2" "log" "os" - "os/signal" - "path/filepath" "strings" - "syscall" + "gopkg.in/urfave/cli.v2" + "github.com/tockins/interact" "time" + "strconv" + "path/filepath" + rc "github.com/tockins/realize/realize" ) -const ( - RPrefix = "realize" - RVersion = "2.0" - RExt = ".yaml" - RFile = RPrefix + RExt - RDir = "." + RPrefix - RExtWin = ".exe" -) - -type ( - Realize struct { - Settings Settings `yaml:"settings" json:"settings"` - Server Server `yaml:"server" json:"server"` - Schema `yaml:",inline"` - sync chan string - exit chan os.Signal - } - LogWriter struct{} -) - -var r Realize - -// init check -func init() { - // custom log - log.SetFlags(0) - log.SetOutput(LogWriter{}) - if build.Default.GOPATH == "" { - log.Fatal("$GOPATH isn't set properly") - } - if err := os.Setenv("GOBIN", filepath.Join(build.Default.GOPATH, "bin")); err != nil { - log.Fatal(err) - } -} +var r rc.Realize // Realize cli commands func main() { app := &cli.App{ - Name: strings.Title(RPrefix), - Version: RVersion, + Name: strings.Title(rc.RPrefix), + Version: rc.RVersion, Description: "Realize is the #1 Golang Task Runner which enhance your workflow by automating the most common tasks and using the best performing Golang live reloading.", Commands: []*cli.Command{ { Name: "start", Aliases: []string{"s"}, - Description: "Start " + strings.Title(RPrefix) + " on a given path. If not exist a config file it creates a new one.", + Description: "Start " + strings.Title(rc.RPrefix) + " on a given path. If not exist a config file it creates a new one.", Flags: []cli.Flag{ &cli.StringFlag{Name: "path", Aliases: []string{"p"}, Value: ".", Usage: "Project base path"}, &cli.StringFlag{Name: "name", Aliases: []string{"n"}, Value: "", Usage: "Run a project by its name"}, @@ -73,7 +39,7 @@ func main() { &cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing config and doesn't create a new one"}, }, Action: func(c *cli.Context) error { - return r.start(c) + return start(c) }, }, { @@ -82,7 +48,7 @@ func main() { Aliases: []string{"a"}, Description: "Add a project to an existing config or to a new one.", Flags: []cli.Flag{ - &cli.StringFlag{Name: "path", Aliases: []string{"p"}, Value: wdir(), Usage: "Project base path"}, + &cli.StringFlag{Name: "path", Aliases: []string{"p"}, Value: rc.Wdir(), Usage: "Project base path"}, &cli.BoolFlag{Name: "fmt", Aliases: []string{"f"}, Value: false, Usage: "Enable go fmt"}, &cli.BoolFlag{Name: "vet", Aliases: []string{"v"}, Value: false, Usage: "Enable go vet"}, &cli.BoolFlag{Name: "test", Aliases: []string{"t"}, Value: false, Usage: "Enable go test"}, @@ -92,7 +58,7 @@ func main() { &cli.BoolFlag{Name: "run", Aliases: []string{"nr"}, Value: false, Usage: "Enable go run"}, }, Action: func(c *cli.Context) error { - return r.add(c) + return add(c) }, }, { @@ -101,7 +67,7 @@ func main() { Aliases: []string{"i"}, Description: "Make a new config file step by step.", Action: func(c *cli.Context) error { - return r.setup(c) + return setup(c) }, }, { @@ -113,24 +79,24 @@ func main() { &cli.StringFlag{Name: "name", Aliases: []string{"n"}, Value: ""}, }, Action: func(c *cli.Context) error { - return r.remove(c) + return remove(c) }, }, { Name: "clean", Category: "Configuration", Aliases: []string{"c"}, - Description: "Remove " + strings.Title(RPrefix) + " folder.", + Description: "Remove " + strings.Title(rc.RPrefix) + " folder.", Action: func(c *cli.Context) error { - return r.clean() + return clean() }, }, { Name: "version", Aliases: []string{"v"}, - Description: "Print " + strings.Title(RPrefix) + " version.", + Description: "Print " + strings.Title(rc.RPrefix) + " version.", Action: func(p *cli.Context) error { - r.version() + version() return nil }, }, @@ -142,37 +108,1128 @@ func main() { } } -// Stop realize workflow -func (r *Realize) Stop() { - close(r.exit) +// Version print current version +func version() { + log.Println(r.Prefix(rc.Green.Bold(rc.RVersion))) } -// Run realize workflow -func (r *Realize) Start() { - r.exit = make(chan os.Signal, 2) - signal.Notify(r.exit, os.Interrupt, syscall.SIGTERM) - for k := range r.Schema.Projects { - r.Schema.Projects[k].parent = r - r.Schema.Projects[k].Setup() - go r.Schema.Projects[k].Watch(r.exit) +// Clean remove realize folder +func clean() (err error) { + if err := r.Settings.Remove(rc.RDir); err != nil { + return err } - for { - select { - case <-r.exit: - return + log.Println(r.Prefix(rc.Green.Bold("folder successfully removed"))) + return nil +} + +// Add a project to an existing config or create a new one +func add(c *cli.Context) (err error) { + // read a config if exist + err = r.Settings.Read(&r) + if err != nil { + return err + } + projects := len(r.Schema.Projects) + // create and add a new project + r.Schema.Add(r.Schema.New(c)) + if len(r.Schema.Projects) > projects { + // update config + err = r.Settings.Write(r) + if err != nil { + return err + } + log.Println(r.Prefix(rc.Green.Bold("project successfully added"))) + } else { + log.Println(r.Prefix(rc.Green.Bold("project can't be added"))) + } + return nil +} + +// Setup a new config step by step +func setup(c *cli.Context) (err error) { + interact.Run(&interact.Interact{ + Before: func(context interact.Context) error { + context.SetErr(rc.Red.Bold("INVALID INPUT")) + context.SetPrfx(rc.Output, rc.Yellow.Regular("[")+time.Now().Format("15:04:05")+rc.Yellow.Regular("]")+rc.Yellow.Bold("[")+strings.ToUpper(rc.RPrefix)+rc.Yellow.Bold("]")) + return nil + }, + Questions: []*interact.Question{ + { + Before: func(d interact.Context) error { + if _, err := os.Stat(rc.RDir + "/" + rc.RFile); err != nil { + d.Skip() + } + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Would you want to overwrite existing " + rc.Magenta.Regular(rc.RPrefix) + " config?", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } else if val { + r := rc.Realize{} + r.Server = rc.Server{Parent:&r, Status:false, Open:false, Port:rc.Port,Host: rc.Host} + } + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Would you want to customize settings?", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef(0, rc.Green.Regular("(os default)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[int]"), + Msg: "Set max number of open files (root required)", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Int() + if err != nil { + return d.Err() + } + r.Settings.FileLimit = int32(val) + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Force polling watcher?", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef(100, rc.Green.Regular("(100ms)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[int]"), + Msg: "Set polling interval", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Int() + if err != nil { + return d.Err() + } + r.Settings.Legacy.Interval = time.Duration(int(val)) * time.Millisecond + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Settings.Legacy.Force = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable logging files", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Settings.Files.Errors = rc.Resource{Name: rc.FileErr, Status: val} + r.Settings.Files.Outputs = rc.Resource{Name: rc.FileOut, Status: val} + r.Settings.Files.Logs = rc.Resource{Name: rc.FileLog, Status: val} + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable web server", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef(rc.Port, rc.Green.Regular("("+strconv.Itoa(rc.Port)+")")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[int]"), + Msg: "Server port", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Int() + if err != nil { + return d.Err() + } + r.Server.Port = int(val) + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(rc.Host, rc.Green.Regular("("+rc.Host+")")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Server host", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Server.Host = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Open in current browser", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Server.Open = val + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Server.Status = val + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + _, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(true, rc.Green.Regular("(y)")) + d.SetEnd("!") + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Would you want to " + rc.Magenta.Regular("add a new project") + "? (insert '!' to stop)", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + if val { + r.Schema.Add(r.Schema.New(c)) + } + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef(rc.Wdir(), rc.Green.Regular("("+rc.Wdir()+")")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Project name", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Name = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + dir := rc.Wdir() + d.SetDef(dir, rc.Green.Regular("("+dir+")")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Project path", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Path = filepath.Clean(val) + return nil + }, + }, + + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go vet", + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Vet additional arguments", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + if val != "" { + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Vet.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Vet.Args, val) + } + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Vet.Status = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go fmt", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Fmt additional arguments", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + if val != "" { + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fmt.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fmt.Args, val) + } + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fmt.Status = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go test", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Test additional arguments", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + if val != "" { + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Test.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Test.Args, val) + } + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Test.Status = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go fix", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Fix additional arguments", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + if val != "" { + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fix.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fix.Args, val) + } + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Fix.Status = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go clean", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Clean additional arguments", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + if val != "" { + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Clean.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Clean.Args, val) + } + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Clean.Status = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go generate", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Generate additional arguments", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + if val != "" { + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Generate.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Generate.Args, val) + } + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Generate.Status = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(true, rc.Green.Regular("(y)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go install", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Install additional arguments", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + if val != "" { + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Install.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Install.Args, val) + } + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Install.Status = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go build", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Build additional arguments", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + if val != "" { + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Build.Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Build.Args, val) + } + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Build.Status = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(true, rc.Green.Regular("(y)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Enable go run", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Tools.Run = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Customize watching paths", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + if val { + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths = r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths[:len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths)-1] + } + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetEnd("!") + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Insert a path to watch (insert '!' to stop)", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths = append(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Paths, val) + d.Reload() + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + _, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Customize ignore paths", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + if val { + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore = r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore[:len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore)-1] + } + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetEnd("!") + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Insert a path to ignore (insert '!' to stop)", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore = append(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Ignore, val) + d.Reload() + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + _, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Add an additional argument", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + d.SetEnd("!") + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Add another argument (insert '!' to stop)", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Args = append(r.Schema.Projects[len(r.Schema.Projects)-1].Args, val) + d.Reload() + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + _, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(none)")) + d.SetEnd("!") + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Add a 'before' custom command (insert '!' to stop)", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Insert a command", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts = append(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts, rc.Command{Type: "before", Cmd: val}) + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Launch from a specific path", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Path = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Tag as global command", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Global = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Display command output", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Output = val + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + if val { + d.Reload() + } + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(none)")) + d.SetEnd("!") + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Add an 'after' custom commands (insert '!' to stop)", + Resolve: func(d interact.Context) bool { + val, _ := d.Ans().Bool() + return val + }, + }, + Subs: []*interact.Question{ + { + Before: func(d interact.Context) error { + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Insert a command", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts = append(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts, rc.Command{Type: "after", Cmd: val}) + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Launch from a specific path", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Path = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Tag as global command", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Global = val + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef(false, rc.Green.Regular("(n)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[y/n]"), + Msg: "Display command output", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts[len(r.Schema.Projects[len(r.Schema.Projects)-1].Watcher.Scripts)-1].Output = val + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().Bool() + if err != nil { + return d.Err() + } + if val { + d.Reload() + } + return nil + }, + }, + { + Before: func(d interact.Context) error { + d.SetDef("", rc.Green.Regular("(none)")) + return nil + }, + Quest: interact.Quest{ + Options: rc.Yellow.Regular("[string]"), + Msg: "Set an error output pattern", + }, + Action: func(d interact.Context) interface{} { + val, err := d.Ans().String() + if err != nil { + return d.Err() + } + r.Schema.Projects[len(r.Schema.Projects)-1].ErrorOutputPattern = val + return nil + }, + }, + }, + Action: func(d interact.Context) interface{} { + if val, err := d.Ans().Bool(); err != nil { + return d.Err() + } else if val { + d.Reload() + } + return nil + }, + }, + }, + After: func(d interact.Context) error { + if val, _ := d.Qns().Get(0).Ans().Bool(); val { + err := r.Settings.Remove(rc.RDir) + if err != nil { + return err + } + } + return nil + }, + }) + // create config + err = r.Settings.Write(r) + if err != nil { + return err + } + log.Println(r.Prefix(rc.Green.Bold("Config successfully created"))) + return nil +} + +// Start realize workflow +func start(c *cli.Context) (err error) { + r.Server = rc.Server{Parent:&r,Status:false,Open:false,Port: rc.Port,Host:rc.Host} + // check no-config and read + if !c.Bool("no-config") { + // read a config if exist + err = r.Settings.Read(&r) + if err != nil { + return err + } + if c.String("name") != "" { + // filter by name flag if exist + r.Schema.Filter("name", c.String("name")) + } + // increase file limit + if r.Settings.FileLimit != 0 { + if err = r.Settings.Flimit(); err != nil { + return err + } + } + + } + // check project list length + if len(r.Schema.Projects) <= 0 { + // create a new project based on given params + project := r.Schema.New(c) + // Add to projects list + r.Schema.Add(project) + // save config + if !c.Bool("no-config") { + err = r.Settings.Write(r) + if err != nil { + return err + } } } -} - -// Prefix a given string with tool name -func (r *Realize) Prefix(input string) string { - if len(input) > 0 { - return fmt.Sprint(yellow.bold("["), strings.ToUpper(RPrefix), yellow.bold("]"), " : ", input) + // config and start server + if c.Bool("server") || r.Server.Status { + r.Server.Status = true + if c.Bool("open") || r.Server.Open { + r.Server.Open = true + r.Server.OpenURL() + } + err = r.Server.Start() + if err != nil { + return err + } } - return input + // start workflow + r.Start() + return } -// Rewrite the layout of the log timestamp -func (w LogWriter) Write(bytes []byte) (int, error) { - return fmt.Fprint(output, yellow.regular("["), time.Now().Format("15:04:05"), yellow.regular("]"), string(bytes)) +// Remove a project from an existing config +func remove(c *cli.Context) (err error) { + // read a config if exist + err = r.Settings.Read(&r) + if err != nil { + return err + } + if c.String("name") != "" { + err := r.Schema.Remove(c.String("name")) + if err != nil { + return err + } + // update config + err = r.Settings.Write(r) + if err != nil { + return err + } + log.Println(r.Prefix(rc.Green.Bold("project successfully removed"))) + } else { + log.Println(r.Prefix(rc.Green.Bold("project name not found"))) + } + return nil } + diff --git a/bindata.go b/realize/bindata.go similarity index 99% rename from bindata.go rename to realize/bindata.go index d430eb0..1fec5b4 100644 --- a/bindata.go +++ b/realize/bindata.go @@ -18,7 +18,7 @@ // assets/index.html // DO NOT EDIT! -package main +package realize import ( "bytes" diff --git a/realize/cli.go b/realize/cli.go new file mode 100644 index 0000000..5bc4c9d --- /dev/null +++ b/realize/cli.go @@ -0,0 +1,81 @@ +package realize + +import ( + "log" + "os" + "path/filepath" + "strings" + "time" + "os/signal" + "syscall" + "fmt" + "go/build" +) + +const ( + RPrefix = "realize" + RVersion = "2.0" + RExt = ".yaml" + RFile = RPrefix + RExt + RDir = "." + RPrefix + RExtWin = ".exe" +) + +type ( + Realize struct { + Settings Settings `yaml:"settings" json:"settings"` + Server Server `yaml:"server" json:"server"` + Schema `yaml:",inline"` + sync chan string + exit chan os.Signal + } + LogWriter struct{} +) + +// init check +func init() { + // custom log + log.SetFlags(0) + log.SetOutput(LogWriter{}) + if build.Default.GOPATH == "" { + log.Fatal("$GOPATH isn't set properly") + } + if err := os.Setenv("GOBIN", filepath.Join(build.Default.GOPATH, "bin")); err != nil { + log.Fatal(err) + } +} + +// Stop realize workflow +func (r *Realize) Stop() { + close(r.exit) +} + +// Run realize workflow +func (r *Realize) Start() { + r.exit = make(chan os.Signal, 2) + signal.Notify(r.exit, os.Interrupt, syscall.SIGTERM) + for k := range r.Schema.Projects { + r.Schema.Projects[k].parent = r + r.Schema.Projects[k].Setup() + go r.Schema.Projects[k].Watch(r.exit) + } + for { + select { + case <-r.exit: + return + } + } +} + +// Prefix a given string with tool name +func (r *Realize) Prefix(input string) string { + if len(input) > 0 { + return fmt.Sprint(Yellow.Bold("["), strings.ToUpper(RPrefix), Yellow.Bold("]"), " : ", input) + } + return input +} + +// Rewrite the layout of the log timestamp +func (w LogWriter) Write(bytes []byte) (int, error) { + return fmt.Fprint(Output, Yellow.Regular("["), time.Now().Format("15:04:05"), Yellow.Regular("]"), string(bytes)) +} diff --git a/realize/cli_test.go b/realize/cli_test.go new file mode 100644 index 0000000..3f6c8cd --- /dev/null +++ b/realize/cli_test.go @@ -0,0 +1,24 @@ +package realize + +import ( + "testing" + "os" +) + +type mockRealize struct { + Settings Settings `yaml:"settings" json:"settings"` + Server Server `yaml:"server" json:"server"` + Schema `yaml:",inline"` + sync chan string + exit chan os.Signal +} + +func TestRealize_Stop(t *testing.T) { + m := mockRealize{} + m.exit = make(chan os.Signal, 2) + close(m.exit) + _, ok := <-m.exit + if !ok { + t.Error("Unexpected error", "channel should be closed") + } +} diff --git a/commands.go b/realize/commands.go similarity index 98% rename from commands.go rename to realize/commands.go index 3d66c90..5b76dcb 100644 --- a/commands.go +++ b/realize/commands.go @@ -1,4 +1,4 @@ -package main +package realize import ( "bytes" diff --git a/realize/commands_test.go b/realize/commands_test.go new file mode 100644 index 0000000..4b7b005 --- /dev/null +++ b/realize/commands_test.go @@ -0,0 +1 @@ +package realize diff --git a/notify.go b/realize/notify.go similarity index 99% rename from notify.go rename to realize/notify.go index 47cb785..5069cb3 100644 --- a/notify.go +++ b/realize/notify.go @@ -1,4 +1,4 @@ -package main +package realize // this code is imported from moby, unfortunately i can't import it directly as dependencies from its repo, // cause there was a problem between moby vendor and fsnotify diff --git a/notify_test.go b/realize/notify_test.go similarity index 99% rename from notify_test.go rename to realize/notify_test.go index 3767a94..3bc8bb8 100644 --- a/notify_test.go +++ b/realize/notify_test.go @@ -1,4 +1,4 @@ -package main +package realize import ( "fmt" diff --git a/projects.go b/realize/projects.go similarity index 85% rename from projects.go rename to realize/projects.go index dbee885..58d6a41 100644 --- a/projects.go +++ b/realize/projects.go @@ -1,4 +1,4 @@ -package main +package realize import ( "bufio" @@ -75,6 +75,10 @@ type BufferOut struct { Errors []string `json:"errors"` } +type Reload interface{ + Restart(FileWatcher,string,<-chan bool) +} + // Setup a project func (p *Project) Setup() { // get base path @@ -113,11 +117,11 @@ func (p *Project) Watch(exit chan os.Signal) { } } // start message - msg = fmt.Sprintln(p.pname(p.Name, 1), ":", blue.bold("Watching"), magenta.bold(p.files), "file/s", magenta.bold(p.folders), "folder/s") + msg = fmt.Sprintln(p.pname(p.Name, 1), ":", Blue.Bold("Watching"), Magenta.Bold(p.files), "file/s", Magenta.Bold(p.folders), "folder/s") out = BufferOut{Time: time.Now(), Text: "Watching " + strconv.FormatInt(p.files, 10) + " files/s " + strconv.FormatInt(p.folders, 10) + " folder/s"} p.stamp("log", out, msg, "") // start watcher - go p.Reload(p.watcher, "", stop) + go p.Restart(p.watcher, "", stop) L: for { select { @@ -131,7 +135,7 @@ L: ext = "DIR" } // change message - msg = fmt.Sprintln(p.pname(p.Name, 4), ":", magenta.bold(strings.ToUpper(ext)), "changed", magenta.bold(event.Name)) + msg = fmt.Sprintln(p.pname(p.Name, 4), ":", Magenta.Bold(strings.ToUpper(ext)), "changed", Magenta.Bold(event.Name)) out = BufferOut{Time: time.Now(), Text: ext + " changed " + event.Name} // switch event type switch event.Op { @@ -142,7 +146,7 @@ L: close(stop) stop = make(chan bool) p.stamp("log", out, msg, "") - go p.Reload(p.watcher, "", stop) + go p.Restart(p.watcher, "", stop) } default: file, err := os.Stat(event.Name) @@ -160,7 +164,7 @@ L: stop = make(chan bool) // stop and start again p.stamp("log", out, msg, "") - go p.Reload(p.watcher, event.Name, stop) + go p.Restart(p.watcher, event.Name, stop) } } p.lastTime = time.Now().Truncate(time.Second) @@ -178,7 +182,7 @@ L: } // Reload launches the toolchain run, build, install -func (p *Project) Reload(watcher FileWatcher, path string, stop <-chan bool) { +func (p *Project) Restart(watcher FileWatcher, path string, stop <-chan bool) { var done bool var install, build Response go func() { @@ -210,7 +214,7 @@ func (p *Project) Reload(watcher FileWatcher, path string, stop <-chan bool) { return } if p.Tools.Install.Status { - msg = fmt.Sprintln(p.pname(p.Name, 1), ":", green.regular(p.Tools.Install.name), "started") + msg = fmt.Sprintln(p.pname(p.Name, 1), ":", Green.Regular(p.Tools.Install.name), "started") out = BufferOut{Time: time.Now(), Text: p.Tools.Install.name + " started"} p.stamp("log", out, msg, "") start := time.Now() @@ -221,7 +225,7 @@ func (p *Project) Reload(watcher FileWatcher, path string, stop <-chan bool) { return } if p.Tools.Build.Status { - msg = fmt.Sprintln(p.pname(p.Name, 1), ":", green.regular(p.Tools.Build.name), "started") + msg = fmt.Sprintln(p.pname(p.Name, 1), ":", Green.Regular(p.Tools.Build.name), "started") out = BufferOut{Time: time.Now(), Text: p.Tools.Build.name + " started"} p.stamp("log", out, msg, "") start := time.Now() @@ -241,12 +245,12 @@ func (p *Project) Reload(watcher FileWatcher, path string, stop <-chan bool) { return case r := <-result: if r.Err != nil { - msg := fmt.Sprintln(p.pname(p.Name, 2), ":", red.regular(r.Err)) + msg := fmt.Sprintln(p.pname(p.Name, 2), ":", Red.Regular(r.Err)) out := BufferOut{Time: time.Now(), Text: r.Err.Error(), Type: "Go Run"} p.stamp("error", out, msg, "") } if r.Out != "" { - msg := fmt.Sprintln(p.pname(p.Name, 3), ":", blue.regular(r.Out)) + msg := fmt.Sprintln(p.pname(p.Name, 3), ":", Blue.Regular(r.Out)) out := BufferOut{Time: time.Now(), Text: r.Out, Type: "Go Run"} p.stamp("out", out, msg, "") } @@ -258,7 +262,7 @@ func (p *Project) Reload(watcher FileWatcher, path string, stop <-chan bool) { start = time.Now() err := p.Run(p.Path, result, stop) if err != nil { - msg := fmt.Sprintln(p.pname(p.Name, 2), ":", red.regular(err)) + msg := fmt.Sprintln(p.pname(p.Name, 2), ":", Red.Regular(err)) out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Run"} p.stamp("error", out, msg, "") } @@ -305,7 +309,7 @@ func (p *Project) Run(path string, stream chan Response, stop <-chan bool) (err gobin := os.Getenv("GOBIN") dirPath := filepath.Base(path) if path == "." { - dirPath = filepath.Base(wdir()) + dirPath = filepath.Base(Wdir()) } path = filepath.Join(gobin, dirPath) if _, err := os.Stat(path); err == nil { @@ -363,7 +367,7 @@ func (p *Project) Run(path string, stream chan Response, stop <-chan bool) (err // Error occurred func (p *Project) err(err error) { - msg = fmt.Sprintln(p.pname(p.Name, 2), ":", red.regular(err.Error())) + msg = fmt.Sprintln(p.pname(p.Name, 2), ":", Red.Regular(err.Error())) out = BufferOut{Time: time.Now(), Text: err.Error()} p.stamp("error", out, msg, "") } @@ -372,19 +376,19 @@ func (p *Project) err(err error) { func (p *Project) pname(name string, color int) string { switch color { case 1: - name = yellow.regular("[") + strings.ToUpper(name) + yellow.regular("]") + name = Yellow.Regular("[") + strings.ToUpper(name) + Yellow.Regular("]") break case 2: - name = yellow.regular("[") + red.bold(strings.ToUpper(name)) + yellow.regular("]") + name = Yellow.Regular("[") + Red.Bold(strings.ToUpper(name)) + Yellow.Regular("]") break case 3: - name = yellow.regular("[") + blue.bold(strings.ToUpper(name)) + yellow.regular("]") + name = Yellow.Regular("[") + Blue.Bold(strings.ToUpper(name)) + Yellow.Regular("]") break case 4: - name = yellow.regular("[") + magenta.bold(strings.ToUpper(name)) + yellow.regular("]") + name = Yellow.Regular("[") + Magenta.Bold(strings.ToUpper(name)) + Yellow.Regular("]") break case 5: - name = yellow.regular("[") + green.bold(strings.ToUpper(name)) + yellow.regular("]") + name = Yellow.Regular("[") + Green.Bold(strings.ToUpper(name)) + Yellow.Regular("]") break } return name @@ -413,11 +417,11 @@ func (p *Project) tools(stop <-chan bool, path string) { return case r := <-result: if r.Err != nil { - msg = fmt.Sprintln(p.pname(p.Name, 2), ":", red.bold(r.Name), red.regular("there are some errors in"), ":", magenta.bold(path)) + msg = fmt.Sprintln(p.pname(p.Name, 2), ":", Red.Bold(r.Name), Red.Regular("there are some errors in"), ":", Magenta.Bold(path)) buff := BufferOut{Time: time.Now(), Text: "there are some errors in", Path: path, Type: r.Name, Stream: r.Err.Error()} p.stamp("error", buff, msg, r.Err.Error()) } else if r.Out != "" { - msg = fmt.Sprintln(p.pname(p.Name, 3), ":", red.bold(r.Name), red.regular("outputs"), ":", blue.bold(path)) + msg = fmt.Sprintln(p.pname(p.Name, 3), ":", Red.Bold(r.Name), Red.Regular("outputs"), ":", Blue.Bold(path)) buff := BufferOut{Time: time.Now(), Text: "outputs", Path: path, Type: r.Name, Stream: r.Out} p.stamp("out", buff, msg, r.Out) } @@ -446,12 +450,12 @@ func (p *Project) cmd(stop <-chan bool, flag string, global bool) { case <-done: return case r := <-result: - msg = fmt.Sprintln(p.pname(p.Name, 5), ":", green.bold("Command"), green.bold("\"")+r.Name+green.bold("\"")) + msg = fmt.Sprintln(p.pname(p.Name, 5), ":", Green.Bold("Command"), Green.Bold("\"")+r.Name+Green.Bold("\"")) out = BufferOut{Time: time.Now(), Text: r.Name, Type: flag} if r.Err != nil { p.stamp("error", out, msg, "") out = BufferOut{Time: time.Now(), Text: r.Err.Error(), Type: flag} - p.stamp("error", out, "", fmt.Sprintln(red.regular(r.Err.Error()))) + p.stamp("error", out, "", fmt.Sprintln(Red.Regular(r.Err.Error()))) } if r.Out != "" { out = BufferOut{Time: time.Now(), Text: r.Out, Type: flag} @@ -486,8 +490,8 @@ func (p *Project) walk(path string, info os.FileInfo, err error) error { // Print on files, cli, ws func (p *Project) stamp(t string, o BufferOut, msg string, stream string) { - time := time.Now() - content := []string{time.Format("2006-01-02 15:04:05"), strings.ToUpper(p.Name), ":", o.Text, "\r\n", stream} + ctime := time.Now() + content := []string{ctime.Format("2006-01-02 15:04:05"), strings.ToUpper(p.Name), ":", o.Text, "\r\n", stream} switch t { case "out": p.Buffer.StdOut = append(p.Buffer.StdOut, o) @@ -518,18 +522,18 @@ func (p *Project) stamp(t string, o BufferOut, msg string, stream string) { log.Print(msg) } if stream != "" { - fmt.Fprint(output, stream) + fmt.Fprint(Output, stream) } } // Print with time after func (r *Response) print(start time.Time, p *Project) { if r.Err != nil { - msg = fmt.Sprintln(p.pname(p.Name, 2), ":", red.bold(r.Name), "\n", r.Err.Error()) + msg = fmt.Sprintln(p.pname(p.Name, 2), ":", Red.Bold(r.Name), "\n", r.Err.Error()) out = BufferOut{Time: time.Now(), Text: r.Err.Error(), Type: r.Name, Stream: r.Out} p.stamp("error", out, msg, r.Out) } else { - msg = fmt.Sprintln(p.pname(p.Name, 5), ":", green.bold(r.Name), "completed in", magenta.regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) + msg = fmt.Sprintln(p.pname(p.Name, 5), ":", Green.Bold(r.Name), "completed in", Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) out = BufferOut{Time: time.Now(), Text: r.Name + " in " + big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3) + " s"} p.stamp("log", out, msg, r.Out) } diff --git a/realize/projects_test.go b/realize/projects_test.go new file mode 100644 index 0000000..4b7b005 --- /dev/null +++ b/realize/projects_test.go @@ -0,0 +1 @@ +package realize diff --git a/schema.go b/realize/schema.go similarity index 96% rename from schema.go rename to realize/schema.go index 0abe5f2..c78b946 100644 --- a/schema.go +++ b/realize/schema.go @@ -1,4 +1,4 @@ -package main +package realize import ( "errors" @@ -37,7 +37,7 @@ func (s *Schema) Remove(name string) error { func (s *Schema) New(c *cli.Context) Project { name := filepath.Base(c.String("path")) if name == "." { - name = filepath.Base(wdir()) + name = filepath.Base(Wdir()) } project := Project{ Name: name, diff --git a/realize/schema_test.go b/realize/schema_test.go new file mode 100644 index 0000000..4b7b005 --- /dev/null +++ b/realize/schema_test.go @@ -0,0 +1 @@ +package realize diff --git a/server.go b/realize/server.go similarity index 95% rename from server.go rename to realize/server.go index 386b935..d96f0c0 100644 --- a/server.go +++ b/realize/server.go @@ -1,4 +1,4 @@ -package main +package realize import ( "bytes" @@ -20,7 +20,7 @@ const ( // Server settings type Server struct { - parent *Realize + Parent *Realize Status bool `yaml:"status" json:"status"` Open bool `yaml:"open" json:"open"` Port int `yaml:"port" json:"port"` @@ -152,13 +152,13 @@ func (s *Server) Start() (err error) { e.GET("/ws", s.projects) e.HideBanner = true e.Debug = false - go e.Start(string(s.parent.Server.Host) + ":" + strconv.Itoa(s.parent.Server.Port)) + go e.Start(string(s.Parent.Server.Host) + ":" + strconv.Itoa(s.Parent.Server.Port)) return nil } // OpenURL in a new tab of default browser func (s *Server) OpenURL() (io.Writer, error) { - url := "http://" + string(s.parent.Server.Host) + ":" + strconv.Itoa(s.parent.Server.Port) + url := "http://" + string(s.Parent.Server.Host) + ":" + strconv.Itoa(s.Parent.Server.Port) stderr := bytes.Buffer{} cmd := map[string]string{ "windows": "start", diff --git a/realize/server_test.go b/realize/server_test.go new file mode 100644 index 0000000..4b7b005 --- /dev/null +++ b/realize/server_test.go @@ -0,0 +1 @@ +package realize diff --git a/settings.go b/realize/settings.go similarity index 98% rename from settings.go rename to realize/settings.go index e553500..91e6866 100644 --- a/settings.go +++ b/realize/settings.go @@ -1,4 +1,4 @@ -package main +package realize import ( "gopkg.in/yaml.v2" @@ -130,7 +130,7 @@ func (s Settings) Stream(file string) ([]byte, error) { func (s Settings) Fatal(err error, msg ...interface{}) { if err != nil { if len(msg) > 0 { - log.Fatalln(red.regular(msg...), err.Error()) + log.Fatalln(Red.Regular(msg...), err.Error()) } else { log.Fatalln(err.Error()) } diff --git a/realize/settings_test.go b/realize/settings_test.go new file mode 100644 index 0000000..4b7b005 --- /dev/null +++ b/realize/settings_test.go @@ -0,0 +1 @@ +package realize diff --git a/settings_unix.go b/realize/settings_unix.go similarity index 94% rename from settings_unix.go rename to realize/settings_unix.go index 1afb3f0..49d9439 100644 --- a/settings_unix.go +++ b/realize/settings_unix.go @@ -1,6 +1,6 @@ // +build !windows -package main +package realize import "syscall" diff --git a/settings_windows.go b/realize/settings_windows.go similarity index 88% rename from settings_windows.go rename to realize/settings_windows.go index 13dc18a..15a2ef0 100644 --- a/settings_windows.go +++ b/realize/settings_windows.go @@ -1,6 +1,6 @@ // +build windows -package main +package realize // Flimit defines the max number of watched files func (s *Settings) Flimit() error { diff --git a/realize/style.go b/realize/style.go new file mode 100644 index 0000000..d90f643 --- /dev/null +++ b/realize/style.go @@ -0,0 +1,27 @@ +package realize + +import ( + "github.com/fatih/color" +) + +var ( + Output = color.Output + Red = colorBase(color.FgHiRed) + Blue = colorBase(color.FgHiBlue) + Green = colorBase(color.FgHiGreen) + Yellow = colorBase(color.FgHiYellow) + Magenta = colorBase(color.FgHiMagenta) +) + +// ColorBase type +type colorBase color.Attribute + +// Regular font with a color +func (c colorBase) Regular(a ...interface{}) string { + return color.New(color.Attribute(c)).Sprint(a...) +} + +// Bold font with a color +func (c colorBase) Bold(a ...interface{}) string { + return color.New(color.Attribute(c), color.Bold).Sprint(a...) +} diff --git a/style_test.go b/realize/style_test.go similarity index 91% rename from style_test.go rename to realize/style_test.go index b40be5c..7e84ef9 100644 --- a/style_test.go +++ b/realize/style_test.go @@ -1,4 +1,4 @@ -package main +package realize import ( "bytes" @@ -13,7 +13,7 @@ func TestStyle_Regular(t *testing.T) { for i, s := range strs { input[i] = s } - result := red.regular(input) + result := Red.Regular(input) c := color.New(color.FgHiRed).SprintFunc() expected := fmt.Sprint(c(input)) if !bytes.Equal([]byte(result), []byte(expected)) { @@ -27,7 +27,7 @@ func TestStyle_Bold(t *testing.T) { for i, s := range strs { input[i] = s } - result := red.bold(input) + result := Red.Bold(input) c := color.New(color.FgHiRed, color.Bold).SprintFunc() expected := fmt.Sprint(c(input)) if !bytes.Equal([]byte(result), []byte(expected)) { diff --git a/tools.go b/realize/tools.go similarity index 99% rename from tools.go rename to realize/tools.go index fd8c982..7e9b0ae 100644 --- a/tools.go +++ b/realize/tools.go @@ -1,4 +1,4 @@ -package main +package realize import ( "bytes" diff --git a/realize/tools_test.go b/realize/tools_test.go new file mode 100644 index 0000000..4b7b005 --- /dev/null +++ b/realize/tools_test.go @@ -0,0 +1 @@ +package realize diff --git a/utils.go b/realize/utils.go similarity index 97% rename from utils.go rename to realize/utils.go index 27419ae..c877a27 100644 --- a/utils.go +++ b/realize/utils.go @@ -1,4 +1,4 @@ -package main +package realize import ( "errors" @@ -73,7 +73,7 @@ func replace(a []string, b string) []string { } // Wdir return current working directory -func wdir() string { +func Wdir() string { dir, err := os.Getwd() if err != nil { log.Fatal(err.Error()) diff --git a/utils_test.go b/realize/utils_test.go similarity index 98% rename from utils_test.go rename to realize/utils_test.go index 84f6162..51b19e5 100644 --- a/utils_test.go +++ b/realize/utils_test.go @@ -1,4 +1,4 @@ -package main +package realize import ( "flag" diff --git a/realize_test.go b/realize_test.go index 9f18ccc..f8545e0 100644 --- a/realize_test.go +++ b/realize_test.go @@ -1,13 +1,148 @@ package main -import "os" +import ( + "os" + "strings" + "testing" + rc "github.com/tockins/realize/realize" + "github.com/go-siris/siris/core/errors" + "bytes" + "log" +) var mockResponse interface{} type mockRealize struct { - Settings Settings `yaml:"settings" json:"settings"` - Server Server `yaml:"server" json:"server"` - Schema `yaml:",inline"` + Settings rc.Settings `yaml:"settings" json:"settings"` + Server rc.Server `yaml:"server" json:"server"` + rc.Schema `yaml:",inline"` sync chan string exit chan os.Signal } + +func (m *mockRealize) add() error{ + if mockResponse != nil { + return mockResponse.(error) + } + m.Projects = append(m.Projects, rc.Project{Name:"One"}) + return nil +} + +func (m *mockRealize) setup() error{ + if mockResponse != nil { + return mockResponse.(error) + } + return nil +} + +func (m *mockRealize) start() error{ + if mockResponse != nil { + return mockResponse.(error) + } + return nil +} + +func (m *mockRealize) clean() error{ + if mockResponse != nil { + return mockResponse.(error) + } + return nil +} + +func (m *mockRealize) remove() error{ + if mockResponse != nil { + return mockResponse.(error) + } + m.Projects = []rc.Project{} + return nil +} + +func TestRealize_add(t *testing.T) { + m := mockRealize{} + mockResponse = nil + if err := m.add(); err != nil{ + t.Fatal("Unexpected error") + } + if len(m.Projects) <= 0{ + t.Fatal("Unexpected error") + } + + m = mockRealize{} + m.Projects = []rc.Project{{Name:"Default"}} + mockResponse = nil + if err := m.add(); err != nil{ + t.Fatal("Unexpected error") + } + if len(m.Projects) != 2{ + t.Fatal("Unexpected error") + } + + m = mockRealize{} + mockResponse = errors.New("error") + if err := m.clean(); err == nil{ + t.Fatal("Expected error") + } + if len(m.Projects) != 0{ + t.Fatal("Unexpected error") + } +} + +func TestRealize_start(t *testing.T) { + m := mockRealize{} + mockResponse = nil + if err := m.add(); err != nil{ + t.Fatal("Unexpected error") + } +} + +func TestRealize_setup(t *testing.T) { + m := mockRealize{} + mockResponse = nil + if err := m.setup(); err != nil{ + t.Fatal("Unexpected error") + } +} + +func TestRealize_clean(t *testing.T) { + m := mockRealize{} + mockResponse = nil + if err := m.clean(); err != nil{ + t.Fatal("Unexpected error") + } + mockResponse = errors.New("error") + if err := m.clean(); err == nil{ + t.Fatal("Expected error") + } +} + +func TestRealize_remove(t *testing.T) { + m := mockRealize{} + mockResponse = nil + if err := m.remove(); err != nil{ + t.Fatal("Unexpected error") + } + + m = mockRealize{} + mockResponse = nil + m.Projects = []rc.Project{{Name:"Default"},{Name:"Default"}} + if err := m.remove(); err != nil{ + t.Fatal("Unexpected error") + } + if len(m.Projects) != 0{ + t.Fatal("Unexpected error") + } + + mockResponse = errors.New("error") + if err := m.clean(); err == nil{ + t.Fatal("Expected error") + } +} + +func TestRealize_version(t *testing.T) { + var buf bytes.Buffer + log.SetOutput(&buf) + version() + if !strings.Contains(buf.String(), rc.RVersion) { + t.Fatal("Version expted", rc.RVersion) + } +} \ No newline at end of file diff --git a/style.go b/style.go deleted file mode 100644 index f972837..0000000 --- a/style.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "github.com/fatih/color" -) - -var ( - output = color.Output - red = colorBase(color.FgHiRed) - blue = colorBase(color.FgHiBlue) - green = colorBase(color.FgHiGreen) - yellow = colorBase(color.FgHiYellow) - magenta = colorBase(color.FgHiMagenta) -) - -// ColorBase type -type colorBase color.Attribute - -// Regular font with a color -func (c colorBase) regular(a ...interface{}) string { - return color.New(color.Attribute(c)).Sprint(a...) -} - -// Bold font with a color -func (c colorBase) bold(a ...interface{}) string { - return color.New(color.Attribute(c), color.Bold).Sprint(a...) -}