Skip to content

Commit

Permalink
Update to 0.0.9 add -delay cli flag as requested at #14
Browse files Browse the repository at this point in the history
  • Loading branch information
kataras committed Feb 14, 2018
1 parent 6d0aea2 commit 163865a
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 71 deletions.
10 changes: 10 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 0.0.9

1. `rizla.Run()` -> `rizla.Run(map[string][]string)`. Run now accepts a `sources map[string][]string`, can be nil if projects added manually previously, the `key string` is the program filepath with `.go` extension and the `values []string` are any optional arguments that the program excepts to be passed. Therefore use `Run(nil)` if you used `rizla.Run()` before.

2. `rizla.RunWith(watcher rizla.Watcher, programFile string)` -> `rizla.RunWith(watcher rizla.Watcher, sources map[string][]string, delayOnDetect time.Duration)`.

3. At `rizla#Project` the property `AllowRunAfter time.Duration` added.

4. New `-delay` cli flag added, as requested by @scorpnode at https://github.com/kataras/rizla/issues/14

## 0.0.8

Support flags as requested at [#13](https://github.com/kataras/rizla/issues/13) by @Zeno-Code.
Expand Down
60 changes: 31 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,27 @@ $ go get -u github.com/kataras/rizla
$ rizla main.go #single project monitoring
$ rizla C:/myprojects/project1/main.go C:/myprojects/project2/main.go #multi projects monitoring
$ rizla -walk main.go #prepend '-walk' only when the default file changes scanning method doesn't works for you.
$ rizla -delay=5s main.go # if delay > 0 then it delays the reload, also note that it accepts the first change but the rest of changes every "delay".
```

Want to use it from your project's source code? easy

```sh
$ cat from_code_simple.go
```

```go
package main

import (
"github.com/kataras/rizla/rizla"
"github.com/kataras/rizla/rizla"
)

func main() {
// Build, run & start monitoring the projects
rizla.Run("C:/iris-project/main.go", "C:/otherproject/main.go")
// rizla.RunWith(rizla.WatcherFromFlag("-walk"), "./main.go")
// watcher, _ := rizla.WatcherFromFlag("-walk")
// rizla.RunWith(watcher, "./main.go", 0)
}
```

Expand All @@ -44,11 +48,12 @@ $ cat from_code_pro.go
package main

import (
"github.com/kataras/rizla/rizla"
"path/filepath"
"runtime"
"time"
"os"
"path/filepath"
"runtime"
"time"
"os"

"github.com/kataras/rizla/rizla"
)

func main() {
Expand All @@ -68,69 +73,67 @@ func main() {
// Custom subdirectory matcher, for the watcher, return true to include this folder to the watcher
// the default is:
project.Watcher = func(absolutePath string) bool {
base := filepath.Base(abs)
return !(base == ".git" || base == "node_modules" || base == "vendor")
base := filepath.Base(abs)
return !(base == ".git" || base == "node_modules" || base == "vendor")
}
// Custom file matcher on runtime (file change), return true to reload when a file with this file name changed
// the default is:
project.Matcher = func(filename string) bool {
isWindows = runtime.GOOS == "windows"
goExt = ".go"
return (filepath.Ext(fullname) == goExt) ||
(!isWindows && strings.Contains(fullname, goExt))
isWindows = runtime.GOOS == "windows"
goExt = ".go"
return (filepath.Ext(fullname) == goExt) ||
(!isWindows && strings.Contains(fullname, goExt))
}
// Add arguments, these will be used from the executable file
project.Args = []string{"-myargument","the value","-otherargument","a value"}
// Custom callback before reload, the default is:
project.OnReload = func(string) {
fromproject := ""
if p.Name != "" {
fromproject = "From project '" + project.Name + "': "
}
project.Out.Infof("\n%sA change has been detected, reloading now...", fromproject)
fromproject := ""
if p.Name != "" {
fromproject = "From project '" + project.Name + "': "
}
project.Out.Infof("\n%sA change has been detected, reloading now...", fromproject)
}
// Custom callback after reload, the default is:
project.OnReloaded = func(string) {
project.Out.Successf("ready!\n")
project.Out.Successf("ready!\n")
}

// End of optional

// Add the project to the rizla container
rizla.Add(project)
// Build, run & start monitoring the project(s)
rizla.Run()
rizla.Run(nil)
}
```

> That's all!

FAQ
------------
Ask questions and get real-time answers from the [Chat][CHAT].


Features
------------
- Super easy - is created for everyone.
- You can use it either as command line tool either as part of your project's source code!
- Multi-Monitoring - Supports monitoring of unlimited projects.
- Rizla, by-default, uses the operating system's signals to fire a change because it is the fastest way and it consumes the minimal CPU.
- You 're still able to change the watcher to use the `filepath.Walk` too with `-walk` flag.

- delay reload on detect change with `-delay`

People

------------
If you'd like to discuss this package, or ask questions about it, feel free to [Chat][CHAT].

The author of rizla is [@kataras](https://github.com/kataras).


Versioning
------------

Current: **v0.0.8**
Current: **v0.0.9**

[HISTORY](https://github.com/kataras/rizla/blob/master/HISTORY.md) file is your best friend!

Expand All @@ -143,15 +146,14 @@ Read more about Semantic Versioning 2.0.0
Todo
------------

- [ ] Tests
- [ ] Provide full examples.
- [ ] Tests
- [ ] Provide full examples.

Third-Party Licenses
------------

Third-Party Licenses can be found [here](THIRDPARTY-LICENSE)


License
------------

Expand All @@ -163,7 +165,7 @@ License can be found [here](LICENSE).
[Travis]: http://travis-ci.org/kataras/rizla
[License Widget]: https://img.shields.io/badge/license-MIT%20%20License%20-E91E63.svg?style=flat-square
[License]: https://github.com/kataras/rizla/blob/master/LICENSE
[Release Widget]: https://img.shields.io/badge/release-v0.0.8-blue.svg?style=flat-square
[Release Widget]: https://img.shields.io/badge/release-v0.0.9-blue.svg?style=flat-square
[Release]: https://github.com/kataras/rizla/releases
[Chat Widget]: https://img.shields.io/badge/community-chat-00BCD4.svg?style=flat-square
[Chat]: https://kataras.rocket.chat/channel/rizla
Expand Down
56 changes: 46 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os"
"path/filepath"
"strings"
"time"

"github.com/fatih/color"
"github.com/kataras/rizla/rizla"
Expand All @@ -25,13 +26,36 @@ const (
Description = "Rizla builds, runs and monitors your Go Applications with ease."
)

const delayArgName = "-delay"

func getDelayFromArg(arg string) (time.Duration, bool) {
if strings.HasPrefix(arg, delayArgName) || strings.HasPrefix(arg, delayArgName[1:]) {
// [-]delay 5s
// [-]delay=5s
if spaceIdx := strings.IndexRune(arg, ' '); spaceIdx > 0 {
delayStr := arg[spaceIdx+1:]
d, _ := time.ParseDuration(delayStr)
return d, true
}

if equalIdx := strings.IndexRune(arg, '='); equalIdx > 0 {
delayStr := arg[equalIdx+1:]
d, _ := time.ParseDuration(delayStr)
return d, true
}
}

return 0, false
}

var helpTmpl = fmt.Sprintf(`NAME:
%s - %s
USAGE:
rizla main.go
rizla C:/myprojects/project1/main.go C:/myprojects/project2/main.go C:/myprojects/project3/main.go
rizla -walk main.go [if -walk then rizla uses the stdlib's filepath.Walk method instead of file system's signals]
rizla -delay=5s main.go [if delay > 0 then it delays the reload, also note that it accepts the first change but the rest of changes every "delay"]
VERSION:
%s
`, Name, Description, Version)
Expand All @@ -47,19 +71,31 @@ func main() {

args := os.Args[1:]
programFiles := make(map[string][]string, 0) // key = main file, value = args.
var fsWatcher rizla.Watcher
fsWatcher, _ := rizla.WatcherFromFlag("signal")

var lastProgramFile string
var delayOnDetect time.Duration

for i, a := range args {
// The first argument must be the method type of the file system's watcher.
// if -w,-walk,walk then
// asks to use the stdlib's filepath.walk method instead of the operating system's signal.
// It's only usage is when the user's IDE overrides the os' signals.
// otherwise
// use the fsnotify's operating system's file system's signals.
if i == 0 {
fsWatcher = rizla.WatcherFromFlag(a)
// if main files with arguments aren't passed yet,
// then the argument(s) should refer to the rizla tool and not the
// external programs.
if lastProgramFile == "" {
// The first argument must be the method type of the file system's watcher.
// if -w,-walk,walk then
// asks to use the stdlib's filepath.walk method instead of the operating system's signal.
// It's only usage is when the user's IDE overrides the os' signals.
// otherwise
// use the fsnotify's operating system's file system's signals.
if watcher, ok := rizla.WatcherFromFlag(a); ok {
fsWatcher = watcher
continue
}

if delay, ok := getDelayFromArg(a); ok {
delayOnDetect = delay
continue
}
}

// it's main.go or any go main program
Expand Down Expand Up @@ -92,7 +128,7 @@ func main() {
}
}

rizla.RunWith(fsWatcher, programFiles)
rizla.RunWith(fsWatcher, programFiles, delayOnDetect)
}

func help(code int) {
Expand Down
3 changes: 3 additions & 0 deletions rizla/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ type Project struct {
// AllowReloadAfter skip reload on file changes that made too fast from the last reload
// minimum allowed duration is 3 seconds.
AllowReloadAfter time.Duration
// AllowRunAfter it accepts the file changes
// but it waits "x" duration for the reload to happen.
AllowRunAfter time.Duration
// OnReload fires when when file has been changed and rizla is going to reload the project
// the parameter is the changed file name
OnReload func(string)
Expand Down
78 changes: 50 additions & 28 deletions rizla/rizla.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ var (
// second (optional) parameter(s) are the directories of the projects.
// it's optional because they can be added with the .Add(NewProject) before the RunWith.
//
func RunWith(watcher Watcher, sources map[string][]string) {
func RunWith(watcher Watcher, sources map[string][]string, delayOnDetect time.Duration) {
// Author's notes: Because rizla's Run is not allowed to be called more than once
// the whole package works as it is, so the watcher here
// is CHANGING THE UNEXPORTED PACKGE VARIABLE 'fsWatcher'.
Expand All @@ -73,7 +73,9 @@ func RunWith(watcher Watcher, sources map[string][]string) {

if len(sources) > 0 {
for programFile, args := range sources {
Add(NewProject(programFile, args...))
project := NewProject(programFile, args...)
project.AllowRunAfter = delayOnDetect
Add(project)
}
}

Expand All @@ -98,37 +100,56 @@ func RunWith(watcher Watcher, sources map[string][]string) {

watcher.OnChange(func(p *Project, filename string) {
if time.Now().After(p.lastChange.Add(p.AllowReloadAfter)) {
p.lastChange = time.Now()
match := p.Matcher(filename)

if match {

p.OnReload(filename)
if match := p.Matcher(filename); !match {
return
}

// kill previous running instance
err := killProcess(p.proc, p.AppName)
if err != nil {
p.Err.Dangerf("kill: %v", err)
return
if p.AllowRunAfter > 0 {

// Note that here, at "AllowRunAfter", maybe a lot of re-builds
// at the same time if the user saved without
// "AllowReloadAfter" configured, so every of the changes
// are allowed in short period of time.
// As a solution if AllowReloadAfter is not configured we will
// configure it here, we can't do it before the first try
// because it will wrong to wait "x" time to the first change detect allow.
// We could make it with 1-buf channel as well.
if p.AllowReloadAfter == 0 {
p.lastChange = time.Now()
p.AllowReloadAfter = p.AllowRunAfter
// if minus := 250 * time.Millisecond; p.AllowRunAfter > minus {
// p.AllowReloadAfter = p.AllowRunAfter - minus
// }
}
time.Sleep(p.AllowRunAfter)
}

// go build
err = buildProject(p)
if err != nil {
p.Err.Dangerf("build: %v", errBuild)
return
}
p.lastChange = time.Now()
p.OnReload(filename)

// exec run the builded program
err = runProject(p)
if err != nil {
p.Err.Dangerf("run: %s", errRun.Format(err.Error()).Error())
return
}
// kill previous running instance
err := killProcess(p.proc, p.AppName)
if err != nil {
p.Err.Dangerf("kill: %v", err)
return
}

p.OnReloaded(filename)
// go build
err = buildProject(p)
if err != nil {
p.Err.Dangerf("build: %v", errBuild)
return
}

// exec run the builded program
err = runProject(p)
if err != nil {
p.Err.Dangerf("run: %s", errRun.Format(err.Error()).Error())
return
}

p.OnReloaded(filename)

}
})

Expand All @@ -143,10 +164,11 @@ func Run(sources map[string][]string) {
if fsWatcher != nil {
// if user already called RunWith before, the watcher is saved on the 'fsWatcher' variable,
// use that instead.
RunWith(fsWatcher, sources)
RunWith(fsWatcher, sources, 0)
return
}
RunWith(WatcherFromFlag(""), sources)

RunWith(newSignalWatcher(), sources, 0)
}

// Stop any projects are watched by the RunWith/Run method, this function should be call when you call the Run inside a goroutine.
Expand Down
Loading

0 comments on commit 163865a

Please sign in to comment.