Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow the use of Config files #61

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,28 @@ watcher -cmd="python script.py" -pipe=true
```

Now when changes are detected, the event's info will be output from the running python script.

# Config file

All of the command line flags can be set using a json config file like below. Any config values that are
not declared will use its default values instead.

```json
{
"recursive" : false,
"dotfiles": false,
"cmd": "python script.py",
"interval": "250ms",
"listfiles": true,
"pipe": true,
"keepalive": true
}

```
You can use the config file by supplying the full path and name of config file to `-config` comand line flag
like in the example below.

```shell
watcher -config="watcher.json"
```

24 changes: 24 additions & 0 deletions cmd/watcher/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,27 @@ watcher -cmd="python script.py" -pipe=true
```

Now when changes are detected, the event's info will be output from the running python script.

# Config file

All of the command line flags can be set using a json config file like below. Any config values that are
not declared will use its default values instead.

```json
{
"recursive" : false,
"dotfiles": false,
"cmd": "python script.py",
"interval": "250ms",
"listfiles": true,
"pipe": true,
"keepalive": true
}

```
You can use the config file by supplying the full path and name of config file to `-config` comand line flag
like in the example below.

```shell
watcher -config="watcher.json"
```
146 changes: 146 additions & 0 deletions cmd/watcher/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package config

import (
"encoding/json"
"flag"
"io/ioutil"
"os"
)

// Config values that can be used in a json file.
type Config struct {
Interval string `json:"interval"`
Recursive bool `json:"recursive"`
Dotfiles bool `json:"dotfiles"`
Cmd string `json:"cmd"`
Startcmd bool `json:"startcmd"`
ListFiles bool `json:"listfiles"`
StdinPipe bool `json:"pipe"`
Keepalive bool `json:"keepalive"`
Ignore string `json:"ignore"`
}

var c Config

// GetConfig Checks for a user defined config file. If there is no config file the
// command line flags or their defaults are used.
func GetConfig() Config {
configFile := flag.String("config", "", "config file")
interval := flag.String("interval", "100ms", "watcher poll interval")
recursive := flag.Bool("recursive", true, "watch folders recursively")
dotfiles := flag.Bool("dotfiles", true, "watch dot files")
cmd := flag.String("cmd", "", "command to run when an event occurs")
startcmd := flag.Bool("startcmd", false, "run the command when watcher starts")
listFiles := flag.Bool("list", false, "list watched files on start")
stdinPipe := flag.Bool("pipe", false, "pipe event's info to command's stdin")
keepalive := flag.Bool("keepalive", false, "keep alive when a cmd returns code != 0")
ignore := flag.String("ignore", "", "comma separated list of paths to ignore")

flag.Parse()

// If the configfile flag is defined use its values.
if len(*configFile) > 0 {
jsonFile, err := os.Open(*configFile)
if err != nil {
panic(err)
}

defer jsonFile.Close()

byteValue, error := ioutil.ReadAll(jsonFile)
if error != nil {
panic(error)
}

var data Config
json.Unmarshal(byteValue, &data)
// Set config values. If a value is not set in the config file
// the default value will be used.
c.setInterval(data.Interval)
c.setRecursive(data.Recursive)
c.setDotfiles(data.Dotfiles)
c.setCmd(data.Cmd)
c.setStartCmd(data.Startcmd)
c.setListFiles(data.ListFiles)
c.setPipe(data.StdinPipe)
c.setKeepAlive(data.Keepalive)
c.setIgnore(data.Ignore)

} else {
//Use CLI values
c.Interval = *interval
c.Recursive = *recursive
c.Dotfiles = *dotfiles
c.Cmd = *cmd
c.Startcmd = *startcmd
c.ListFiles = *listFiles
c.StdinPipe = *stdinPipe
c.Keepalive = *keepalive
c.Ignore = *ignore
}

return c
}

func (c *Config) setInterval(interval string) {
c.Interval = "200ms"
if len(interval) > 0 {
c.Interval = interval
}
}

func (c *Config) setRecursive(recursive bool) {
c.Recursive = true
if !recursive {
c.Recursive = false
}
}

func (c *Config) setDotfiles(dotfiles bool) {
c.Dotfiles = true
if !dotfiles {
c.Dotfiles = false
}
}

func (c *Config) setCmd(cmd string) {
c.Cmd = ""
if len(cmd) > 0 {
c.Cmd = cmd
}
}

func (c *Config) setStartCmd(startCmd bool) {
c.Startcmd = false
if startCmd {
c.Startcmd = true
}
}

func (c *Config) setListFiles(listFiles bool) {
c.ListFiles = false
if listFiles {
c.ListFiles = true
}
}

func (c *Config) setPipe(pipe bool) {
c.StdinPipe = false
if pipe {
c.StdinPipe = true
}
}

func (c *Config) setKeepAlive(keepAlive bool) {
c.Keepalive = false
if keepAlive {
c.Keepalive = true
}
}

func (c *Config) setIgnore(ignore string) {
c.Ignore = ""
if len(ignore) > 0 {
c.Ignore = ignore
}
}
68 changes: 68 additions & 0 deletions cmd/watcher/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package config_test

import (
"testing"

"github.com/radovskyb/watcher/cmd/watcher/config"
)

type Defaults = struct {
interval string
expected interface{}
}

var c = config.GetConfig()

func TestDefaultsInterval(t *testing.T) {
if c.Interval != "200ms" {
t.Error("Failed to set default Interval value")
}
}

func TestDefaultRecursive(t *testing.T) {
if !c.Recursive {
t.Error("Failed to set default Recursive value")
}
}

func TestDefaultDotFiles(t *testing.T) {
if !c.Dotfiles {
t.Error("Failed to set default Dot files value")
}
}

func TestDefaultCmd(t *testing.T) {
if c.Cmd != "" {
t.Error("Failed to set default CMD value")
}
}

func TestDefaultStartCmd(t *testing.T) {
if c.Startcmd {
t.Error("Failed to set default StartCmd value")
}
}

func TestDefaultListFiles(t *testing.T) {
if c.ListFiles {
t.Error("Failed to set default Listfiles value")
}
}

func TestDefaultStdinPipe(t *testing.T) {
if c.StdinPipe {
t.Error("Failed to set default StdinPipe value")
}
}

func TestDefaultKeepAlive(t *testing.T) {
if c.Keepalive {
t.Error("Failed to set default KeepAlive value")
}
}

func TestDefaultIgnore(t *testing.T) {
if c.Ignore != "" {
t.Error("Failed to set default file ignore value")
}
}
42 changes: 22 additions & 20 deletions cmd/watcher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@ import (
"unicode"

"github.com/radovskyb/watcher"
"github.com/radovskyb/watcher/cmd/watcher/config"
)

func main() {
interval := flag.String("interval", "100ms", "watcher poll interval")
recursive := flag.Bool("recursive", true, "watch folders recursively")
dotfiles := flag.Bool("dotfiles", true, "watch dot files")
cmd := flag.String("cmd", "", "command to run when an event occurs")
startcmd := flag.Bool("startcmd", false, "run the command when watcher starts")
listFiles := flag.Bool("list", false, "list watched files on start")
stdinPipe := flag.Bool("pipe", false, "pipe event's info to command's stdin")
keepalive := flag.Bool("keepalive", false, "keep alive when a cmd returns code != 0")
ignore := flag.String("ignore", "", "comma separated list of paths to ignore")
config := config.GetConfig()
interval := config.Interval
recursive := config.Recursive
dotfiles := config.Dotfiles
cmd := config.Cmd
startcmd := config.Startcmd
listFiles := config.ListFiles
stdinPipe := config.StdinPipe
keepalive := config.Keepalive
ignore := config.Ignore

flag.Parse()

Expand All @@ -41,8 +43,8 @@ func main() {

var cmdName string
var cmdArgs []string
if *cmd != "" {
split := strings.FieldsFunc(*cmd, unicode.IsSpace)
if cmd != "" {
split := strings.FieldsFunc(cmd, unicode.IsSpace)
cmdName = split[0]
if len(split) > 1 {
cmdArgs = split[1:]
Expand All @@ -51,10 +53,10 @@ func main() {

// Create a new Watcher with the specified options.
w := watcher.New()
w.IgnoreHiddenFiles(!*dotfiles)
w.IgnoreHiddenFiles(!dotfiles)

// Get any of the paths to ignore.
ignoredPaths := strings.Split(*ignore, ",")
ignoredPaths := strings.Split(ignore, ",")

for _, path := range ignoredPaths {
trimmed := strings.TrimSpace(path)
Expand All @@ -79,17 +81,17 @@ func main() {
fmt.Println(event)

// Run the command if one was specified.
if *cmd != "" {
if cmd != "" {
c := exec.Command(cmdName, cmdArgs...)
if *stdinPipe {
if stdinPipe {
c.Stdin = strings.NewReader(event.String())
} else {
c.Stdin = os.Stdin
}
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if err := c.Run(); err != nil {
if (c.ProcessState == nil || !c.ProcessState.Success()) && *keepalive {
if (c.ProcessState == nil || !c.ProcessState.Success()) && keepalive {
log.Println(err)
continue
}
Expand All @@ -110,7 +112,7 @@ func main() {

// Add the files and folders specified.
for _, file := range files {
if *recursive {
if recursive {
if err := w.AddRecursive(file); err != nil {
log.Fatalln(err)
}
Expand All @@ -122,7 +124,7 @@ func main() {
}

// Print a list of all of the files and folders being watched.
if *listFiles {
if listFiles {
for path, f := range w.WatchedFiles() {
fmt.Printf("%s: %s\n", path, f.Name())
}
Expand All @@ -132,7 +134,7 @@ func main() {
fmt.Printf("Watching %d files\n", len(w.WatchedFiles()))

// Parse the interval string into a time.Duration.
parsedInterval, err := time.ParseDuration(*interval)
parsedInterval, err := time.ParseDuration(interval)
if err != nil {
log.Fatalln(err)
}
Expand All @@ -151,7 +153,7 @@ func main() {

// Run the command before watcher starts if one was specified.
go func() {
if *cmd != "" && *startcmd {
if cmd != "" && startcmd {
c := exec.Command(cmdName, cmdArgs...)
c.Stdin = os.Stdin
c.Stdout = os.Stdout
Expand Down