Merge pull request #32 from tockins/dev

v1.2.1
This commit is contained in:
Alessio Pracchia 2016-12-17 01:58:08 +01:00 committed by GitHub
commit ca6057cde6
8 changed files with 100 additions and 87 deletions

View File

@ -14,27 +14,15 @@ A Go build system with file watchers, output streams and live reload. Run, build
![Preview](http://i.imgur.com/dJbNZjt.gif) ![Preview](http://i.imgur.com/dJbNZjt.gif)
#### What's new
##### v1.2
- [x] Windows support
- [x] Go generate support
- [x] Bugs fix
- [x] Web panel errors log improved
- [x] Refactoring
- [x] Web panel edit settings, partial
#### Features #### Features
- Build, Install, Test, Fmt and Run at the same time
- Live reload on file changes (re-build, re-install and re-run)
- Watch custom paths
- Watch specific file extensions
- Multiple projects support
- Output streams
- Execution times
- Highly customizable - Highly customizable
- Fast run - Build, Install, Test, Fmt, Generate and Run at the same time
- Live reload on file changes (re-build, re-install...)
- Watch custom paths and specific file extensions
- Support for multiple projects
- Output streams and error logs (Watch them in console or save them on a file)
- Web Panel (Watch all projects, edit the config settings, download each type of log)
#### Installation and usage #### Installation and usage
@ -186,12 +174,16 @@ A Go build system with file watchers, output streams and live reload. Run, build
errors: false // saves the errors of the project in a file errors: false // saves the errors of the project in a file
``` ```
#### Next release #### Next features, in progress...
##### v1.3 - [ ] Web panel - edit settings (full support)
- [ ] Web panel edit settings, full support - [ ] Web panel - logs download
- [ ] Schedule - reload a project after a specific time
- [ ] Easy dependencies - automatically resolve the project dependencies
- [ ] Import license - retrieve the license for each imported library
- [ ] Tests - [ ] Tests
#### Contacts #### Contacts
- Chat with us [Gitter](https://gitter.im/tockins/realize) - Chat with us [Gitter](https://gitter.im/tockins/realize)

View File

@ -12,12 +12,11 @@ import (
const ( const (
name = "Realize" name = "Realize"
version = "1.2" version = "1.2.1"
description = "A Go build system with file watchers, output streams and live reload. Run, build and watch file changes with custom paths" description = "A Go build system with file watchers, output streams and live reload. Run, build and watch file changes with custom paths"
config = "realize.yaml" config = "realize.yaml"
output = "outputs.log" output = "outputs.log"
log = "logs.log" log = "logs.log"
err = "errors.log"
host = "localhost" host = "localhost"
port = 5000 port = 5000
server = true server = true

View File

@ -1,4 +1,3 @@
// +build !windows // +build !windows
package settings package settings
@ -12,6 +11,6 @@ func (s *Settings) Flimit() {
rLimit.Cur = s.Config.Flimit rLimit.Cur = s.Config.Flimit
err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
if err != nil { if err != nil {
s.Fatal("Error Setting Rlimit", err) s.Fatal(err, "Error setting rlimit")
} }
} }

View File

@ -3,6 +3,7 @@ package settings
import ( import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
) )
// Scan return a byte stream of a given file // Scan return a byte stream of a given file
@ -23,7 +24,13 @@ func (s Settings) Write(name string, data []byte) error {
} }
// Create a new file and return its pointer // Create a new file and return its pointer
func (s Settings) Create(file string) *os.File { func (s Settings) Create(path string, name string) *os.File {
var file string
if _, err := os.Stat(".realize/"); err == nil {
file = filepath.Join(path, ".realize/", name)
} else {
file = filepath.Join(path, name)
}
out, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0655) out, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0655)
s.Validate(err) s.Validate(err)
return out return out

View File

@ -2,6 +2,7 @@ package settings
import ( import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"os"
) )
type Settings struct { type Settings struct {
@ -28,9 +29,13 @@ type Resources struct {
Log string `yaml:"log" json:"log"` Log string `yaml:"log" json:"log"`
} }
// Read from the configuration file // Read from config file
func (s *Settings) Read(out interface{}) error { func (s *Settings) Read(out interface{}) error {
content, err := s.Stream(s.Resources.Config) localConfigPath := s.Resources.Config
if _, err := os.Stat(".realize/" + s.Resources.Config); err == nil {
localConfigPath = ".realize/" + s.Resources.Config
}
content, err := s.Stream(localConfigPath)
if err == nil { if err == nil {
err = yaml.Unmarshal(content, out) err = yaml.Unmarshal(content, out)
return err return err
@ -39,10 +44,15 @@ func (s *Settings) Read(out interface{}) error {
} }
// Record create and unmarshal the yaml config file // Record create and unmarshal the yaml config file
func (h *Settings) Record(out interface{}) error { func (s *Settings) Record(out interface{}) error {
y, err := yaml.Marshal(out) y, err := yaml.Marshal(out)
if err != nil { if err != nil {
return err return err
} }
return h.Write(h.Resources.Config, y) if _, err := os.Stat(".realize/"); os.IsNotExist(err) {
if err = os.Mkdir(".realize/", 0770); err != nil {
return s.Write(s.Resources.Config, y)
}
}
return s.Write(".realize/"+s.Resources.Config, y)
} }

View File

@ -14,14 +14,14 @@ func (s Settings) Wdir() string {
func (s Settings) Validate(err error) error { func (s Settings) Validate(err error) error {
if err != nil { if err != nil {
s.Fatal("", err) s.Fatal(err, "")
} }
return nil return nil
} }
func (s Settings) Fatal(msg string, err error) { func (s Settings) Fatal(err error, msg ...interface{}) {
if msg != "" { if len(msg) > 0 {
log.Fatal(s.Red.Regular(msg), err.Error()) log.Fatalln(s.Red.Regular(msg...), err.Error())
} }
log.Fatal(err.Error()) log.Fatalln(err.Error())
} }

View File

@ -16,21 +16,34 @@ import (
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 {
var build *exec.Cmd var build *exec.Cmd
if len(p.Params) != 0 {
var params []string var params []string
var path = ""
for _, param := range p.Params { for _, param := range p.Params {
arr := strings.Fields(param) arr := strings.Fields(param)
params = append(params, arr...) params = append(params, arr...)
} }
if _, err := os.Stat(filepath.Join(p.base, p.path)); err == nil {
path = filepath.Join(p.base, p.path)
}
if _, err := os.Stat(filepath.Join(p.base, p.path+".exe")); err == nil {
path = filepath.Join(p.base, p.path+".exe")
}
if path != "" {
build = exec.Command(path, params...)
} else {
if _, err := os.Stat(filepath.Join(os.Getenv("GOBIN"), filepath.Base(p.path))); err == nil {
build = exec.Command(filepath.Join(os.Getenv("GOBIN"), filepath.Base(p.path)), params...) build = exec.Command(filepath.Join(os.Getenv("GOBIN"), filepath.Base(p.path)), params...)
} else { } else {
build = exec.Command(filepath.Join(os.Getenv("GOBIN"), filepath.Base(p.path))) p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Can't run a not compiled project"})
p.Fatal(err, "Can't run a not compiled project", ":")
}
} }
build.Dir = p.base
defer func() { defer func() {
if err := build.Process.Kill(); err != nil { if err := build.Process.Kill(); err != nil {
p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Failed to stop: " + err.Error()}) p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Failed to stop: " + err.Error()})
p.Fatal("Failed to stop:", err) p.Fatal(err, "Failed to stop", ":")
} }
p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Ended"}) p.Buffer.StdLog = append(p.Buffer.StdLog, BufferOut{Time: time.Now(), Text: "Ended"})
log.Println(p.pname(p.Name, 2), ":", p.Red.Regular("Ended")) log.Println(p.pname(p.Name, 2), ":", p.Red.Regular("Ended"))
@ -68,11 +81,10 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
log.Println(p.pname(p.Name, 3), ":", p.Blue.Regular(output.Text())) log.Println(p.pname(p.Name, 3), ":", p.Blue.Regular(output.Text()))
} }
if p.File.Streams { if p.File.Streams {
path := filepath.Join(p.base, p.Resources.Output) f := p.Create(p.base, p.parent.Resources.Output)
f := p.Create(path)
t := time.Now() t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + output.Text() + "\r\n"); err != nil { if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + output.Text() + "\r\n"); err != nil {
p.Fatal("", err) p.Fatal(err, "")
} }
} }
} }

View File

@ -26,7 +26,6 @@ func (p *Project) watching() {
defer func() { defer func() {
wg.Done() wg.Done()
}() }()
if err != nil { if err != nil {
log.Fatalln(p.pname(p.Name, 2), ":", p.Red.Bold(err.Error())) log.Fatalln(p.pname(p.Name, 2), ":", p.Red.Bold(err.Error()))
return return
@ -85,51 +84,47 @@ func (p *Project) watching() {
} }
// Install calls an implementation of the "go install" // Install calls an implementation of the "go install"
func (p *Project) install(channel chan bool, wr *sync.WaitGroup) { func (p *Project) install() {
defer func() {
p.sync()
}()
if p.Bin { if p.Bin {
log.Println(p.pname(p.Name, 1), ":", "Installing..")
start := time.Now() start := time.Now()
log.Println(p.pname(p.Name, 1), ":", "Installing..")
if stream, err := p.goInstall(); err != nil { if stream, err := p.goInstall(); err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Install"), p.Red.Regular(err.Error())) msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Install"), p.Red.Regular(err.Error()))
out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Install", Stream: stream} out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Install", Stream: stream}
p.print("error", out, msg, stream) p.print("error", out, msg, stream)
wr.Done()
} else { } else {
msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Installed")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Installed")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
out := BufferOut{Time: time.Now(), Text: "Installed"} out := BufferOut{Time: time.Now(), Text: "Installed"}
p.print("log", out, msg, stream) p.print("log", out, msg, stream)
}
p.sync()
}
return
}
func (p *Project) run(channel chan bool, wr *sync.WaitGroup) {
if p.Run { if p.Run {
start := time.Now()
runner := make(chan bool, 1) runner := make(chan bool, 1)
log.Println(p.pname(p.Name, 1), ":", "Running..") log.Println(p.pname(p.Name, 1), ":", "Running..")
start = time.Now()
go p.goRun(channel, runner, wr) go p.goRun(channel, runner, wr)
for { for {
select { select {
case <-runner: case <-runner:
msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Has been run")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s")) msg := fmt.Sprintln(p.pname(p.Name, 5), ":", p.Green.Regular("Has been run")+" after", p.Magenta.Regular(big.NewFloat(float64(time.Since(start).Seconds())).Text('f', 3), " s"))
out := BufferOut{Time: time.Now(), Text: "Has been run"} out := BufferOut{Time: time.Now(), Text: "Has been run"}
p.print("log", out, msg, stream) p.print("log", out, msg, "")
return return
} }
} }
} }
}
}
return
} }
// Build calls an implementation of the "go build" // Build calls an implementation of the "go build"
func (p *Project) build() { func (p *Project) build() {
defer func() {
p.sync()
}()
if p.Build { if p.Build {
log.Println(p.pname(p.Name, 1), ":", "Building..")
start := time.Now() start := time.Now()
log.Println(p.pname(p.Name, 1), ":", "Building..")
if stream, err := p.goBuild(); err != nil { if stream, err := p.goBuild(); err != nil {
msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Build"), p.Red.Regular(err.Error())) msg := fmt.Sprintln(p.pname(p.Name, 2), ":", p.Red.Bold("Go Build"), p.Red.Regular(err.Error()))
out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Build", Stream: stream} out := BufferOut{Time: time.Now(), Text: err.Error(), Type: "Go Build", Stream: stream}
@ -139,6 +134,7 @@ func (p *Project) build() {
out := BufferOut{Time: time.Now(), Text: "Builded"} out := BufferOut{Time: time.Now(), Text: "Builded"}
p.print("log", out, msg, stream) p.print("log", out, msg, stream)
} }
p.sync()
} }
return return
} }
@ -282,9 +278,10 @@ func (p *Project) ignore(str string) bool {
// Routines launches the following methods: run, build, install // Routines launches the following methods: run, build, install
func (p *Project) routines(channel chan bool, wr *sync.WaitGroup) { func (p *Project) routines(channel chan bool, wr *sync.WaitGroup) {
p.install()
p.build()
wr.Add(1) wr.Add(1)
go p.build() go p.run(channel, wr)
go p.install(channel, wr)
wr.Wait() wr.Wait()
} }
@ -315,31 +312,28 @@ func (p *Project) print(t string, o BufferOut, msg string, stream string) {
case "out": case "out":
p.Buffer.StdOut = append(p.Buffer.StdOut, o) p.Buffer.StdOut = append(p.Buffer.StdOut, o)
if p.File.Streams { if p.File.Streams {
path := filepath.Join(p.base, p.Resources.Output) f := p.Create(p.base, p.parent.Resources.Output)
f := p.Create(path)
t := time.Now() t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil { if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil {
p.Fatal("", err) p.Fatal(err, "")
} }
} }
case "log": case "log":
p.Buffer.StdLog = append(p.Buffer.StdLog, o) p.Buffer.StdLog = append(p.Buffer.StdLog, o)
if p.File.Logs { if p.File.Logs {
path := filepath.Join(p.base, p.Resources.Log) f := p.Create(p.base, p.parent.Resources.Log)
f := p.Create(path)
t := time.Now() t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil { if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil {
p.Fatal("", err) p.Fatal(err, "")
} }
} }
case "error": case "error":
p.Buffer.StdErr = append(p.Buffer.StdErr, o) p.Buffer.StdErr = append(p.Buffer.StdErr, o)
if p.File.Errors { if p.File.Errors {
path := filepath.Join(p.base, p.Resources.Log) f := p.Create(p.base, p.parent.Resources.Log)
f := p.Create(path)
t := time.Now() t := time.Now()
if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil { if _, err := f.WriteString(t.Format("2006-01-02 15:04:05") + " : " + o.Text + "\r\n"); err != nil {
p.Fatal("", err) p.Fatal(err, "")
} }
} }