commit
ca6057cde6
34
README.md
34
README.md
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
|
||||||
arr := strings.Fields(param)
|
for _, param := range p.Params {
|
||||||
params = append(params, arr...)
|
arr := strings.Fields(param)
|
||||||
}
|
params = append(params, arr...)
|
||||||
build = exec.Command(filepath.Join(os.Getenv("GOBIN"), filepath.Base(p.path)), params...)
|
}
|
||||||
} else {
|
if _, err := os.Stat(filepath.Join(p.base, p.path)); err == nil {
|
||||||
build = exec.Command(filepath.Join(os.Getenv("GOBIN"), filepath.Base(p.path)))
|
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...)
|
||||||
|
} else {
|
||||||
|
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, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
|
||||||
if p.Run {
|
|
||||||
runner := make(chan bool, 1)
|
|
||||||
log.Println(p.pname(p.Name, 1), ":", "Running..")
|
|
||||||
start = time.Now()
|
|
||||||
go p.goRun(channel, runner, wr)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
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"))
|
|
||||||
out := BufferOut{Time: time.Now(), Text: "Has been run"}
|
|
||||||
p.print("log", out, msg, stream)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
p.sync()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Project) run(channel chan bool, wr *sync.WaitGroup) {
|
||||||
|
if p.Run {
|
||||||
|
start := time.Now()
|
||||||
|
runner := make(chan bool, 1)
|
||||||
|
log.Println(p.pname(p.Name, 1), ":", "Running..")
|
||||||
|
go p.goRun(channel, runner, wr)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
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"))
|
||||||
|
out := BufferOut{Time: time.Now(), Text: "Has been run"}
|
||||||
|
p.print("log", out, msg, "")
|
||||||
|
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, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user