Merge
This commit is contained in:
commit
de3989ae9d
73
README.md
73
README.md
@ -50,6 +50,7 @@ A Go build system with file watchers, output streams and live reload. Run, build
|
|||||||
--name="Project Name" -> Name, if not specified takes the working directory name
|
--name="Project Name" -> Name, if not specified takes the working directory name
|
||||||
--path="server" -> Base Path, if not specified takes the working directory name
|
--path="server" -> Base Path, if not specified takes the working directory name
|
||||||
--build -> Enables the build
|
--build -> Enables the build
|
||||||
|
--test -> Enables the tests
|
||||||
--no-bin -> Disables the installation
|
--no-bin -> Disables the installation
|
||||||
--no-run -> Disables the run
|
--no-run -> Disables the run
|
||||||
--no-fmt -> Disables the fmt (go fmt)
|
--no-fmt -> Disables the fmt (go fmt)
|
||||||
@ -58,18 +59,16 @@ A Go build system with file watchers, output streams and live reload. Run, build
|
|||||||
|
|
||||||
```
|
```
|
||||||
$ realize add
|
$ realize add
|
||||||
```
|
|
||||||
```
|
|
||||||
$ realize add --path="mypath"
|
$ realize add --path="mypath"
|
||||||
```
|
|
||||||
```
|
|
||||||
$ realize add --name="My Project" --build
|
$ realize add --name="My Project" --build
|
||||||
```
|
|
||||||
```
|
|
||||||
$ realize add --name="My Project" --path="/projects/package" --build
|
$ realize add --name="My Project" --path="/projects/package" --build
|
||||||
```
|
|
||||||
```
|
|
||||||
$ realize add --name="My Project" --path="projects/package" --build --no-run
|
$ realize add --name="My Project" --path="projects/package" --build --no-run
|
||||||
|
|
||||||
|
$ realize add --path="/Users/alessio/go/src/github.com/tockins/realize-examples/coin/"
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want, you can specify additional arguments for your project.
|
If you want, you can specify additional arguments for your project.
|
||||||
@ -108,18 +107,21 @@ A Go build system with file watchers, output streams and live reload. Run, build
|
|||||||
|
|
||||||
```
|
```
|
||||||
--build -> Enables the build
|
--build -> Enables the build
|
||||||
|
--test -> Enables the tests
|
||||||
--no-bin -> Disables the installation
|
--no-bin -> Disables the installation
|
||||||
--no-run -> Disables the run
|
--no-run -> Disables the run
|
||||||
--no-fmt -> Disables the fmt (go fmt)
|
--no-fmt -> Disables the fmt (go fmt)
|
||||||
--config -> Take the defined settings if exist a config file
|
--config -> Take the defined settings if exist a config file
|
||||||
```
|
```
|
||||||
|
|
||||||
The "fast" command supporst addittional arguments as the "add" command.
|
The "fast" command supports addittional arguments as the "add" command.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ realize fast --no-run yourParams --yourFlags // correct
|
$ realize fast --no-run yourParams --yourFlags // correct
|
||||||
|
|
||||||
$ realize fast yourParams --yourFlags --no-run // wrong
|
$ realize fast yourParams --yourFlags --no-run // wrong
|
||||||
|
|
||||||
|
$ realize fast --path="/Users/alessio/go/src/github.com/tockins/realize-examples/coin/"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -136,7 +138,6 @@ A Go build system with file watchers, output streams and live reload. Run, build
|
|||||||
- For more examples check [Realize Examples](https://github.com/tockins/realize-examples)
|
- For more examples check [Realize Examples](https://github.com/tockins/realize-examples)
|
||||||
|
|
||||||
```
|
```
|
||||||
version: "1.0"
|
|
||||||
projects:
|
projects:
|
||||||
- app_name: App One -> name
|
- app_name: App One -> name
|
||||||
app_path: one -> root path
|
app_path: one -> root path
|
||||||
@ -144,7 +145,8 @@ A Go build system with file watchers, output streams and live reload. Run, build
|
|||||||
app_bin: true -> enable/disable go install
|
app_bin: true -> enable/disable go install
|
||||||
app_build: false -> enable/disable go build
|
app_build: false -> enable/disable go build
|
||||||
app_fmt: true -> enable/disable go fmt
|
app_fmt: true -> enable/disable go fmt
|
||||||
app_params:
|
app_test: true -> enable/disable go test
|
||||||
|
app_params: -> the project will be launched with these parameters
|
||||||
- --flag1
|
- --flag1
|
||||||
- param1
|
- param1
|
||||||
app_watcher:
|
app_watcher:
|
||||||
@ -156,47 +158,20 @@ A Go build system with file watchers, output streams and live reload. Run, build
|
|||||||
- bin
|
- bin
|
||||||
exts: -> file extensions to observe for live reload
|
exts: -> file extensions to observe for live reload
|
||||||
- .go
|
- .go
|
||||||
- app_name: App Two -> another project
|
output: -> enable/disable the output destinations
|
||||||
app_path: two
|
cli: true -> cli output
|
||||||
app_run: true
|
file: true -> creates an output file inside the project
|
||||||
app_build: true
|
|
||||||
app_bin: true
|
|
||||||
app_watcher:
|
|
||||||
paths:
|
|
||||||
- /
|
|
||||||
ignore_paths:
|
|
||||||
- vendor
|
|
||||||
- bin
|
|
||||||
exts:
|
|
||||||
- .go
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Next releases
|
#### Next release
|
||||||
|
|
||||||
#####Milestone 1.0
|
|
||||||
|
|
||||||
- [x] Cli start, remove, add, list, run
|
|
||||||
- [x] Remove duplicate projects
|
|
||||||
- [x] Support for multiple projects
|
|
||||||
- [x] Watcher files preview
|
|
||||||
- [x] Support for directories with duplicates names
|
|
||||||
- [ ] Go test support
|
|
||||||
- [x] Additional arguments
|
|
||||||
- [x] Go fmt support
|
|
||||||
- [x] Cli fast run
|
|
||||||
- [x] Execution times for build/install
|
|
||||||
- [x] Go doc
|
|
||||||
- [x] Support for server start/stop
|
|
||||||
- [x] Stream projects output
|
|
||||||
- [x] Cli feedback
|
|
||||||
|
|
||||||
##### Milestone 1.1
|
##### Milestone 1.1
|
||||||
- [ ] Test under windows
|
- [ ] Testing on windows
|
||||||
- [ ] Unit test
|
- [x] Custom paths for the commands fast/add
|
||||||
- [ ] Custom path on commands
|
- [x] Save output on a file
|
||||||
- [ ] Output files
|
- [x] Enable the fields Before/After
|
||||||
- [ ] Cli args
|
- [ ] Web panel - **Maybe**
|
||||||
- [ ] Before/After command
|
|
||||||
|
|
||||||
|
|
||||||
#### Contacts
|
#### Contacts
|
||||||
@ -204,4 +179,4 @@ A Go build system with file watchers, output streams and live reload. Run, build
|
|||||||
- Chat with us [Gitter](https://gitter.im/tockins/realize)
|
- Chat with us [Gitter](https://gitter.im/tockins/realize)
|
||||||
|
|
||||||
- [Alessio Pracchia](https://www.linkedin.com/in/alessio-pracchia-38a70673)
|
- [Alessio Pracchia](https://www.linkedin.com/in/alessio-pracchia-38a70673)
|
||||||
- [Daniele Conventi](https://www.linkedin.com/in/daniele-conventi-b419b0a4)
|
- [Daniele Conventi](https://www.linkedin.com/in/conventi)
|
||||||
|
171
cli/cmd.go
Normal file
171
cli/cmd.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"gopkg.in/urfave/cli.v2"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package realize
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -8,24 +8,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"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"`
|
|
||||||
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 {
|
||||||
|
|
||||||
@ -41,7 +28,7 @@ func (p *Project) GoRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
|
|||||||
if err := build.Process.Kill(); err != nil {
|
if err := build.Process.Kill(); err != nil {
|
||||||
log.Fatal(Red("Failed to stop: "), Red(err))
|
log.Fatal(Red("Failed to stop: "), Red(err))
|
||||||
}
|
}
|
||||||
log.Println(pname(p.Name, 2), ":", RedS("Stopped"))
|
log.Println(pname(p.Name, 2), ":", RedS("Ended"))
|
||||||
wr.Done()
|
wr.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -50,7 +37,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
|
||||||
@ -66,7 +52,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, Bp.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)
|
||||||
@ -83,7 +79,7 @@ func (p *Project) GoRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GoBuild is an implementation of the "go build"
|
// GoBuild is an implementation of the "go build"
|
||||||
func (p *Project) GoBuild() (error, string) {
|
func (p *Project) GoBuild() (string, error) {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
build := exec.Command("go", "build")
|
build := exec.Command("go", "build")
|
||||||
@ -91,27 +87,27 @@ func (p *Project) GoBuild() (error, string) {
|
|||||||
build.Stdout = &out
|
build.Stdout = &out
|
||||||
build.Stderr = &stderr
|
build.Stderr = &stderr
|
||||||
if err := build.Run(); err != nil {
|
if err := build.Run(); err != nil {
|
||||||
return err, stderr.String()
|
return stderr.String(), err
|
||||||
}
|
}
|
||||||
return nil, ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoInstall is an implementation of the "go install"
|
// GoInstall is an implementation of the "go install"
|
||||||
func (p *Project) GoInstall() (error, string) {
|
func (p *Project) GoInstall() (string, error) {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
err := os.Setenv("GOBIN", filepath.Join(os.Getenv("GOPATH"), "bin"))
|
err := os.Setenv("GOBIN", filepath.Join(os.Getenv("GOPATH"), "bin"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ""
|
return "", nil
|
||||||
}
|
}
|
||||||
build := exec.Command("go", "install")
|
build := exec.Command("go", "install")
|
||||||
build.Dir = p.base
|
build.Dir = p.base
|
||||||
build.Stdout = &out
|
build.Stdout = &out
|
||||||
build.Stderr = &stderr
|
build.Stderr = &stderr
|
||||||
if err := build.Run(); err != nil {
|
if err := build.Run(); err != nil {
|
||||||
return err, stderr.String()
|
return stderr.String(), err
|
||||||
}
|
}
|
||||||
return nil, ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoFmt is an implementation of the gofmt
|
// GoFmt is an implementation of the gofmt
|
||||||
@ -126,3 +122,30 @@ func (p *Project) GoFmt(path string) (io.Writer, error) {
|
|||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoTest is an implementation of the go test
|
||||||
|
func (p *Project) GoTest(path string) (io.Writer, error) {
|
||||||
|
var out bytes.Buffer
|
||||||
|
build := exec.Command("go", "test")
|
||||||
|
build.Dir = path
|
||||||
|
build.Stdout = &out
|
||||||
|
build.Stderr = &out
|
||||||
|
if err := build.Run(); err != nil {
|
||||||
|
return build.Stdout, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cmd exec a list of defined commands
|
||||||
|
func (p *Project) Cmd(cmds []string) (errors []error) {
|
||||||
|
for _, cmd := range cmds {
|
||||||
|
cmd := strings.Replace(strings.Replace(cmd, "'", "", -1), "\"", "", -1)
|
||||||
|
c := strings.Split(cmd, " ")
|
||||||
|
build := exec.Command(c[0], c[1:]...)
|
||||||
|
build.Dir = p.base
|
||||||
|
if err := build.Run(); err != nil {
|
||||||
|
errors = append(errors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors
|
||||||
|
}
|
62
cli/main.go
Normal file
62
cli/main.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Bp *Blueprint
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Green, Red Bold, Red, Blue, Blue Bold, Yellow, Yellow Bold, Magenta, Magenta Bold colors
|
||||||
|
var Green, Red, RedS, Blue, BlueS, Yellow, YellowS, Magenta, MagentaS = color.New(color.FgGreen, color.Bold).SprintFunc(),
|
||||||
|
color.New(color.FgRed, color.Bold).SprintFunc(),
|
||||||
|
color.New(color.FgRed).SprintFunc(),
|
||||||
|
color.New(color.FgBlue, color.Bold).SprintFunc(),
|
||||||
|
color.New(color.FgBlue).SprintFunc(),
|
||||||
|
color.New(color.FgYellow, color.Bold).SprintFunc(),
|
||||||
|
color.New(color.FgYellow).SprintFunc(),
|
||||||
|
color.New(color.FgMagenta, color.Bold).SprintFunc(),
|
||||||
|
color.New(color.FgMagenta).SprintFunc()
|
||||||
|
|
||||||
|
// Projects struct contains a projects list
|
||||||
|
type Blueprint struct {
|
||||||
|
Projects []Project `yaml:"Projects,omitempty"`
|
||||||
|
Files map[string]string `yaml:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watcher struct defines the livereload's logic
|
||||||
|
type Watcher struct {
|
||||||
|
// different before and after on re-run?
|
||||||
|
Before []string `yaml:"before,omitempty"`
|
||||||
|
After []string `yaml:"after,omitempty"`
|
||||||
|
Paths []string `yaml:"paths,omitempty"`
|
||||||
|
Ignore []string `yaml:"ignore_paths,omitempty"`
|
||||||
|
Exts []string `yaml:"exts,omitempty"`
|
||||||
|
Preview bool `yaml:"preview,omitempty"`
|
||||||
|
Output map[string]bool `yaml:"output,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the application
|
||||||
|
func init() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetOutput(new(logWriter))
|
||||||
|
}
|
139
cli/utils.go
Normal file
139
cli/utils.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"gopkg.in/urfave/cli.v2"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wdir returns the name last element of the working directory path
|
||||||
|
func Wdir() string {
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(Red(err))
|
||||||
|
}
|
||||||
|
return filepath.Base(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(Red(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 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))
|
||||||
|
}
|
@ -1,63 +1,20 @@
|
|||||||
package realize
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
"gopkg.in/urfave/cli.v2"
|
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The Watcher struct defines the livereload's logic
|
|
||||||
type Watcher struct {
|
|
||||||
// different before and after on re-run?
|
|
||||||
Before []string `yaml:"before,omitempty"`
|
|
||||||
After []string `yaml:"after,omitempty"`
|
|
||||||
Paths []string `yaml:"paths,omitempty"`
|
|
||||||
Ignore []string `yaml:"ignore_paths,omitempty"`
|
|
||||||
Exts []string `yaml:"exts,omitempty"`
|
|
||||||
Preview bool `yaml:"preview,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
|
||||||
func (p *Project) watching() {
|
func (p *Project) watching() {
|
||||||
|
|
||||||
@ -78,8 +35,14 @@ func (p *Project) watching() {
|
|||||||
}
|
}
|
||||||
defer end()
|
defer end()
|
||||||
|
|
||||||
p.walks(watcher)
|
p.cmd()
|
||||||
go routines(p, channel, &wr)
|
err = p.walks(watcher)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(pname(p.Name, 1), ":", Red(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
@ -101,7 +64,7 @@ func (p *Project) watching() {
|
|||||||
|
|
||||||
i := strings.Index(event.Name, filepath.Ext(event.Name))
|
i := strings.Index(event.Name, filepath.Ext(event.Name))
|
||||||
if event.Name[:i] != "" && inArray(ext, p.Watcher.Exts) {
|
if event.Name[:i] != "" && inArray(ext, p.Watcher.Exts) {
|
||||||
log.Println(pname(p.Name, 4), ":", Magenta(event.Name[:i]+ext))
|
fmt.Println(pname(p.Name, 4), Magenta(strings.ToUpper(ext[1:])+" changed"), Magenta(event.Name[:i]+ext))
|
||||||
// stop and run again
|
// stop and run again
|
||||||
if p.Run {
|
if p.Run {
|
||||||
close(channel)
|
close(channel)
|
||||||
@ -112,7 +75,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,11 +92,11 @@ func (p *Project) install(channel chan bool, wr *sync.WaitGroup) {
|
|||||||
if p.Bin {
|
if p.Bin {
|
||||||
log.Println(pname(p.Name, 1), ":", "Installing..")
|
log.Println(pname(p.Name, 1), ":", "Installing..")
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err, std := p.GoInstall(); err != nil {
|
if std, err := p.GoInstall(); err != nil {
|
||||||
log.Println(pname(p.Name, 1), ":", fmt.Sprint(Red(err)), std)
|
log.Println(pname(p.Name, 1), ":", fmt.Sprint(Red(err)), std)
|
||||||
wr.Done()
|
wr.Done()
|
||||||
} else {
|
} else {
|
||||||
log.Println(pname(p.Name, 5), ":", Green("Installed")+" after", MagentaS(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), "s"))
|
log.Println(pname(p.Name, 5), ":", Green("Installed")+" after", MagentaS(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
|
||||||
if p.Run {
|
if p.Run {
|
||||||
runner := make(chan bool, 1)
|
runner := make(chan bool, 1)
|
||||||
log.Println(pname(p.Name, 1), ":", "Running..")
|
log.Println(pname(p.Name, 1), ":", "Running..")
|
||||||
@ -142,7 +105,7 @@ func (p *Project) install(channel chan bool, wr *sync.WaitGroup) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-runner:
|
case <-runner:
|
||||||
log.Println(pname(p.Name, 5), ":", Green("Has been run")+" after", MagentaS(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), "s"))
|
log.Println(pname(p.Name, 5), ":", Green("Has been run")+" after", MagentaS(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,29 +120,67 @@ func (p *Project) build() {
|
|||||||
if p.Build {
|
if p.Build {
|
||||||
log.Println(pname(p.Name, 1), ":", "Building..")
|
log.Println(pname(p.Name, 1), ":", "Building..")
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err, std := p.GoBuild(); err != nil {
|
if std, err := p.GoBuild(); err != nil {
|
||||||
log.Println(pname(p.Name, 1), ":", fmt.Sprint(Red(err)), std)
|
log.Println(pname(p.Name, 1), ":", fmt.Sprint(Red(err)), std)
|
||||||
} else {
|
} else {
|
||||||
log.Println(pname(p.Name, 5), ":", Green("Builded")+" after", MagentaS(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), "s"))
|
log.Println(pname(p.Name, 5), ":", Green("Builded")+" after", MagentaS(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build calls an implementation of the "gofmt"
|
// Fmt calls an implementation of the "gofmt"
|
||||||
func (p *Project) fmt(path string) error {
|
func (p *Project) fmt(path string) error {
|
||||||
if p.Fmt {
|
if p.Fmt {
|
||||||
if _, err := p.GoFmt(path); err != nil {
|
if _, err := p.GoFmt(path); err != nil {
|
||||||
log.Println(pname(p.Name, 1), Red("There are some GoFmt errors in "), ":", Magenta(path))
|
log.Println(pname(p.Name, 1), Red("There are some GoFmt errors in "), ":", Magenta(path))
|
||||||
//fmt.Println(msg)
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cmd calls an wrapper for execute the commands after/before
|
||||||
|
func (p *Project) cmd() {
|
||||||
|
c := make(chan os.Signal, 2)
|
||||||
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
|
cast := func(commands []string) {
|
||||||
|
if errs := p.Cmd(commands); errs != nil {
|
||||||
|
for _, err := range errs {
|
||||||
|
log.Println(pname(p.Name, 2), Red(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.Watcher.Before) > 0 {
|
||||||
|
cast(p.Watcher.Before)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-c:
|
||||||
|
if len(p.Watcher.After) > 0 {
|
||||||
|
cast(p.Watcher.After)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test calls an implementation of the "go test"
|
||||||
|
func (p *Project) test(path string) error {
|
||||||
|
if p.Test {
|
||||||
|
if _, err := p.GoTest(path); err != nil {
|
||||||
|
log.Println(pname(p.Name, 1), Red("Go Test fails in "), ":", Magenta(path))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walks the file tree of a project
|
// Walks the file tree of a project
|
||||||
func (p *Project) walks(watcher *fsnotify.Watcher) {
|
func (p *Project) walks(watcher *fsnotify.Watcher) error {
|
||||||
var files, folders int64
|
var files, folders int64
|
||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
|
|
||||||
@ -202,6 +203,11 @@ func (p *Project) walks(watcher *fsnotify.Watcher) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
folders++
|
folders++
|
||||||
|
go func() {
|
||||||
|
if err := p.test(path); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,10 +216,13 @@ func (p *Project) walks(watcher *fsnotify.Watcher) {
|
|||||||
|
|
||||||
if p.Path == "." || p.Path == "/" {
|
if p.Path == "." || p.Path == "/" {
|
||||||
p.base = wd
|
p.base = wd
|
||||||
p.Path = WorkingDir()
|
p.Path = Wdir()
|
||||||
|
} else if filepath.IsAbs(p.Path) {
|
||||||
|
p.base = p.Path
|
||||||
} else {
|
} else {
|
||||||
p.base = filepath.Join(wd, p.Path)
|
p.base = filepath.Join(wd, p.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dir := range p.Watcher.Paths {
|
for _, dir := range p.Watcher.Paths {
|
||||||
base := filepath.Join(p.base, dir)
|
base := filepath.Join(p.base, dir)
|
||||||
if _, err := os.Stat(base); err == nil {
|
if _, err := os.Stat(base); err == nil {
|
||||||
@ -221,11 +230,11 @@ func (p *Project) walks(watcher *fsnotify.Watcher) {
|
|||||||
log.Println(Red(err.Error()))
|
log.Println(Red(err.Error()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(pname(p.Name, 1), ":\t", Red(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(pname(p.Name, 1), Red("Watching"), Magenta(files), "file/s", Magenta(folders), "folder/s")
|
||||||
fmt.Println()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore validates a path
|
// Ignore validates a path
|
||||||
@ -239,41 +248,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
|
|
||||||
}
|
|
@ -2,37 +2,79 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
r "github.com/tockins/realize/realize"
|
c "github.com/tockins/realize/cli"
|
||||||
|
s "github.com/tockins/realize/server"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"gopkg.in/urfave/cli.v2"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var App Realize
|
||||||
|
|
||||||
|
// Realize struct contains the general app informations
|
||||||
|
type Realize struct {
|
||||||
|
Name, Description, Author, Email string
|
||||||
|
Version string
|
||||||
|
Limit uint64
|
||||||
|
Blueprint c.Blueprint
|
||||||
|
Server s.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flimit defines the max number of watched files
|
||||||
|
func (r *Realize) Increases() {
|
||||||
|
// 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(c.Red("Error Setting Rlimit "), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
Blueprint: c.Blueprint{
|
||||||
|
Files: map[string]string{
|
||||||
|
"config": "r.config.yaml",
|
||||||
|
"output": "r.output.log",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
App.Increases()
|
||||||
|
c.Bp = &App.Blueprint
|
||||||
|
s.Bp = &App.Blueprint
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
app := r.Info()
|
|
||||||
|
|
||||||
handle := func(err error) error {
|
handle := func(err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(r.Red(err.Error()))
|
fmt.Println(c.Red(err.Error()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header := func() error {
|
header := func() error {
|
||||||
fmt.Println(r.Blue(app.Name) + " - " + r.Blue(app.Version))
|
fmt.Println(c.Blue(App.Name) + " - " + c.Blue(App.Version))
|
||||||
fmt.Println(r.BlueS(app.Description) + "\n")
|
fmt.Println(c.BlueS(App.Description) + "\n")
|
||||||
gopath := os.Getenv("GOPATH")
|
gopath := os.Getenv("GOPATH")
|
||||||
if gopath == "" {
|
if gopath == "" {
|
||||||
log.Fatal(r.Red("$GOPATH isn't set up properly"))
|
log.Fatal(c.Red("$GOPATH isn't set up properly"))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cli := &cli.App{
|
cli := &cli.App{
|
||||||
Name: app.Name,
|
Name: App.Name,
|
||||||
Version: app.Version,
|
Version: App.Version,
|
||||||
Authors: []*cli.Author{
|
Authors: []*cli.Author{
|
||||||
{
|
{
|
||||||
Name: "Alessio Pracchia",
|
Name: "Alessio Pracchia",
|
||||||
@ -43,14 +85,13 @@ func main() {
|
|||||||
Email: "conventi@hastega.it",
|
Email: "conventi@hastega.it",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Usage: app.Description,
|
Usage: App.Description,
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
{
|
{
|
||||||
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()
|
||||||
@ -59,17 +100,20 @@ 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.BoolFlag{Name: "build", Value: false, Usage: "Enables the build"},
|
&cli.BoolFlag{Name: "build", Value: false, Usage: "Enables the build"},
|
||||||
&cli.BoolFlag{Name: "no-run", Usage: "Disables the run"},
|
&cli.BoolFlag{Name: "no-run", Usage: "Disables the run"},
|
||||||
&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: "config", Value: false, Usage: "Take the defined settings if exist a config file."},
|
&cli.BoolFlag{Name: "test", Value: false, Usage: "Enable the tests"},
|
||||||
|
&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))
|
App.Server.Start()
|
||||||
|
return handle(App.Blueprint.Fast(p))
|
||||||
},
|
},
|
||||||
Before: func(c *cli.Context) error {
|
Before: func(c *cli.Context) error {
|
||||||
header()
|
header()
|
||||||
@ -78,20 +122,20 @@ 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: c.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 go 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"},
|
||||||
&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"},
|
||||||
},
|
},
|
||||||
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()
|
||||||
@ -100,15 +144,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()
|
||||||
@ -117,12 +160,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()
|
@ -1,92 +0,0 @@
|
|||||||
package realize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Default values and info
|
|
||||||
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
|
|
||||||
|
|
||||||
// Green color bold
|
|
||||||
var Green = color.New(color.FgGreen, color.Bold).SprintFunc()
|
|
||||||
|
|
||||||
// Red color bold
|
|
||||||
var Red = color.New(color.FgRed, color.Bold).SprintFunc()
|
|
||||||
|
|
||||||
// RedS color used for errors
|
|
||||||
var RedS = color.New(color.FgRed).SprintFunc()
|
|
||||||
|
|
||||||
// Blue color bold used for project output
|
|
||||||
var Blue = color.New(color.FgBlue, color.Bold).SprintFunc()
|
|
||||||
|
|
||||||
// BlueS color
|
|
||||||
var BlueS = color.New(color.FgBlue).SprintFunc()
|
|
||||||
|
|
||||||
// Yellow color bold
|
|
||||||
var Yellow = color.New(color.FgYellow, color.Bold).SprintFunc()
|
|
||||||
|
|
||||||
// YellowS color
|
|
||||||
var YellowS = color.New(color.FgYellow).SprintFunc()
|
|
||||||
|
|
||||||
// MagentaS color
|
|
||||||
var MagentaS = color.New(color.FgMagenta).SprintFunc()
|
|
||||||
|
|
||||||
// Magenta color bold
|
|
||||||
var Magenta = color.New(color.FgMagenta, color.Bold).SprintFunc()
|
|
||||||
|
|
||||||
// WatcherIgnores is an array of default ignored paths
|
|
||||||
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() {
|
|
||||||
log.SetFlags(0)
|
|
||||||
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))
|
|
||||||
}
|
|
@ -1,216 +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")),
|
|
||||||
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) (error, Project) {
|
|
||||||
for _, val := range arr {
|
|
||||||
if value.Path == val.Path || value.Name == val.Name {
|
|
||||||
return errors.New("There is a duplicate of '" + val.Name + "'. Check your config file!"), val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, Project{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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")),
|
|
||||||
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("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
|
|
||||||
}
|
|
1
server/assets/index.html
Normal file
1
server/assets/index.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
Testing
|
239
server/data.go
Normal file
239
server/data.go
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
// Code generated by go-bindata.
|
||||||
|
// sources:
|
||||||
|
// server/assets/index.html
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||||
|
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err = io.Copy(&buf, gz)
|
||||||
|
clErr := gz.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||||
|
}
|
||||||
|
if clErr != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type asset struct {
|
||||||
|
bytes []byte
|
||||||
|
info os.FileInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type bindataFileInfo struct {
|
||||||
|
name string
|
||||||
|
size int64
|
||||||
|
mode os.FileMode
|
||||||
|
modTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi bindataFileInfo) Name() string {
|
||||||
|
return fi.name
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Size() int64 {
|
||||||
|
return fi.size
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||||
|
return fi.mode
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) ModTime() time.Time {
|
||||||
|
return fi.modTime
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) IsDir() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Sys() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _serverAssetsIndexHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x0a\x49\x2d\x2e\xc9\xcc\x4b\x07\x04\x00\x00\xff\xff\x9a\x63\x4e\x27\x07\x00\x00\x00")
|
||||||
|
|
||||||
|
func serverAssetsIndexHtmlBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
_serverAssetsIndexHtml,
|
||||||
|
"server/assets/index.html",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverAssetsIndexHtml() (*asset, error) {
|
||||||
|
bytes, err := serverAssetsIndexHtmlBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{name: "server/assets/index.html", size: 7, mode: os.FileMode(420), modTime: time.Unix(1472831748, 0)}
|
||||||
|
a := &asset{bytes: bytes, info: info}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asset loads and returns the asset for the given name.
|
||||||
|
// It returns an error if the asset could not be found or
|
||||||
|
// could not be loaded.
|
||||||
|
func Asset(name string) ([]byte, error) {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
if f, ok := _bindata[cannonicalName]; ok {
|
||||||
|
a, err := f()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||||
|
}
|
||||||
|
return a.bytes, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Asset %s not found", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustAsset is like Asset but panics when Asset would return an error.
|
||||||
|
// It simplifies safe initialization of global variables.
|
||||||
|
func MustAsset(name string) []byte {
|
||||||
|
a, err := Asset(name)
|
||||||
|
if err != nil {
|
||||||
|
panic("asset: Asset(" + name + "): " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetInfo loads and returns the asset info for the given name.
|
||||||
|
// It returns an error if the asset could not be found or
|
||||||
|
// could not be loaded.
|
||||||
|
func AssetInfo(name string) (os.FileInfo, error) {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
if f, ok := _bindata[cannonicalName]; ok {
|
||||||
|
a, err := f()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||||
|
}
|
||||||
|
return a.info, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetNames returns the names of the assets.
|
||||||
|
func AssetNames() []string {
|
||||||
|
names := make([]string, 0, len(_bindata))
|
||||||
|
for name := range _bindata {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||||
|
var _bindata = map[string]func() (*asset, error){
|
||||||
|
"server/assets/index.html": serverAssetsIndexHtml,
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetDir returns the file names below a certain
|
||||||
|
// directory embedded in the file by go-bindata.
|
||||||
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
|
// following hierarchy:
|
||||||
|
// data/
|
||||||
|
// foo.txt
|
||||||
|
// img/
|
||||||
|
// a.png
|
||||||
|
// b.png
|
||||||
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
// AssetDir("") will return []string{"data"}.
|
||||||
|
func AssetDir(name string) ([]string, error) {
|
||||||
|
node := _bintree
|
||||||
|
if len(name) != 0 {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
pathList := strings.Split(cannonicalName, "/")
|
||||||
|
for _, p := range pathList {
|
||||||
|
node = node.Children[p]
|
||||||
|
if node == nil {
|
||||||
|
return nil, fmt.Errorf("Asset %s not found", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if node.Func != nil {
|
||||||
|
return nil, fmt.Errorf("Asset %s not found", name)
|
||||||
|
}
|
||||||
|
rv := make([]string, 0, len(node.Children))
|
||||||
|
for childName := range node.Children {
|
||||||
|
rv = append(rv, childName)
|
||||||
|
}
|
||||||
|
return rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type bintree struct {
|
||||||
|
Func func() (*asset, error)
|
||||||
|
Children map[string]*bintree
|
||||||
|
}
|
||||||
|
|
||||||
|
var _bintree = &bintree{nil, map[string]*bintree{
|
||||||
|
"server": {nil, map[string]*bintree{
|
||||||
|
"assets": {nil, map[string]*bintree{
|
||||||
|
"index.html": {serverAssetsIndexHtml, map[string]*bintree{}},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
}}
|
||||||
|
|
||||||
|
// RestoreAsset restores an asset under the given directory
|
||||||
|
func RestoreAsset(dir, name string) error {
|
||||||
|
data, err := Asset(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, err := AssetInfo(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreAssets restores an asset under the given directory recursively
|
||||||
|
func RestoreAssets(dir, name string) error {
|
||||||
|
children, err := AssetDir(name)
|
||||||
|
// File
|
||||||
|
if err != nil {
|
||||||
|
return RestoreAsset(dir, name)
|
||||||
|
}
|
||||||
|
// Dir
|
||||||
|
for _, child := range children {
|
||||||
|
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func _filePath(dir, name string) string {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||||
|
}
|
57
server/main.go
Normal file
57
server/main.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo"
|
||||||
|
"github.com/labstack/echo/engine/standard"
|
||||||
|
"github.com/labstack/echo/middleware"
|
||||||
|
c "github.com/tockins/realize/cli"
|
||||||
|
"golang.org/x/net/websocket"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Bp *c.Blueprint
|
||||||
|
|
||||||
|
// Server struct contains server informations
|
||||||
|
type Server struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func render(c echo.Context, path string) error {
|
||||||
|
data, err := Asset(path)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound)
|
||||||
|
}
|
||||||
|
rs := c.Response()
|
||||||
|
rs.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
|
||||||
|
rs.WriteHeader(http.StatusOK)
|
||||||
|
rs.Write(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start() {
|
||||||
|
e := echo.New()
|
||||||
|
e.Use(middleware.Gzip())
|
||||||
|
e.GET("/", func(c echo.Context) error {
|
||||||
|
return render(c, "server/assets/index.html")
|
||||||
|
})
|
||||||
|
|
||||||
|
e.GET("/projects", standard.WrapHandler(projects()))
|
||||||
|
go e.Run(standard.New(":5000"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The WebSocket for projects list
|
||||||
|
func projects() websocket.Handler {
|
||||||
|
return websocket.Handler(func(ws *websocket.Conn) {
|
||||||
|
for {
|
||||||
|
err := websocket.Message.Send(ws, "Hello")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
msg := ""
|
||||||
|
err = websocket.Message.Receive(ws, &msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
33
server/open.go
Normal file
33
server/open.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cli map[string]string
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cli = map[string]string{
|
||||||
|
"windows": "start",
|
||||||
|
"darwin": "open",
|
||||||
|
"linux": "xdg-open",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Open(url string) (io.Writer, error) {
|
||||||
|
if open, err := cli[runtime.GOOS]; !err {
|
||||||
|
return nil, errors.New("This operating system is not supported.")
|
||||||
|
} else {
|
||||||
|
cmd := exec.Command(open, url)
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return cmd.Stderr, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user