commit
87918aed27
158
README.md
158
README.md
|
@ -7,47 +7,53 @@
|
|||
[![Join the chat at https://gitter.im/tockins/realize](https://badges.gitter.im/tockins/realize.svg)](https://gitter.im/tockins/realize?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/tockins/realize)](https://goreportcard.com/report/github.com/tockins/realize)
|
||||
|
||||
<p align="center">
|
||||
<img src="http://i.imgur.com/pkMDtrl.png" width="350px">
|
||||
</p>
|
||||
|
||||
![Logo](http://i.imgur.com/8nr2s1b.jpg)
|
||||
#### Realize is a Go tool that is focused to speed up and improve the developers workflow.
|
||||
|
||||
A Go build system with file watchers, output streams and live reload. Run, build and watch file changes with custom paths
|
||||
Automate your work pipeline, integrate additional tools of third party, define custom cli commands and reload projects at each changed without stop to write code.
|
||||
|
||||
<p align="center">
|
||||
<img src="http://i.imgur.com/KpMSLnE.png">
|
||||
</p>
|
||||
|
||||
![Preview](http://i.imgur.com/dJbNZjt.gif)
|
||||
|
||||
#### Features
|
||||
|
||||
- Highly customizable
|
||||
- Config your project Step by Step
|
||||
- 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
|
||||
- Watch by FsNotify or by polling
|
||||
- Setup step by step
|
||||
- Live reload
|
||||
- Support for multiple projects
|
||||
- Output streams and error logs (support for save on a file)
|
||||
- Web Panel (projects list, config settings, logs)
|
||||
- Save logs on files
|
||||
- Web panel for a smart view
|
||||
- Build, install, run, test, fmt, generate, vet and much more
|
||||
- Watch custom paths and specific file extensions
|
||||
- Multiple watching methods (Polling, File watcher)
|
||||
- Docker support
|
||||
|
||||
v 1.5
|
||||
|
||||
- [ ] Watch dependencies options
|
||||
- [ ] Watch gopath dependencies
|
||||
- [ ] Web panel, download logs
|
||||
- [ ] Multiple configurations (dev, production)
|
||||
- [ ] Support to ignore paths and files in gititnore
|
||||
- [ ] Input redirection (wait for an input and redirect)
|
||||
- [ ] Web panel full support
|
||||
- [ ] Multiple configurations
|
||||
- [ ] GoMobile support ?
|
||||
- [ ] Ignore path and files in gititnore ?
|
||||
|
||||
#### Wiki
|
||||
|
||||
- [Getting Started](#installation-and-usage)
|
||||
- [Getting Started](#installation)
|
||||
- [Run cmd](#run) - Run a project
|
||||
- [Add cmd](#add) - Add a new project
|
||||
- [Init cmd](#init) - Make a custom config step by step
|
||||
- [Remove cmd](#remove) - Remove a project
|
||||
- [List cmd](#list) - List the projects
|
||||
- [Config sample](#config-sample)
|
||||
- [Support](#support)
|
||||
- [Config sample](#config-sample) - Sample config file
|
||||
- [Support](#support-us-and-suggest-an-improvement)
|
||||
|
||||
|
||||
- ##### Installation
|
||||
#### Installation
|
||||
Run this to get/install:
|
||||
```
|
||||
$ go get github.com/tockins/realize
|
||||
|
@ -60,7 +66,7 @@ $ go get github.com/tockins/realize
|
|||
$ realize run
|
||||
```
|
||||
|
||||
It will create a realize.yaml file if it doesn't exist already, adds the working directory as project and run the pipeline.
|
||||
It will create a realize.yaml file if it doesn't exist already, add the working directory as project and run the pipeline.
|
||||
|
||||
The Run command supports the following custom parameters:
|
||||
|
||||
|
@ -75,6 +81,7 @@ $ go get github.com/tockins/realize
|
|||
--legacy -> Enable legacy watch instead of Fsnotify watch
|
||||
--generate -> Enable go generate
|
||||
--test -> Enable go test
|
||||
--open -> Open in default browser
|
||||
```
|
||||
Examples:
|
||||
|
||||
|
@ -137,63 +144,62 @@ $ go get github.com/tockins/realize
|
|||
|
||||
For more examples check [Realize Examples](https://github.com/tockins/realize-examples)
|
||||
|
||||
```
|
||||
settings:
|
||||
legacy:
|
||||
status: true // legacy watch status
|
||||
interval: 10s // polling interval
|
||||
resources: // files names related to streams
|
||||
outputs: outputs.log
|
||||
logs: logs.log
|
||||
errors: errors.log
|
||||
server:
|
||||
status: false // server status
|
||||
open: false // open browser at start
|
||||
host: localhost // server host
|
||||
port: 5001 // server port
|
||||
projects:
|
||||
- name: coin
|
||||
path: coin // project path
|
||||
commands:
|
||||
vet: true
|
||||
fmt: true
|
||||
test: false
|
||||
generate: false
|
||||
bin:
|
||||
status: true
|
||||
build:
|
||||
status: false
|
||||
args:
|
||||
- -race
|
||||
run: true
|
||||
```
|
||||
settings:
|
||||
legacy:
|
||||
status: true // legacy watch status
|
||||
interval: 10s // polling interval
|
||||
resources: // files names related to streams
|
||||
outputs: outputs.log
|
||||
logs: logs.log
|
||||
errors: errors.log
|
||||
server:
|
||||
status: false // server status
|
||||
open: false // open browser at start
|
||||
host: localhost // server host
|
||||
port: 5001 // server port
|
||||
projects:
|
||||
- name: coin
|
||||
path: coin // project path
|
||||
environment: // env variables
|
||||
test: test
|
||||
myvar: value
|
||||
commands:
|
||||
vet: true
|
||||
fmt: true
|
||||
test: false
|
||||
generate: false
|
||||
bin:
|
||||
status: true
|
||||
build:
|
||||
status: false
|
||||
args:
|
||||
- --myarg
|
||||
watcher:
|
||||
preview: false // watched files preview
|
||||
paths: // watched paths
|
||||
- /
|
||||
ignore_paths: // ignored paths
|
||||
- vendor
|
||||
exts: // watched extensions
|
||||
- .go
|
||||
scripts:
|
||||
- type: before // type
|
||||
command: ./ls -l // command
|
||||
changed: true // relaunch when a file changes
|
||||
startup: true // launch at start
|
||||
- type: after
|
||||
command: ./ls
|
||||
changed: true
|
||||
streams: // enable/disable streams
|
||||
cli_out: true
|
||||
file_out: false
|
||||
file_log: false
|
||||
file_err: false
|
||||
- -race
|
||||
run: true
|
||||
args:
|
||||
- --myarg
|
||||
watcher:
|
||||
preview: false // watched files preview
|
||||
paths: // watched paths
|
||||
- /
|
||||
ignore_paths: // ignored paths
|
||||
- vendor
|
||||
exts: // watched extensions
|
||||
- .go
|
||||
scripts:
|
||||
- type: before // type
|
||||
command: ./ls -l // command
|
||||
changed: true // relaunch when a file changes
|
||||
startup: true // launch at start
|
||||
- type: after
|
||||
command: ./ls
|
||||
changed: true
|
||||
streams: // enable/disable streams
|
||||
cli_out: true
|
||||
file_out: false
|
||||
file_log: false
|
||||
file_err: false
|
||||
|
||||
```
|
||||
|
||||
|
||||
###### Support us and suggest an improvement
|
||||
- Start the project
|
||||
#### Support us and suggest an improvement
|
||||
- Chat with us [Gitter](https://gitter.im/tockins/realize)
|
||||
- Suggest a new [Feature](https://github.com/tockins/realize/issues/new)
|
||||
|
|
24
realize.go
24
realize.go
|
@ -16,13 +16,13 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
appVersion = "1.3"
|
||||
appVersion = "1.4.1"
|
||||
config = "realize.yaml"
|
||||
outputs = "outputs.log"
|
||||
errs = "errors.log"
|
||||
logs = "logs.log"
|
||||
host = "localhost"
|
||||
port = 5001
|
||||
port = 3001
|
||||
interval = 200
|
||||
)
|
||||
|
||||
|
@ -44,7 +44,6 @@ func main() {
|
|||
if gopath == "" {
|
||||
return errors.New("$GOPATH isn't set properly")
|
||||
}
|
||||
|
||||
r = realize{
|
||||
Sync: make(chan string),
|
||||
Settings: settings.Settings{
|
||||
|
@ -116,19 +115,12 @@ func main() {
|
|||
&cli.BoolFlag{Name: "build", Aliases: []string{"b"}, Value: false, Usage: "Enable go build."},
|
||||
&cli.BoolFlag{Name: "legacy", Aliases: []string{"l"}, Value: false, Usage: "Watch by polling instead of Watch by fsnotify."},
|
||||
&cli.BoolFlag{Name: "server", Aliases: []string{"s"}, Value: false, Usage: "Enable server and open into the default browser."},
|
||||
&cli.BoolFlag{Name: "open", Aliases: []string{"o"}, Value: false, Usage: "Open server directly in the default browser."},
|
||||
&cli.BoolFlag{Name: "no-run", Aliases: []string{"nr"}, Value: false, Usage: "Disable go run"},
|
||||
&cli.BoolFlag{Name: "no-install", Aliases: []string{"ni"}, Value: false, Usage: "Disable go install"},
|
||||
&cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."},
|
||||
},
|
||||
Action: func(p *cli.Context) error {
|
||||
c := r
|
||||
if p.String("name") != ""{
|
||||
for index, project := range r.Blueprint.Projects{
|
||||
if project.Name == p.String("name"){
|
||||
c.Blueprint.Projects = []watcher.Project{r.Blueprint.Projects[index]}
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.Bool("legacy") {
|
||||
r.Config.Legacy = settings.Legacy{
|
||||
Status: p.Bool("legacy"),
|
||||
|
@ -144,14 +136,16 @@ func main() {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err := c.Server.Start(p); err != nil {
|
||||
if err := r.Server.Start(p); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Blueprint.Run(p); err != nil {
|
||||
if err := r.Blueprint.Run(p); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.Record(c); err != nil {
|
||||
return err
|
||||
if !p.Bool("no-config") {
|
||||
if err := r.Record(r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -41,6 +41,9 @@ func render(c echo.Context, path string, mime int) error {
|
|||
case 4:
|
||||
rs.Header().Set(echo.HeaderContentType, "image/svg+xml")
|
||||
break
|
||||
case 5:
|
||||
rs.Header().Set(echo.HeaderContentType, "image/png")
|
||||
break
|
||||
}
|
||||
rs.WriteHeader(http.StatusOK)
|
||||
rs.Write(data)
|
||||
|
@ -49,7 +52,14 @@ func render(c echo.Context, path string, mime int) error {
|
|||
|
||||
// Start the web server
|
||||
func (s *Server) Start(p *cli.Context) (err error) {
|
||||
if s.Server.Status || p.Bool("server") {
|
||||
if p.Bool("server") {
|
||||
s.Server.Status = p.Bool("server")
|
||||
}
|
||||
if p.Bool("open") {
|
||||
s.Server.Open = p.Bool("open")
|
||||
}
|
||||
|
||||
if s.Server.Status {
|
||||
e := echo.New()
|
||||
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
|
||||
Level: 2,
|
||||
|
@ -66,8 +76,8 @@ func (s *Server) Start(p *cli.Context) (err error) {
|
|||
e.GET("/assets/css/app.css", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/css/app.css", 3)
|
||||
})
|
||||
e.GET("/app/components/projects/index.html", func(c echo.Context) error {
|
||||
return render(c, "assets/app/components/projects/index.html", 1)
|
||||
e.GET("/app/components/settings/index.html", func(c echo.Context) error {
|
||||
return render(c, "assets/app/components/settings/index.html", 1)
|
||||
})
|
||||
e.GET("/app/components/project/index.html", func(c echo.Context) error {
|
||||
return render(c, "assets/app/components/project/index.html", 1)
|
||||
|
@ -75,12 +85,30 @@ func (s *Server) Start(p *cli.Context) (err error) {
|
|||
e.GET("/app/components/index.html", func(c echo.Context) error {
|
||||
return render(c, "assets/app/components/index.html", 1)
|
||||
})
|
||||
e.GET("/assets/img/svg/github-logo.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/github-logo.svg", 4)
|
||||
e.GET("/assets/img/svg/ic_settings_black_24px.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/ic_settings_black_24px.svg", 4)
|
||||
})
|
||||
e.GET("/assets/img/svg/ic_fullscreen_black_24px.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/ic_fullscreen_black_24px.svg", 4)
|
||||
})
|
||||
e.GET("/assets/img/svg/ic_add_black_24px.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/ic_add_black_24px.svg", 4)
|
||||
})
|
||||
e.GET("/assets/img/svg/ic_keyboard_backspace_black_24px.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/ic_keyboard_backspace_black_24px.svg", 4)
|
||||
})
|
||||
e.GET("/assets/img/svg/ic_error_black_48px.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/ic_error_black_48px.svg", 4)
|
||||
})
|
||||
e.GET("/assets/img/svg/ic_remove_black_24px.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/ic_remove_black_24px.svg", 4)
|
||||
})
|
||||
e.GET("/assets/img/svg/logo.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/logo.svg", 4)
|
||||
})
|
||||
e.GET("/assets/img/favicon-32x32.png", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/favicon-32x32.png", 5)
|
||||
})
|
||||
e.GET("/assets/img/svg/ic_swap_vertical_circle_black_48px.svg", func(c echo.Context) error {
|
||||
return render(c, "assets/assets/img/svg/ic_swap_vertical_circle_black_48px.svg", 4)
|
||||
})
|
||||
|
@ -89,7 +117,7 @@ func (s *Server) Start(p *cli.Context) (err error) {
|
|||
e.GET("/ws", s.projects)
|
||||
|
||||
go e.Start(string(s.Settings.Server.Host) + ":" + strconv.Itoa(s.Settings.Server.Port))
|
||||
if s.Open || p.Bool("open") {
|
||||
if s.Open {
|
||||
_, err = Open("http://" + string(s.Settings.Server.Host) + ":" + strconv.Itoa(s.Settings.Server.Port))
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package settings
|
||||
|
||||
import (
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
"os"
|
||||
"time"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var Dir = ".realize/"
|
||||
|
|
|
@ -5,7 +5,9 @@ import (
|
|||
"fmt"
|
||||
"github.com/tockins/realize/style"
|
||||
cli "gopkg.in/urfave/cli.v2"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Run launches the toolchain for each project
|
||||
|
@ -16,7 +18,7 @@ func (h *Blueprint) Run(p *cli.Context) error {
|
|||
wg.Add(len(h.Projects))
|
||||
for k, element := range h.Projects {
|
||||
tools := tools{}
|
||||
if element.Cmds.Fmt{
|
||||
if element.Cmds.Fmt {
|
||||
tools.Fmt = tool{
|
||||
status: &h.Projects[k].Cmds.Fmt,
|
||||
cmd: "gofmt",
|
||||
|
@ -24,7 +26,7 @@ func (h *Blueprint) Run(p *cli.Context) error {
|
|||
name: "Go Fmt",
|
||||
}
|
||||
}
|
||||
if element.Cmds.Generate{
|
||||
if element.Cmds.Generate {
|
||||
tools.Generate = tool{
|
||||
status: &h.Projects[k].Cmds.Generate,
|
||||
cmd: "go",
|
||||
|
@ -32,7 +34,7 @@ func (h *Blueprint) Run(p *cli.Context) error {
|
|||
name: "Go Generate",
|
||||
}
|
||||
}
|
||||
if element.Cmds.Test{
|
||||
if element.Cmds.Test {
|
||||
tools.Test = tool{
|
||||
status: &h.Projects[k].Cmds.Test,
|
||||
cmd: "go",
|
||||
|
@ -51,6 +53,14 @@ func (h *Blueprint) Run(p *cli.Context) error {
|
|||
h.Projects[k].tools = tools
|
||||
h.Projects[k].parent = h
|
||||
h.Projects[k].path = h.Projects[k].Path
|
||||
|
||||
// env variables
|
||||
for key, item := range h.Projects[k].Environment {
|
||||
if err := os.Setenv(key, item); err != nil {
|
||||
h.Projects[k].Buffer.StdErr = append(h.Projects[k].Buffer.StdErr, BufferOut{Time: time.Now(), Text: err.Error(), Type: "Env error", Stream: ""})
|
||||
}
|
||||
}
|
||||
|
||||
if h.Legacy.Status {
|
||||
go h.Projects[k].watchByPolling()
|
||||
} else {
|
||||
|
@ -69,7 +79,6 @@ func (h *Blueprint) Add(p *cli.Context) error {
|
|||
Name: h.Name(p.String("name"), p.String("path")),
|
||||
Path: h.Path(p.String("path")),
|
||||
Cmds: Cmds{
|
||||
|
||||
Vet: p.Bool("vet"),
|
||||
Fmt: !p.Bool("no-fmt"),
|
||||
Test: p.Bool("test"),
|
||||
|
@ -178,5 +187,5 @@ func (h *Blueprint) check() error {
|
|||
h.Clean()
|
||||
return nil
|
||||
}
|
||||
return errors.New("there are no projects")
|
||||
return errors.New("There are no projects")
|
||||
}
|
||||
|
|
|
@ -85,11 +85,11 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
|
|||
for output.Scan() {
|
||||
text := output.Text()
|
||||
msg := fmt.Sprintln(p.pname(p.Name, 3), ":", style.Blue.Regular(text))
|
||||
if isError || isErrorText(text) {
|
||||
if isError && !isErrorText(text) {
|
||||
out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"}
|
||||
p.print("error", out, msg, "")
|
||||
} else {
|
||||
out := BufferOut{Time: time.Now(), Text: text}
|
||||
out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"}
|
||||
p.print("out", out, msg, "")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,14 +34,15 @@ type Project struct {
|
|||
settings.Settings `yaml:"-"`
|
||||
LastChangedOn time.Time `yaml:"-" json:"-"`
|
||||
base string
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Path string `yaml:"path" json:"path"`
|
||||
Cmds Cmds `yaml:"commands" json:"commands"`
|
||||
Args []string `yaml:"args,omitempty" json:"args,omitempty"`
|
||||
Watcher Watcher `yaml:"watcher" json:"watcher"`
|
||||
Streams Streams `yaml:"streams,omitempty" json:"streams,omitempty"`
|
||||
Buffer Buffer `yaml:"-" json:"buffer"`
|
||||
ErrorOutputPattern string `yaml:"errorOutputPattern,omitempty" json:"errorOutputPattern,omitempty"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Path string `yaml:"path" json:"path"`
|
||||
Environment map[string]string `yaml:"environment,omitempty" json:"environment,omitempty"`
|
||||
Cmds Cmds `yaml:"commands" json:"commands"`
|
||||
Args []string `yaml:"args,omitempty" json:"args,omitempty"`
|
||||
Watcher Watcher `yaml:"watcher" json:"watcher"`
|
||||
Streams Streams `yaml:"streams,omitempty" json:"streams,omitempty"`
|
||||
Buffer Buffer `yaml:"-" json:"buffer"`
|
||||
ErrorOutputPattern string `yaml:"errorOutputPattern,omitempty" json:"errorOutputPattern,omitempty"`
|
||||
parent *Blueprint
|
||||
path string
|
||||
tools tools
|
||||
|
|
|
@ -286,10 +286,10 @@ func (p *Project) tool(path string, tool tool) error {
|
|||
// Cmd calls an wrapper for execute the commands after/before
|
||||
func (p *Project) cmd(flag string, changed bool) {
|
||||
for _, cmd := range p.Watcher.Scripts {
|
||||
if strings.ToLower(cmd.Type) == flag{
|
||||
if strings.ToLower(cmd.Type) == flag {
|
||||
if changed && cmd.Changed || !changed && cmd.Startup {
|
||||
errors, logs := p.command(cmd)
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 5), ":", style.Green.Bold("Command"), style.Green.Bold("\"") + cmd.Command + style.Green.Bold("\""))
|
||||
msg = fmt.Sprintln(p.pname(p.Name, 5), ":", style.Green.Bold("Command"), style.Green.Bold("\"")+cmd.Command+style.Green.Bold("\""))
|
||||
out = BufferOut{Time: time.Now(), Text: cmd.Command, Type: flag}
|
||||
if logs != "" {
|
||||
p.print("log", out, msg, "")
|
||||
|
@ -323,7 +323,7 @@ func (p *Project) ignore(str string) bool {
|
|||
}
|
||||
|
||||
// Routines launches the toolchain run, build, install
|
||||
func (p *Project) routines(wr *sync.WaitGroup,channel chan bool, watcher watcher, file string) {
|
||||
func (p *Project) routines(wr *sync.WaitGroup, channel chan bool, watcher watcher, file string) {
|
||||
if len(file) > 0 {
|
||||
p.cmd("before", true)
|
||||
path := filepath.Dir(file)
|
||||
|
@ -396,9 +396,6 @@ func (p *Project) print(t string, o BufferOut, msg string, stream string) {
|
|||
p.Fatal(err, "")
|
||||
}
|
||||
}
|
||||
if msg != "" {
|
||||
log.Print(msg)
|
||||
}
|
||||
case "error":
|
||||
p.Buffer.StdErr = append(p.Buffer.StdErr, o)
|
||||
if p.Streams.FileErr {
|
||||
|
@ -412,9 +409,9 @@ func (p *Project) print(t string, o BufferOut, msg string, stream string) {
|
|||
p.Fatal(err, "")
|
||||
}
|
||||
}
|
||||
if msg != "" {
|
||||
log.Print(msg)
|
||||
}
|
||||
}
|
||||
if msg != "" {
|
||||
log.Print(msg)
|
||||
}
|
||||
if stream != "" {
|
||||
fmt.Print(stream)
|
||||
|
|
Loading…
Reference in New Issue