Merge pull request #72 from tockins/dev

Dev v1.4.1
This commit is contained in:
Alessio Pracchia 2017-08-09 00:11:55 +02:00 committed by GitHub
commit 87918aed27
9 changed files with 364 additions and 143 deletions

158
README.md
View File

@ -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) [![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) [![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 #### Features
- Highly customizable - Highly customizable
- Config your project Step by Step - Setup step by step
- Build, Install, Test, Fmt, Generate and Run at the same time - Live reload
- Live reload on file changes (re-build, re-install...)
- Watch custom paths and specific file extensions
- Watch by FsNotify or by polling
- Support for multiple projects - Support for multiple projects
- Output streams and error logs (support for save on a file) - Save logs on files
- Web Panel (projects list, config settings, logs) - 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 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) - [ ] Input redirection (wait for an input and redirect)
- [ ] Web panel full support
- [ ] Multiple configurations
- [ ] GoMobile support ?
- [ ] Ignore path and files in gititnore ?
#### Wiki #### Wiki
- [Getting Started](#installation-and-usage) - [Getting Started](#installation)
- [Run cmd](#run) - Run a project - [Run cmd](#run) - Run a project
- [Add cmd](#add) - Add a new project - [Add cmd](#add) - Add a new project
- [Init cmd](#init) - Make a custom config step by step - [Init cmd](#init) - Make a custom config step by step
- [Remove cmd](#remove) - Remove a project - [Remove cmd](#remove) - Remove a project
- [List cmd](#list) - List the projects - [List cmd](#list) - List the projects
- [Config sample](#config-sample) - [Config sample](#config-sample) - Sample config file
- [Support](#support) - [Support](#support-us-and-suggest-an-improvement)
- ##### Installation #### Installation
Run this to get/install: Run this to get/install:
``` ```
$ go get github.com/tockins/realize $ go get github.com/tockins/realize
@ -60,7 +66,7 @@ $ go get github.com/tockins/realize
$ realize run $ 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: 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 --legacy -> Enable legacy watch instead of Fsnotify watch
--generate -> Enable go generate --generate -> Enable go generate
--test -> Enable go test --test -> Enable go test
--open -> Open in default browser
``` ```
Examples: Examples:
@ -137,63 +144,62 @@ $ go get github.com/tockins/realize
For more examples check [Realize Examples](https://github.com/tockins/realize-examples) For more examples check [Realize Examples](https://github.com/tockins/realize-examples)
``` ```
settings: settings:
legacy: legacy:
status: true // legacy watch status status: true // legacy watch status
interval: 10s // polling interval interval: 10s // polling interval
resources: // files names related to streams resources: // files names related to streams
outputs: outputs.log outputs: outputs.log
logs: logs.log logs: logs.log
errors: errors.log errors: errors.log
server: server:
status: false // server status status: false // server status
open: false // open browser at start open: false // open browser at start
host: localhost // server host host: localhost // server host
port: 5001 // server port port: 5001 // server port
projects: projects:
- name: coin - name: coin
path: coin // project path path: coin // project path
commands: environment: // env variables
vet: true test: test
fmt: true myvar: value
test: false commands:
generate: false vet: true
bin: fmt: true
status: true test: false
build: generate: false
status: false bin:
args: status: true
- -race build:
run: true status: false
args: args:
- --myarg - -race
watcher: run: true
preview: false // watched files preview args:
paths: // watched paths - --myarg
- / watcher:
ignore_paths: // ignored paths preview: false // watched files preview
- vendor paths: // watched paths
exts: // watched extensions - /
- .go ignore_paths: // ignored paths
scripts: - vendor
- type: before // type exts: // watched extensions
command: ./ls -l // command - .go
changed: true // relaunch when a file changes scripts:
startup: true // launch at start - type: before // type
- type: after command: ./ls -l // command
command: ./ls changed: true // relaunch when a file changes
changed: true startup: true // launch at start
streams: // enable/disable streams - type: after
cli_out: true command: ./ls
file_out: false changed: true
file_log: false streams: // enable/disable streams
file_err: false cli_out: true
file_out: false
file_log: false
file_err: false
``` #### Support us and suggest an improvement
###### Support us and suggest an improvement
- Start the project
- Chat with us [Gitter](https://gitter.im/tockins/realize) - Chat with us [Gitter](https://gitter.im/tockins/realize)
- Suggest a new [Feature](https://github.com/tockins/realize/issues/new) - Suggest a new [Feature](https://github.com/tockins/realize/issues/new)

View File

@ -16,13 +16,13 @@ import (
) )
const ( const (
appVersion = "1.3" appVersion = "1.4.1"
config = "realize.yaml" config = "realize.yaml"
outputs = "outputs.log" outputs = "outputs.log"
errs = "errors.log" errs = "errors.log"
logs = "logs.log" logs = "logs.log"
host = "localhost" host = "localhost"
port = 5001 port = 3001
interval = 200 interval = 200
) )
@ -44,7 +44,6 @@ func main() {
if gopath == "" { if gopath == "" {
return errors.New("$GOPATH isn't set properly") return errors.New("$GOPATH isn't set properly")
} }
r = realize{ r = realize{
Sync: make(chan string), Sync: make(chan string),
Settings: settings.Settings{ 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: "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: "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: "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-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-install", Aliases: []string{"ni"}, Value: false, Usage: "Disable go install"},
&cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."}, &cli.BoolFlag{Name: "no-config", Aliases: []string{"nc"}, Value: false, Usage: "Ignore existing configurations."},
}, },
Action: func(p *cli.Context) error { 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") { if p.Bool("legacy") {
r.Config.Legacy = settings.Legacy{ r.Config.Legacy = settings.Legacy{
Status: p.Bool("legacy"), Status: p.Bool("legacy"),
@ -144,14 +136,16 @@ func main() {
return err return err
} }
} }
if err := c.Server.Start(p); err != nil { if err := r.Server.Start(p); err != nil {
return err return err
} }
if err := c.Blueprint.Run(p); err != nil { if err := r.Blueprint.Run(p); err != nil {
return err return err
} }
if err := r.Record(c); err != nil { if !p.Bool("no-config") {
return err if err := r.Record(r); err != nil {
return err
}
} }
return nil return nil
}, },

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,9 @@ func render(c echo.Context, path string, mime int) error {
case 4: case 4:
rs.Header().Set(echo.HeaderContentType, "image/svg+xml") rs.Header().Set(echo.HeaderContentType, "image/svg+xml")
break break
case 5:
rs.Header().Set(echo.HeaderContentType, "image/png")
break
} }
rs.WriteHeader(http.StatusOK) rs.WriteHeader(http.StatusOK)
rs.Write(data) rs.Write(data)
@ -49,7 +52,14 @@ func render(c echo.Context, path string, mime int) error {
// Start the web server // Start the web server
func (s *Server) Start(p *cli.Context) (err error) { 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 := echo.New()
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
Level: 2, 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 { e.GET("/assets/css/app.css", func(c echo.Context) error {
return render(c, "assets/assets/css/app.css", 3) return render(c, "assets/assets/css/app.css", 3)
}) })
e.GET("/app/components/projects/index.html", func(c echo.Context) error { e.GET("/app/components/settings/index.html", func(c echo.Context) error {
return render(c, "assets/app/components/projects/index.html", 1) return render(c, "assets/app/components/settings/index.html", 1)
}) })
e.GET("/app/components/project/index.html", func(c echo.Context) error { e.GET("/app/components/project/index.html", func(c echo.Context) error {
return render(c, "assets/app/components/project/index.html", 1) 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 { e.GET("/app/components/index.html", func(c echo.Context) error {
return render(c, "assets/app/components/index.html", 1) return render(c, "assets/app/components/index.html", 1)
}) })
e.GET("/assets/img/svg/github-logo.svg", func(c echo.Context) error { e.GET("/assets/img/svg/ic_settings_black_24px.svg", func(c echo.Context) error {
return render(c, "assets/assets/img/svg/github-logo.svg", 4) 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 { 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) 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 { 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) 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) e.GET("/ws", s.projects)
go e.Start(string(s.Settings.Server.Host) + ":" + strconv.Itoa(s.Settings.Server.Port)) 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)) _, err = Open("http://" + string(s.Settings.Server.Host) + ":" + strconv.Itoa(s.Settings.Server.Port))
if err != nil { if err != nil {
return err return err

View File

@ -1,9 +1,9 @@
package settings package settings
import ( import (
yaml "gopkg.in/yaml.v2"
"os" "os"
"time" "time"
yaml "gopkg.in/yaml.v2"
) )
var Dir = ".realize/" var Dir = ".realize/"

View File

@ -5,7 +5,9 @@ import (
"fmt" "fmt"
"github.com/tockins/realize/style" "github.com/tockins/realize/style"
cli "gopkg.in/urfave/cli.v2" cli "gopkg.in/urfave/cli.v2"
"os"
"strings" "strings"
"time"
) )
// Run launches the toolchain for each project // Run launches the toolchain for each project
@ -16,7 +18,7 @@ func (h *Blueprint) Run(p *cli.Context) error {
wg.Add(len(h.Projects)) wg.Add(len(h.Projects))
for k, element := range h.Projects { for k, element := range h.Projects {
tools := tools{} tools := tools{}
if element.Cmds.Fmt{ if element.Cmds.Fmt {
tools.Fmt = tool{ tools.Fmt = tool{
status: &h.Projects[k].Cmds.Fmt, status: &h.Projects[k].Cmds.Fmt,
cmd: "gofmt", cmd: "gofmt",
@ -24,7 +26,7 @@ func (h *Blueprint) Run(p *cli.Context) error {
name: "Go Fmt", name: "Go Fmt",
} }
} }
if element.Cmds.Generate{ if element.Cmds.Generate {
tools.Generate = tool{ tools.Generate = tool{
status: &h.Projects[k].Cmds.Generate, status: &h.Projects[k].Cmds.Generate,
cmd: "go", cmd: "go",
@ -32,7 +34,7 @@ func (h *Blueprint) Run(p *cli.Context) error {
name: "Go Generate", name: "Go Generate",
} }
} }
if element.Cmds.Test{ if element.Cmds.Test {
tools.Test = tool{ tools.Test = tool{
status: &h.Projects[k].Cmds.Test, status: &h.Projects[k].Cmds.Test,
cmd: "go", cmd: "go",
@ -51,6 +53,14 @@ func (h *Blueprint) Run(p *cli.Context) error {
h.Projects[k].tools = tools h.Projects[k].tools = tools
h.Projects[k].parent = h h.Projects[k].parent = h
h.Projects[k].path = h.Projects[k].Path 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 { if h.Legacy.Status {
go h.Projects[k].watchByPolling() go h.Projects[k].watchByPolling()
} else { } else {
@ -69,7 +79,6 @@ func (h *Blueprint) Add(p *cli.Context) error {
Name: h.Name(p.String("name"), p.String("path")), Name: h.Name(p.String("name"), p.String("path")),
Path: h.Path(p.String("path")), Path: h.Path(p.String("path")),
Cmds: Cmds{ Cmds: Cmds{
Vet: p.Bool("vet"), Vet: p.Bool("vet"),
Fmt: !p.Bool("no-fmt"), Fmt: !p.Bool("no-fmt"),
Test: p.Bool("test"), Test: p.Bool("test"),
@ -178,5 +187,5 @@ func (h *Blueprint) check() error {
h.Clean() h.Clean()
return nil return nil
} }
return errors.New("there are no projects") return errors.New("There are no projects")
} }

View File

@ -85,11 +85,11 @@ func (p *Project) goRun(channel chan bool, runner chan bool, wr *sync.WaitGroup)
for output.Scan() { for output.Scan() {
text := output.Text() text := output.Text()
msg := fmt.Sprintln(p.pname(p.Name, 3), ":", style.Blue.Regular(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"} out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"}
p.print("error", out, msg, "") p.print("error", out, msg, "")
} else { } else {
out := BufferOut{Time: time.Now(), Text: text} out := BufferOut{Time: time.Now(), Text: text, Type: "Go Run"}
p.print("out", out, msg, "") p.print("out", out, msg, "")
} }
} }

View File

@ -34,14 +34,15 @@ type Project struct {
settings.Settings `yaml:"-"` settings.Settings `yaml:"-"`
LastChangedOn time.Time `yaml:"-" json:"-"` LastChangedOn time.Time `yaml:"-" json:"-"`
base string base string
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Path string `yaml:"path" json:"path"` Path string `yaml:"path" json:"path"`
Cmds Cmds `yaml:"commands" json:"commands"` Environment map[string]string `yaml:"environment,omitempty" json:"environment,omitempty"`
Args []string `yaml:"args,omitempty" json:"args,omitempty"` Cmds Cmds `yaml:"commands" json:"commands"`
Watcher Watcher `yaml:"watcher" json:"watcher"` Args []string `yaml:"args,omitempty" json:"args,omitempty"`
Streams Streams `yaml:"streams,omitempty" json:"streams,omitempty"` Watcher Watcher `yaml:"watcher" json:"watcher"`
Buffer Buffer `yaml:"-" json:"buffer"` Streams Streams `yaml:"streams,omitempty" json:"streams,omitempty"`
ErrorOutputPattern string `yaml:"errorOutputPattern,omitempty" json:"errorOutputPattern,omitempty"` Buffer Buffer `yaml:"-" json:"buffer"`
ErrorOutputPattern string `yaml:"errorOutputPattern,omitempty" json:"errorOutputPattern,omitempty"`
parent *Blueprint parent *Blueprint
path string path string
tools tools tools tools

View File

@ -286,10 +286,10 @@ func (p *Project) tool(path string, tool tool) error {
// Cmd calls an wrapper for execute the commands after/before // Cmd calls an wrapper for execute the commands after/before
func (p *Project) cmd(flag string, changed bool) { func (p *Project) cmd(flag string, changed bool) {
for _, cmd := range p.Watcher.Scripts { 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 { if changed && cmd.Changed || !changed && cmd.Startup {
errors, logs := p.command(cmd) 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} out = BufferOut{Time: time.Now(), Text: cmd.Command, Type: flag}
if logs != "" { if logs != "" {
p.print("log", out, msg, "") p.print("log", out, msg, "")
@ -323,7 +323,7 @@ func (p *Project) ignore(str string) bool {
} }
// Routines launches the toolchain run, build, install // 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 { if len(file) > 0 {
p.cmd("before", true) p.cmd("before", true)
path := filepath.Dir(file) path := filepath.Dir(file)
@ -396,9 +396,6 @@ func (p *Project) print(t string, o BufferOut, msg string, stream string) {
p.Fatal(err, "") p.Fatal(err, "")
} }
} }
if msg != "" {
log.Print(msg)
}
case "error": case "error":
p.Buffer.StdErr = append(p.Buffer.StdErr, o) p.Buffer.StdErr = append(p.Buffer.StdErr, o)
if p.Streams.FileErr { if p.Streams.FileErr {
@ -412,9 +409,9 @@ func (p *Project) print(t string, o BufferOut, msg string, stream string) {
p.Fatal(err, "") p.Fatal(err, "")
} }
} }
if msg != "" { }
log.Print(msg) if msg != "" {
} log.Print(msg)
} }
if stream != "" { if stream != "" {
fmt.Print(stream) fmt.Print(stream)