output file, code clean

This commit is contained in:
alessio 2016-08-31 14:08:15 +02:00
parent d03f5c5a7f
commit 38bd1f8ba5
7 changed files with 404 additions and 381 deletions

30
main.go
View File

@ -11,7 +11,7 @@ import (
func main() { func main() {
app := r.Info() app := r.App
handle := func(err error) error { handle := func(err error) error {
if err != nil { if err != nil {
@ -50,8 +50,7 @@ func main() {
Name: "run", Name: "run",
Usage: "Build and watch file changes", Usage: "Build and watch file changes",
Action: func(p *cli.Context) error { Action: func(p *cli.Context) error {
y := r.New(p) return handle(app.Blueprint.Run())
return handle(y.Watch())
}, },
Before: func(c *cli.Context) error { Before: func(c *cli.Context) error {
header() header()
@ -60,7 +59,7 @@ func main() {
}, },
{ {
Name: "fast", Name: "fast",
Usage: "Build and watch file changes for a single project without any config file", Usage: "Build and watch file changes for a single project without any Configuration file",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{Name: "path", Aliases: []string{"b"}, Value: "", Usage: "Project base path"}, &cli.StringFlag{Name: "path", Aliases: []string{"b"}, Value: "", Usage: "Project base path"},
&cli.BoolFlag{Name: "build", Value: false, Usage: "Enables the build"}, &cli.BoolFlag{Name: "build", Value: false, Usage: "Enables the build"},
@ -68,11 +67,11 @@ func main() {
&cli.BoolFlag{Name: "no-bin", Usage: "Disables the installation"}, &cli.BoolFlag{Name: "no-bin", Usage: "Disables the installation"},
&cli.BoolFlag{Name: "no-fmt", Usage: "Disables the fmt (go fmt)"}, &cli.BoolFlag{Name: "no-fmt", Usage: "Disables the fmt (go fmt)"},
&cli.BoolFlag{Name: "test", Value: false, Usage: "Enable the tests"}, &cli.BoolFlag{Name: "test", Value: false, Usage: "Enable the tests"},
&cli.BoolFlag{Name: "config", Value: false, Usage: "Take the defined settings if exist a config file."}, &cli.BoolFlag{Name: "Configuration", Value: false, Usage: "Take the defined settings if exist a Configuration file."},
}, },
Action: func(p *cli.Context) error { Action: func(p *cli.Context) error {
y := r.New(p) app.Blueprint.Add(p)
return handle(y.Fast(p)) return handle(app.Blueprint.Fast(p))
}, },
Before: func(c *cli.Context) error { Before: func(c *cli.Context) error {
header() header()
@ -81,11 +80,11 @@ func main() {
}, },
{ {
Name: "add", Name: "add",
Category: "config", Category: "Configuration",
Aliases: []string{"a"}, Aliases: []string{"a"},
Usage: "Add another project", Usage: "Add another project",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{Name: "name", Aliases: []string{"n"}, Value: r.WorkingDir(), Usage: "Project name"}, &cli.StringFlag{Name: "name", Aliases: []string{"n"}, Value: app.Wdir(), Usage: "Project name"},
&cli.StringFlag{Name: "path", Aliases: []string{"b"}, Value: "/", Usage: "Project base path"}, &cli.StringFlag{Name: "path", Aliases: []string{"b"}, Value: "/", Usage: "Project base path"},
&cli.BoolFlag{Name: "build", Value: false, Usage: "Enable the build"}, &cli.BoolFlag{Name: "build", Value: false, Usage: "Enable the build"},
&cli.BoolFlag{Name: "no-run", Usage: "Disables the run"}, &cli.BoolFlag{Name: "no-run", Usage: "Disables the run"},
@ -94,8 +93,7 @@ func main() {
&cli.BoolFlag{Name: "test", Value: false, Usage: "Enable the tests"}, &cli.BoolFlag{Name: "test", Value: false, Usage: "Enable the tests"},
}, },
Action: func(p *cli.Context) error { Action: func(p *cli.Context) error {
y := r.New(p) return handle(app.Blueprint.Insert(p))
return handle(y.Add(p))
}, },
Before: func(c *cli.Context) error { Before: func(c *cli.Context) error {
header() header()
@ -104,15 +102,14 @@ func main() {
}, },
{ {
Name: "remove", Name: "remove",
Category: "config", Category: "Configuration",
Aliases: []string{"r"}, Aliases: []string{"r"},
Usage: "Remove a project", Usage: "Remove a project",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{Name: "name", Aliases: []string{"n"}, Value: ""}, &cli.StringFlag{Name: "name", Aliases: []string{"n"}, Value: ""},
}, },
Action: func(p *cli.Context) error { Action: func(p *cli.Context) error {
y := r.New(p) return handle(app.Blueprint.Remove(p))
return handle(y.Remove(p))
}, },
Before: func(c *cli.Context) error { Before: func(c *cli.Context) error {
header() header()
@ -121,12 +118,11 @@ func main() {
}, },
{ {
Name: "list", Name: "list",
Category: "config", Category: "Configuration",
Aliases: []string{"l"}, Aliases: []string{"l"},
Usage: "Projects list", Usage: "Projects list",
Action: func(p *cli.Context) error { Action: func(p *cli.Context) error {
y := r.New(p) return handle(app.Blueprint.List())
return handle(y.List())
}, },
Before: func(c *cli.Context) error { Before: func(c *cli.Context) error {
header() header()

View File

@ -1,21 +1,12 @@
package realize package realize
import ( import (
"fmt"
"github.com/fatih/color" "github.com/fatih/color"
"log" "log"
"sync" "sync"
"syscall"
"time"
) )
// Default values and info var App Realize
const (
AppName = "Realize"
AppVersion = "v1.0"
AppDescription = "A Go build system with file watchers, output streams and live reload. Run, build and watch file changes with custom paths"
AppFile = "realize.config.yaml"
)
var wg sync.WaitGroup var wg sync.WaitGroup
@ -46,47 +37,19 @@ var MagentaS = color.New(color.FgMagenta).SprintFunc()
// Magenta color bold // Magenta color bold
var Magenta = color.New(color.FgMagenta, color.Bold).SprintFunc() var Magenta = color.New(color.FgMagenta, color.Bold).SprintFunc()
// WatcherIgnores is an array of default ignored paths // Initialize the application
var watcherIgnores = []string{"vendor", "bin"}
// WatcherExts is an array of default exts
var watcherExts = []string{".go"}
// WatcherPaths is an array of default watched paths
var watcherPaths = []string{"/"}
type logWriter struct{}
// App struct contains the informations about realize
type App struct {
Name, Version, Description, Author, Email string
}
// Custom log timestamp
func init() { func init() {
App = Realize{
Name: "Realize",
Version: "1.0",
Description: "A Go build system with file watchers, output streams and live reload. Run, build and watch file changes with custom paths",
Limit: 10000,
}
App.Blueprint.files = map[string]string{
"config": "r.config.yaml",
"output": "r.output.log",
}
App.limit()
log.SetFlags(0) log.SetFlags(0)
log.SetOutput(new(logWriter)) log.SetOutput(new(logWriter))
// increases the files limit
var rLimit syscall.Rlimit
rLimit.Max = 10000
rLimit.Cur = 10000
err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
fmt.Println(Red("Error Setting Rlimit "), err)
}
}
// Info returns the general informations about Realize
func Info() *App {
return &App{
Name: AppName,
Version: AppVersion,
Description: AppDescription,
}
}
// Cewrites the log timestamp
func (writer logWriter) Write(bytes []byte) (int, error) {
return fmt.Print(YellowS("[") + time.Now().Format("15:04:05") + YellowS("]") + string(bytes))
} }

225
realize/blueprint.go Normal file
View File

@ -0,0 +1,225 @@
package realize
import (
"errors"
"fmt"
"gopkg.in/urfave/cli.v2"
"gopkg.in/yaml.v2"
"log"
"os"
"path/filepath"
"strings"
"syscall"
"time"
)
// App struct contains the informations about realize
type Realize struct {
Name, Description, Author, Email string
Version string `yaml:"version,omitempty"`
Limit uint64
Blueprint Blueprint
}
// Projects struct contains a projects list
type Blueprint struct {
Projects []Project `yaml:"projects,omitempty"`
files map[string]string
}
// Project defines the informations of a single project
type Project struct {
reload time.Time
base string
Name string `yaml:"app_name,omitempty"`
Path string `yaml:"app_path,omitempty"`
Run bool `yaml:"app_run,omitempty"`
Bin bool `yaml:"app_bin,omitempty"`
Build bool `yaml:"app_build,omitempty"`
Fmt bool `yaml:"app_fmt,omitempty"`
Test bool `yaml:"app_test,omitempty"`
Params []string `yaml:"app_params,omitempty"`
Watcher Watcher `yaml:"app_watcher,omitempty"`
}
// Wdir returns the name last element of the working directory path
func (r *Realize) Wdir() string {
dir, err := os.Getwd()
if err != nil {
log.Fatal(Red(err))
}
return filepath.Base(dir)
}
// Limit defines the max number of watched files
func (r *Realize) limit() {
// increases the files limit
var rLimit syscall.Rlimit
rLimit.Max = r.Limit
rLimit.Cur = r.Limit
err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil {
fmt.Println(Red("Error Setting Rlimit "), err)
}
}
// Watch method adds the given paths on the Watcher
func (h *Blueprint) Run() error {
err := h.Read()
if err == nil {
// loop projects
wg.Add(len(h.Projects))
for k := range h.Projects {
go h.Projects[k].watching()
}
wg.Wait()
return nil
}
return err
}
// Fast method run a project from his working directory without makes a config file
func (h *Blueprint) Fast(params *cli.Context) error {
fast := h.Projects[0]
// Takes the values from config if wd path match with someone else
if params.Bool("config") {
if err := h.Read(); err == nil {
for _, val := range h.Projects {
if fast.Path == val.Path {
fast = val
}
}
}
}
wg.Add(1)
go fast.watching()
wg.Wait()
return nil
}
// Add a new project
func (h *Blueprint) Add(params *cli.Context) error {
p := Project{
Name: nameFlag(params),
Path: filepath.Clean(params.String("path")),
Build: params.Bool("build"),
Bin: boolFlag(params.Bool("no-bin")),
Run: boolFlag(params.Bool("no-run")),
Fmt: boolFlag(params.Bool("no-fmt")),
Test: params.Bool("test"),
Params: argsParam(params),
Watcher: Watcher{
Paths: []string{"/"},
Ignore: []string{"vendor"},
Exts: []string{".go"},
Output: map[string]bool{
"cli": true,
"file": false,
},
},
}
if _, err := duplicates(p, h.Projects); err != nil {
return err
}
h.Projects = append(h.Projects, p)
return nil
}
// Clean duplicate projects
func (h *Blueprint) Clean() {
arr := h.Projects
for key, val := range arr {
if _, err := duplicates(val, arr[key+1:]); err != nil {
h.Projects = append(arr[:key], arr[key+1:]...)
break
}
}
}
// Read, Check and remove duplicates from the config file
func (h *Blueprint) Read() error {
content, err := read(h.files["config"])
if err == nil {
err = yaml.Unmarshal(content, h)
if err == nil {
if len(h.Projects) > 0 {
h.Clean()
return nil
}
return errors.New("There are no projects!")
}
return err
}
return err
}
// Create and unmarshal yaml config file
func (h *Blueprint) Create() error {
y, err := yaml.Marshal(h)
if err != nil {
return err
}
return write(h.files["config"], y)
}
// Inserts a new project in the list
func (h *Blueprint) Insert(params *cli.Context) error {
check := h.Read()
err := h.Add(params)
if err == nil {
err = h.Create()
if check == nil && err == nil {
fmt.Println(Green("Your project was successfully added"))
} else {
fmt.Println(Green("The config file was successfully created"))
}
}
return err
}
// Remove a project
func (h *Blueprint) Remove(params *cli.Context) error {
err := h.Read()
if err == nil {
for key, val := range h.Projects {
if params.String("name") == val.Name {
h.Projects = append(h.Projects[:key], h.Projects[key+1:]...)
err = h.Create()
if err == nil {
fmt.Println(Green("Your project was successfully removed"))
}
return err
}
}
return errors.New("No project found")
}
return err
}
// List of all the projects
func (h *Blueprint) List() error {
err := h.Read()
if err == nil {
for _, val := range h.Projects {
fmt.Println(Blue("|"), Blue(strings.ToUpper(val.Name)))
fmt.Println(MagentaS("|"), "\t", Yellow("Base Path"), ":", MagentaS(val.Path))
fmt.Println(MagentaS("|"), "\t", Yellow("Run"), ":", MagentaS(val.Run))
fmt.Println(MagentaS("|"), "\t", Yellow("Build"), ":", MagentaS(val.Build))
fmt.Println(MagentaS("|"), "\t", Yellow("Install"), ":", MagentaS(val.Bin))
fmt.Println(MagentaS("|"), "\t", Yellow("Fmt"), ":", MagentaS(val.Fmt))
fmt.Println(MagentaS("|"), "\t", Yellow("Test"), ":", MagentaS(val.Test))
fmt.Println(MagentaS("|"), "\t", Yellow("Params"), ":", MagentaS(val.Params))
fmt.Println(MagentaS("|"), "\t", Yellow("Watcher"), ":")
fmt.Println(MagentaS("|"), "\t\t", Yellow("After"), ":", MagentaS(val.Watcher.After))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Before"), ":", MagentaS(val.Watcher.Before))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Extensions"), ":", MagentaS(val.Watcher.Exts))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Paths"), ":", MagentaS(val.Watcher.Paths))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Paths ignored"), ":", MagentaS(val.Watcher.Ignore))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Watch preview"), ":", MagentaS(val.Watcher.Preview))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Output"), ":")
fmt.Println(MagentaS("|"), "\t\t\t", Yellow("Cli"), ":", MagentaS(val.Watcher.Output["cli"]))
fmt.Println(MagentaS("|"), "\t\t\t", Yellow("File"), ":", MagentaS(val.Watcher.Output["file"]))
}
}
return err
}

View File

@ -1,219 +0,0 @@
package realize
import (
"errors"
"fmt"
"gopkg.in/urfave/cli.v2"
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)
// Config struct contains the general informations about a project
type Config struct {
file string
Version string `yaml:"version,omitempty"`
Projects []Project
}
// New method puts the cli params in the struct
func New(params *cli.Context) *Config {
return &Config{
file: AppFile,
Version: AppVersion,
Projects: []Project{
{
Name: nameFlag(params),
Path: filepath.Clean(params.String("path")),
Build: params.Bool("build"),
Bin: boolFlag(params.Bool("no-bin")),
Run: boolFlag(params.Bool("no-run")),
Fmt: boolFlag(params.Bool("no-fmt")),
Test: params.Bool("test"),
Params: argsParam(params),
Watcher: Watcher{
Paths: watcherPaths,
Ignore: watcherIgnores,
Exts: watcherExts,
},
},
},
}
}
// argsParam parse one by one the given argumentes
func argsParam(params *cli.Context) []string {
argsN := params.NArg()
if argsN > 0 {
var args []string
for i := 0; i <= argsN-1; i++ {
args = append(args, params.Args().Get(i))
}
return args
}
return nil
}
// NameParam check the project name presence. If empty takes the working directory name
func nameFlag(params *cli.Context) string {
var name string
if params.String("name") == "" && params.String("path") == "" {
return WorkingDir()
} else if params.String("path") != "/" {
name = filepath.Base(params.String("path"))
} else {
name = params.String("name")
}
return name
}
// BoolParam is used to check the presence of a bool flag
func boolFlag(b bool) bool {
if b {
return false
}
return true
}
// WorkingDir returns the last element of the working dir path
func WorkingDir() string {
dir, err := os.Getwd()
if err != nil {
log.Fatal(Red(err))
}
return filepath.Base(dir)
}
// Duplicates check projects with same name or same combinations of main/path
func Duplicates(value Project, arr []Project) (Project, error) {
for _, val := range arr {
if value.Path == val.Path || value.Name == val.Name {
return val, errors.New("There is a duplicate of '" + val.Name + "'. Check your config file!")
}
}
return Project{}, nil
}
// Clean duplicate projects
func (h *Config) Clean() {
arr := h.Projects
for key, val := range arr {
if _, err := Duplicates(val, arr[key+1:]); err != nil {
h.Projects = append(arr[:key], arr[key+1:]...)
break
}
}
}
// Read, Check and remove duplicates from the config file
func (h *Config) Read() error {
_, err := os.Stat(h.file)
if err == nil {
file, err := ioutil.ReadFile(h.file)
if err == nil {
if len(h.Projects) > 0 {
err = yaml.Unmarshal(file, h)
if err == nil {
h.Clean()
}
return err
}
return errors.New("There are no projects")
}
return h.Create()
}
return err
}
// Create and unmarshal yaml config file
func (h *Config) Create() error {
y, err := yaml.Marshal(h)
if err != nil {
return err
}
return ioutil.WriteFile(h.file, y, 0655)
}
// Add another project
func (h *Config) Add(params *cli.Context) error {
err := h.Read()
if err == nil {
new := Project{
Name: nameFlag(params),
Path: filepath.Clean(params.String("path")),
Build: params.Bool("build"),
Bin: boolFlag(params.Bool("no-bin")),
Run: boolFlag(params.Bool("no-run")),
Fmt: boolFlag(params.Bool("no-fmt")),
Test: params.Bool("test"),
Params: argsParam(params),
Watcher: Watcher{
Paths: watcherPaths,
Exts: watcherExts,
Ignore: watcherIgnores,
},
}
if _, err := Duplicates(new, h.Projects); err != nil {
return err
}
h.Projects = append(h.Projects, new)
err = h.Create()
if err == nil {
fmt.Println(Green("Your project was successfully added"))
}
return err
}
err = h.Create()
if err == nil {
fmt.Println(Green("The config file was successfully created"))
}
return err
}
// Remove a project in list
func (h *Config) Remove(params *cli.Context) error {
err := h.Read()
if err == nil {
for key, val := range h.Projects {
if params.String("name") == val.Name {
h.Projects = append(h.Projects[:key], h.Projects[key+1:]...)
err = h.Create()
if err == nil {
fmt.Println(Green("Your project was successfully removed"))
}
return err
}
}
return errors.New("No project found")
}
return err
}
// List of projects
func (h *Config) List() error {
err := h.Read()
if err == nil {
for _, val := range h.Projects {
fmt.Println(Blue("|"), Blue(strings.ToUpper(val.Name)))
fmt.Println(MagentaS("|"), "\t", Yellow("Base Path"), ":", MagentaS(val.Path))
fmt.Println(MagentaS("|"), "\t", Yellow("Run"), ":", MagentaS(val.Run))
fmt.Println(MagentaS("|"), "\t", Yellow("Build"), ":", MagentaS(val.Build))
fmt.Println(MagentaS("|"), "\t", Yellow("Install"), ":", MagentaS(val.Bin))
fmt.Println(MagentaS("|"), "\t", Yellow("Fmt"), ":", MagentaS(val.Fmt))
fmt.Println(MagentaS("|"), "\t", Yellow("Test"), ":", MagentaS(val.Test))
fmt.Println(MagentaS("|"), "\t", Yellow("Params"), ":", MagentaS(val.Params))
fmt.Println(MagentaS("|"), "\t", Yellow("Watcher"), ":")
fmt.Println(MagentaS("|"), "\t\t", Yellow("After"), ":", MagentaS(val.Watcher.After))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Before"), ":", MagentaS(val.Watcher.Before))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Extensions"), ":", MagentaS(val.Watcher.Exts))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Paths"), ":", MagentaS(val.Watcher.Paths))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Paths ignored"), ":", MagentaS(val.Watcher.Ignore))
fmt.Println(MagentaS("|"), "\t\t", Yellow("Watch preview"), ":", MagentaS(val.Watcher.Preview))
}
return nil
}
return err
}

View File

@ -12,21 +12,6 @@ import (
"time" "time"
) )
// The Project struct defines the informations about a project
type Project struct {
reload time.Time
base string
Name string `yaml:"app_name,omitempty"`
Path string `yaml:"app_path,omitempty"`
Run bool `yaml:"app_run,omitempty"`
Bin bool `yaml:"app_bin,omitempty"`
Build bool `yaml:"app_build,omitempty"`
Fmt bool `yaml:"app_fmt,omitempty"`
Test bool `yaml:"app_test,omitempty"`
Params []string `yaml:"app_params,omitempty"`
Watcher Watcher `yaml:"app_watcher,omitempty"`
}
// GoRun is an implementation of the bin execution // GoRun is an implementation of the bin execution
func (p *Project) GoRun(channel chan bool, runner chan bool, wr *sync.WaitGroup) error { func (p *Project) GoRun(channel chan bool, runner chan bool, wr *sync.WaitGroup) error {
@ -51,7 +36,6 @@ func (p *Project) GoRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
// Read stdout and stderr in same var // Read stdout and stderr in same var
outputs := io.MultiReader(stdout, stderr) outputs := io.MultiReader(stdout, stderr)
if err != nil { if err != nil {
log.Println(Red(err.Error())) log.Println(Red(err.Error()))
return err return err
@ -67,7 +51,17 @@ func (p *Project) GoRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
for in.Scan() { for in.Scan() {
select { select {
default: default:
log.Println(pname(p.Name, 3), ":", BlueS(in.Text())) if p.Watcher.Output["cli"] {
log.Println(pname(p.Name, 3), ":", BlueS(in.Text()))
}
if p.Watcher.Output["file"] {
path := filepath.Join(p.base, App.Blueprint.files["output"])
f := create(path)
t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + in.Text() + "\r\n"); err != nil {
log.Fatal(err)
}
}
} }
} }
close(stop) close(stop)

130
realize/utils.go Normal file
View File

@ -0,0 +1,130 @@
package realize
import (
"errors"
"fmt"
"gopkg.in/urfave/cli.v2"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"time"
)
// Read a file given a name and return its byte stream
func read(file string) ([]byte, error) {
_, err := os.Stat(file)
if err == nil {
content, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
return content, err
}
return nil, err
}
// Write a file given a name and a byte stream
func write(name string, data []byte) error {
err := ioutil.WriteFile(name, data, 0655)
if err != nil {
log.Fatal(err)
return err
}
return nil
}
// Create a new file and return its pointer
func create(file string) *os.File {
out, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0655)
if err != nil {
log.Fatal(err)
}
return out
}
// argsParam parse one by one the given argumentes
func argsParam(params *cli.Context) []string {
argsN := params.NArg()
if argsN > 0 {
var args []string
for i := 0; i <= argsN-1; i++ {
args = append(args, params.Args().Get(i))
}
return args
}
return nil
}
// NameParam check the project name presence. If empty takes the working directory name
func nameFlag(params *cli.Context) string {
var name string
if params.String("name") == "" && params.String("path") == "" {
return App.Wdir()
} else if params.String("path") != "/" {
name = filepath.Base(params.String("path"))
} else {
name = params.String("name")
}
return name
}
// BoolParam is used to check the presence of a bool flag
func boolFlag(b bool) bool {
if b {
return false
}
return true
}
// Duplicates check projects with same name or same combinations of main/path
func duplicates(value Project, arr []Project) (Project, error) {
for _, val := range arr {
if value.Path == val.Path || value.Name == val.Name {
return val, errors.New("There is a duplicate of '" + val.Name + "'. Check your config file!")
}
}
return Project{}, nil
}
// check if a string is inArray
func inArray(str string, list []string) bool {
for _, v := range list {
if v == str {
return true
}
}
return false
}
// Defines the colors scheme for the project name
func pname(name string, color int) string {
switch color {
case 1:
name = Yellow("[") + strings.ToUpper(name) + Yellow("]")
break
case 2:
name = Yellow("[") + Red(strings.ToUpper(name)) + Yellow("]")
break
case 3:
name = Yellow("[") + Blue(strings.ToUpper(name)) + Yellow("]")
break
case 4:
name = Yellow("[") + Magenta(strings.ToUpper(name)) + Yellow("]")
break
case 5:
name = Yellow("[") + Green(strings.ToUpper(name)) + Yellow("]")
break
}
return name
}
// Log struct
type logWriter struct{}
// Cewrites the log timestamp
func (writer logWriter) Write(bytes []byte) (int, error) {
return fmt.Print(YellowS("[") + time.Now().Format("15:04:05") + YellowS("]") + string(bytes))
}

View File

@ -4,7 +4,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"gopkg.in/urfave/cli.v2"
"log" "log"
"math/big" "math/big"
"os" "os"
@ -17,46 +16,13 @@ import (
// The Watcher struct defines the livereload's logic // The Watcher struct defines the livereload's logic
type Watcher struct { type Watcher struct {
// different before and after on re-run? // different before and after on re-run?
Before []string `yaml:"before,omitempty"` Before []string `yaml:"before,omitempty"`
After []string `yaml:"after,omitempty"` After []string `yaml:"after,omitempty"`
Paths []string `yaml:"paths,omitempty"` Paths []string `yaml:"paths,omitempty"`
Ignore []string `yaml:"ignore_paths,omitempty"` Ignore []string `yaml:"ignore_paths,omitempty"`
Exts []string `yaml:"exts,omitempty"` Exts []string `yaml:"exts,omitempty"`
Preview bool `yaml:"preview,omitempty"` Preview bool `yaml:"preview,omitempty"`
} Output map[string]bool `yaml:"output,omitempty"`
// Watch method adds the given paths on the Watcher
func (h *Config) Watch() error {
err := h.Read()
if err == nil {
// loop projects
wg.Add(len(h.Projects))
for k := range h.Projects {
go h.Projects[k].watching()
}
wg.Wait()
return nil
}
return err
}
// Fast method run a project from his working directory without makes a config file
func (h *Config) Fast(params *cli.Context) error {
fast := h.Projects[0]
// Takes the values from config if wd path match with someone else
if params.Bool("config") {
if err := h.Read(); err == nil {
for _, val := range h.Projects {
if fast.Path == val.Path {
fast = val
}
}
}
}
wg.Add(1)
go fast.watching()
wg.Wait()
return nil
} }
// Watching method is the main core. It manages the livereload and the watching // Watching method is the main core. It manages the livereload and the watching
@ -84,7 +50,7 @@ func (p *Project) watching() {
fmt.Println(pname(p.Name, 1), ":", Red(err.Error())) fmt.Println(pname(p.Name, 1), ":", Red(err.Error()))
return return
} }
go routines(p, channel, &wr) go p.routines(channel, &wr)
p.reload = time.Now().Truncate(time.Second) p.reload = time.Now().Truncate(time.Second)
// waiting for an event // waiting for an event
@ -117,7 +83,7 @@ func (p *Project) watching() {
if err != nil { if err != nil {
log.Fatal(Red(err)) log.Fatal(Red(err))
} else { } else {
go routines(p, channel, &wr) go p.routines(channel, &wr)
p.reload = time.Now().Truncate(time.Second) p.reload = time.Now().Truncate(time.Second)
} }
} }
@ -230,7 +196,7 @@ func (p *Project) walks(watcher *fsnotify.Watcher) error {
if p.Path == "." || p.Path == "/" { if p.Path == "." || p.Path == "/" {
p.base = wd p.base = wd
p.Path = WorkingDir() p.Path = App.Wdir()
} else if filepath.IsAbs(p.Path) { } else if filepath.IsAbs(p.Path) {
p.base = p.Path p.base = p.Path
} else { } else {
@ -247,7 +213,7 @@ func (p *Project) walks(watcher *fsnotify.Watcher) error {
return errors.New(base + " path doesn't exist") return errors.New(base + " path doesn't exist")
} }
} }
fmt.Println(Red("Watching: "), pname(p.Name, 1), Magenta(files), "file/s", Magenta(folders), "folder/s") fmt.Println(Red("Watching"), ":", pname(p.Name, 1), Magenta(files), "file/s", Magenta(folders), "folder/s")
return nil return nil
} }
@ -262,41 +228,9 @@ func (p *Project) ignore(str string) bool {
} }
// Routines launches the following methods: run, build, fmt, install // Routines launches the following methods: run, build, fmt, install
func routines(p *Project, channel chan bool, wr *sync.WaitGroup) { func (p *Project) routines(channel chan bool, wr *sync.WaitGroup) {
wr.Add(1) wr.Add(1)
go p.build() go p.build()
go p.install(channel, wr) go p.install(channel, wr)
wr.Wait() wr.Wait()
} }
// check if a string is inArray
func inArray(str string, list []string) bool {
for _, v := range list {
if v == str {
return true
}
}
return false
}
// defines the colors scheme for the project name
func pname(name string, color int) string {
switch color {
case 1:
name = Yellow("[") + strings.ToUpper(name) + Yellow("]")
break
case 2:
name = Yellow("[") + Red(strings.ToUpper(name)) + Yellow("]")
break
case 3:
name = Yellow("[") + Blue(strings.ToUpper(name)) + Yellow("]")
break
case 4:
name = Yellow("[") + Magenta(strings.ToUpper(name)) + Yellow("]")
break
case 5:
name = Yellow("[") + Green(strings.ToUpper(name)) + Yellow("]")
break
}
return name
}