💡 Happy Sunday: Introducing rizla

This commit is contained in:
Makis Maropoulos 2016-06-26 16:26:44 +03:00
parent bd91395b19
commit 6391ba04ca
4 changed files with 18 additions and 216 deletions

View File

@ -2,7 +2,7 @@
[![Travis Widget]][Travis] [![Release Widget]][Release] [![Report Widget]][Report] [![License Widget]][License] [![Gitter Widget]][Gitter] [![Documentation Widget]][Documentation]
[Travis Widget]: https://img.shields.io/travis/tmrts/boilr.svg?style=flat-square
[Travis Widget]: https://img.shields.io/travis/kataras/iris.svg?style=flat-square
[Travis]: http://travis-ci.org/kataras/iris
[License Widget]: https://img.shields.io/badge/license-MIT%20%20License%20-E91E63.svg?style=flat-square
[License]: https://github.com/kataras/iris/blob/master/LICENSE
@ -51,7 +51,7 @@ func main() {
Installation
------------
The only requirement is Go 1.6
The only requirement is the [Go Programming Language](https://golang.org/dl), at least v1.6
`$ go get -u github.com/kataras/iris/iris`
@ -181,7 +181,6 @@ If you are interested in contributing to the Iris project, please see the docume
Third-Party Licenses
------------
This project is using third-party libraries to achieve this result.
Third-Party Licenses can be found [here](THIRDPARTY-LICENSE.md)

View File

@ -8,7 +8,7 @@ Third party packages
- [blackfriday is one of the supporting template engines](https://github.com/russross/blackfriday)
- [klauspost/gzip for faster compression](https://github.com/klauspost/compress)
- [httprouter](https://github.com/julienschmidt/httprouter) for the basic BSD kernel's [trie algorithm](https://en.wikipedia.org/wiki/Trie) used inside [muxEntry](https://github.com/kataras/iris/blob/master/http.go#L578), edited by [Iris' author](https://github.com/kataras) to improve its performance and achieve 0 memory allocations per operation.
- [goo](https://github.com/kataras/goo) used inside iris command line tool
- [rizla](https://github.com/kataras/rizla) used inside iris command line tool
- [cli](https://github.com/kataras/cli) used inside iris command line tool
- [color](https://github.com/fatih/color) with [go-colorable](https://github.com/mattn/go-colorable) for the logger's colors]
- [mergo for merge configs](https://github.com/imdario/mergo)

View File

@ -1,181 +1,32 @@
package main
import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync/atomic"
"github.com/iris-contrib/errors"
"github.com/kataras/cli"
"github.com/kataras/iris/utils"
"github.com/kataras/rizla/rizla"
)
var (
errInvalidArgs = errors.New("Invalid arguments [%s], type -h to get assistant")
errInvalidExt = errors.New("%s is not a go program")
errUnexpected = errors.New("Unexpected error!!! Please post an issue here: https://github.com/kataras/iris/issues")
errBuild = errors.New("\n Failed to build the %s iris program. Trace: %s")
errRun = errors.New("\n Failed to run the %s iris program. Trace: %s")
goExt = ".go"
)
var times uint32
func build(sourcepath string) error {
goBuild := utils.CommandBuilder("go", "build", sourcepath)
goBuild.Dir = workingDir
goBuild.Stdout = os.Stdout
goBuild.Stderr = os.Stderr
if err := goBuild.Run(); err != nil {
ferr := errBuild.Format(sourcepath, err.Error())
printer.Dangerf(ferr.Error())
return ferr
}
return nil
}
func run(executablePath string) (*utils.Cmd, error) {
runCmd := utils.CommandBuilder("." + utils.PathSeparator + executablePath)
runCmd.Dir = workingDir
runCmd.Stderr = os.Stderr
runCmd.Stdout = os.Stdout
if err := runCmd.Start(); err != nil {
ferr := errRun.Format(executablePath, err.Error())
printer.Dangerf(ferr.Error())
return nil, ferr
}
times++
return runCmd, nil
}
func runAndWatch(flags cli.Flags) error {
if len(os.Args) <= 2 {
err := errInvalidArgs.Format(strings.Join(os.Args, ","))
printer.Dangerf(err.Error())
return err
}
isWindows := runtime.GOOS == "windows"
programPath := ""
executablePath := ""
filenameCh := make(chan string)
if len(os.Args) > 2 { // iris run main.go
programPath = os.Args[2]
if programPath[len(programPath)-1] == '/' {
programPath = programPath[0 : len(programPath)-1]
}
if filepath.Ext(programPath) != goExt {
return errInvalidExt.Format(programPath)
}
// check if we have a path,change the workingdir and programpath
if lidx := strings.LastIndexByte(programPath, os.PathSeparator); lidx > 0 { // no /
workingDir = workingDir + utils.PathSeparator + programPath[0:lidx]
programPath = programPath[lidx+1:]
} else if lidx := strings.LastIndexByte(programPath, '/'); lidx > 0 { // no /
workingDir = workingDir + "/" + programPath[0:lidx]
programPath = programPath[lidx+1:]
}
executablePath = programPath[:len(programPath)-3]
if isWindows {
executablePath += ".exe"
}
}
subfiles, err := ioutil.ReadDir(workingDir)
if err != nil {
printer.Dangerf(err.Error())
return err
}
var paths []string
paths = append(paths, workingDir)
for _, subfile := range subfiles {
if subfile.IsDir() {
if abspath, err := filepath.Abs(workingDir + utils.PathSeparator + subfile.Name()); err == nil {
paths = append(paths, abspath)
}
}
}
// run the file watcher before all, because the user maybe has a go syntax error before the first run
utils.WatchDirectoryChanges(paths, func(fname string) {
//remove the working dir from the fname path, printer should only print the relative changed file ( from the project's path)
fname = fname[len(workingDir)+1:]
if (filepath.Ext(fname) == goExt) || (!isWindows && strings.Contains(fname, goExt)) { // on !windows it sends a .gooutput_RANDOM_STRINGHERE, Note that: we do contains instead of HasPrefix
filenameCh <- fname
}
}, printer)
if err = build(programPath); err != nil {
printer.Dangerf(err.Error())
return err
}
runCmd, err := run(executablePath)
if err != nil {
printer.Dangerf(err.Error())
return err
}
// here(below), we don't return the error because the -help command doesn't help the user for these errors.
defer func() {
printer.Dangerf("")
printer.Panic(errUnexpected)
}()
for {
select {
case fname := <-filenameCh:
{
// it's not a warning but I like to use purple color for this message
if !isWindows {
fname = " " // we don't want to print the ".gooutput..." so dont print anything as a name
}
printer.Infof("[OP: %d] File %s changed, reloading...", atomic.LoadUint32(&times), fname)
//kill the prev run
err := runCmd.Process.Kill()
if err == nil {
_, err = runCmd.Process.Wait()
} else {
// force kill, sometimes runCmd.Process.Kill or Signal(os.Kill) doesn't kills
if isWindows {
err = utils.CommandBuilder("taskkill", "/F", "/T", "/PID", strconv.Itoa(runCmd.Process.Pid)).Run()
} else {
err = utils.CommandBuilder("kill", "-INT", "-"+strconv.Itoa(runCmd.Process.Pid)).Run()
}
}
err = build(programPath)
if err != nil {
printer.Warningf(err.Error())
} else {
if runCmd, err = run(executablePath); err != nil {
printer.Warningf(err.Error() + "\n")
} else {
// we did .Start, but it should be fast so no need to add a sleeper
printer.Successf("ready!\n")
}
}
}
}
printer.Dangerf("Invalid arguments [%s], type -h to get assistant", strings.Join(os.Args, ","))
os.Exit(-1)
}
programPath := os.Args[2]
/*project := rizla.NewProject(programPath)
project.Name = "IRIS"
project.AllowReloadAfter = time.Duration(3) * time.Second
rizla.Add(project)
rizla.Out = os.Stdout
rizla.Err = os.Stderr
rizla.Run()*/
// or just do that:
rizla.Run(programPath)
return nil
}

View File

@ -12,9 +12,6 @@ import (
"runtime"
"strings"
"time"
"github.com/fsnotify/fsnotify"
"github.com/kataras/iris/logger"
)
const (
@ -332,48 +329,3 @@ func GetParentDir(targetDirectory string) string {
parentDirectory := targetDirectory[0:lastSlashIndex]
return parentDirectory
}
/*
// 3-BSD License for package fsnotify/fsnotify
// Copyright (c) 2012 The Go Authors. All rights reserved.
// Copyright (c) 2012 fsnotify Authors. All rights reserved.
*/
// WatchDirectoryChanges watches a directory and fires the callback with the changed name, receives a logger just to print with red letters any errors, no need for second callback.
func WatchDirectoryChanges(paths []string, evt func(filename string), logger *logger.Logger) {
isWindows := runtime.GOOS == "windows"
watcher, werr := fsnotify.NewWatcher()
if werr != nil {
logger.Dangerf(werr.Error())
return
}
go func() {
var lastChange = time.Now()
var i = 0
for {
select {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
//this is received two times, the last time is the real changed file, so
i++
if i%2 == 0 || !isWindows { // this 'hack' works for windows & linux but I dont know if works for osx too, we can wait for issue reports here.
if time.Now().After(lastChange.Add(time.Duration(1) * time.Second)) {
lastChange = time.Now()
evt(event.Name)
}
}
}
case err := <-watcher.Errors:
logger.Dangerf(err.Error())
}
}
}()
for _, p := range paths {
if werr = watcher.Add(p); werr != nil {
logger.Dangerf(werr.Error())
}
}
}