diff --git a/README.md b/README.md index c6131a2..8918ea4 100644 --- a/README.md +++ b/README.md @@ -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" +``` + diff --git a/cmd/watcher/README.md b/cmd/watcher/README.md index 0dc6740..37c9f50 100644 --- a/cmd/watcher/README.md +++ b/cmd/watcher/README.md @@ -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" +``` diff --git a/cmd/watcher/config/config.go b/cmd/watcher/config/config.go new file mode 100644 index 0000000..e31da21 --- /dev/null +++ b/cmd/watcher/config/config.go @@ -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 + } +} diff --git a/cmd/watcher/config/config_test.go b/cmd/watcher/config/config_test.go new file mode 100644 index 0000000..4c8330e --- /dev/null +++ b/cmd/watcher/config/config_test.go @@ -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") + } +} diff --git a/cmd/watcher/main.go b/cmd/watcher/main.go index 60e2827..5b6d0f6 100644 --- a/cmd/watcher/main.go +++ b/cmd/watcher/main.go @@ -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() @@ -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:] @@ -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) @@ -79,9 +81,9 @@ 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 @@ -89,7 +91,7 @@ func main() { 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 } @@ -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) } @@ -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()) } @@ -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) } @@ -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