interval loop implemented, consolidated code
This commit is contained in:
parent
4f2d3acf7c
commit
f766c14846
3 changed files with 117 additions and 41 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.vscode
|
130
listen.go
130
listen.go
|
@ -16,12 +16,49 @@ import (
|
|||
)
|
||||
|
||||
type Listen struct {
|
||||
FileMap map[string]bool
|
||||
CksumMap map[string][]byte
|
||||
Condition string
|
||||
Cksum bool
|
||||
Interval string
|
||||
Command []string
|
||||
FileMap map[string]bool
|
||||
CksumMap map[string][]byte
|
||||
IntervalMap map[string]time.Time
|
||||
Condition string
|
||||
Cksum bool
|
||||
Interval time.Duration
|
||||
Command []string
|
||||
Quiet bool
|
||||
}
|
||||
|
||||
func cksumCheck(l Listen, k string, t *bool) bool {
|
||||
hasher := sha256.New()
|
||||
f, err := os.Open(k)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !slices.Equal(l.CksumMap[k], hasher.Sum(nil)) {
|
||||
l.CksumMap[k] = hasher.Sum(nil)
|
||||
if l.Condition == "any" {
|
||||
*t = true
|
||||
return true
|
||||
}
|
||||
|
||||
l.FileMap[k] = true
|
||||
}
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
func allCheck(l Listen) bool {
|
||||
for value := range maps.Values(l.FileMap) {
|
||||
if !value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func loopFsnotify(l Listen, quit chan bool) {
|
||||
|
@ -33,12 +70,10 @@ func loopFsnotify(l Listen, quit chan bool) {
|
|||
defer watcher.Close()
|
||||
for key := range l.FileMap {
|
||||
watcher.Add(key)
|
||||
fmt.Println(watcher.WatchList())
|
||||
}
|
||||
|
||||
for {
|
||||
var renameAdd []string = []string{}
|
||||
hasher := sha256.New()
|
||||
trigger := false
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
|
@ -49,23 +84,9 @@ func loopFsnotify(l Listen, quit chan bool) {
|
|||
for key := range l.FileMap {
|
||||
if event.Name == key {
|
||||
if l.Cksum {
|
||||
f, err := os.Open(key)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !slices.Equal(l.CksumMap[key], hasher.Sum(nil)) {
|
||||
if l.Condition == "any" {
|
||||
trigger = true
|
||||
break
|
||||
}
|
||||
|
||||
l.FileMap[key] = true
|
||||
// return value indicates a break is needed
|
||||
if cksumCheck(l, key, &trigger) {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if event.Has(fsnotify.Write) {
|
||||
|
@ -93,14 +114,8 @@ func loopFsnotify(l Listen, quit chan bool) {
|
|||
} // end for
|
||||
|
||||
if l.Condition == "all" {
|
||||
trigger = true
|
||||
for value := range maps.Values(l.FileMap) {
|
||||
if !value {
|
||||
trigger = false
|
||||
break
|
||||
}
|
||||
}
|
||||
} // end if condition
|
||||
trigger = allCheck(l)
|
||||
}
|
||||
// end case event
|
||||
case _, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
|
@ -131,8 +146,49 @@ func loopFsnotify(l Listen, quit chan bool) {
|
|||
|
||||
func loopInterval(l Listen, quit chan bool) {
|
||||
for {
|
||||
fmt.Printf("running")
|
||||
time.Sleep(1 * time.Second)
|
||||
time.Sleep(l.Interval)
|
||||
trigger := false
|
||||
|
||||
for key := range l.FileMap {
|
||||
if l.Cksum {
|
||||
// return value indicates a break is needed
|
||||
if cksumCheck(l, key, &trigger) {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
s, err := os.Stat(key)
|
||||
if err != nil {
|
||||
log.Fatal()
|
||||
}
|
||||
|
||||
if l.IntervalMap[key] != s.ModTime() {
|
||||
l.IntervalMap[key] = s.ModTime()
|
||||
if l.Condition == "any" {
|
||||
trigger = true
|
||||
break
|
||||
}
|
||||
|
||||
l.FileMap[key] = true
|
||||
}
|
||||
|
||||
}
|
||||
} // end for key
|
||||
|
||||
if l.Condition == "all" {
|
||||
trigger = allCheck(l)
|
||||
}
|
||||
|
||||
if trigger {
|
||||
if len(l.Command) >= 1 {
|
||||
cmd := exec.Command(l.Command[0], l.Command[1:]...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Run()
|
||||
} else {
|
||||
quit <- true
|
||||
}
|
||||
} // end if trigger
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,8 +198,8 @@ func (l Listen) Run() {
|
|||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
|
||||
// main loop
|
||||
if l.Interval == "" {
|
||||
// start main loop
|
||||
if l.Interval == time.Duration(0*time.Second) {
|
||||
go loopFsnotify(l, quit)
|
||||
} else {
|
||||
go loopInterval(l, quit)
|
||||
|
|
27
main.go
27
main.go
|
@ -8,6 +8,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
flags "github.com/jessevdk/go-flags"
|
||||
)
|
||||
|
@ -16,13 +17,15 @@ const VERSION string = "v0.1.0"
|
|||
|
||||
var opts struct {
|
||||
Version bool `short:"v" long:"version" description:"Displays version info and exits"`
|
||||
Quiet bool `short:"q" long:"quiet" description:"Suppresses all non-error output"`
|
||||
Files []string `short:"f" long:"file" description:"File(s) to listen to (watch)" value-name:"FILE"`
|
||||
Condition string `short:"w" long:"when" description:"If multiple files are specified, choose if any file or all files specified are needed to trigger COMMAND" default:"any" choice:"any" choice:"all"`
|
||||
Checksum bool `short:"c" long:"checksum" description:"Use checksum to determine when file(s) are changed instead of writes/modification time"`
|
||||
Interval string `short:"i" long:"interval" description:"Use this time interval (ex. 5m30s, 1s) between filesystem checks instead of using kernel events"`
|
||||
Interval string `short:"i" long:"interval" description:"Use this time interval (ex. 5m30s, 1s) between filesystem checks instead of watching kernel events. If the interval is effectively 0 (the default), kernel events are used" default:"0s"`
|
||||
}
|
||||
|
||||
func validateFiles(files []string) error {
|
||||
func validateArgs(files []string, interval string) error {
|
||||
// file checks
|
||||
if len(files) <= 0 {
|
||||
fmt.Println("listen: at least one file (-f) is required")
|
||||
return flags.ErrCommandRequired
|
||||
|
@ -47,6 +50,12 @@ func validateFiles(files []string) error {
|
|||
}
|
||||
}
|
||||
|
||||
// interval checks
|
||||
if _, err := time.ParseDuration(interval); err != nil {
|
||||
fmt.Printf("listen: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -58,9 +67,11 @@ func main() {
|
|||
if err == nil {
|
||||
if opts.Version {
|
||||
fmt.Printf("listen %s\n", VERSION)
|
||||
} else if err := validateFiles(opts.Files); err == nil {
|
||||
} else if err := validateArgs(opts.Files, opts.Interval); err == nil {
|
||||
var filesMap map[string]bool = make(map[string]bool)
|
||||
var cksumMap map[string][]byte = make(map[string][]byte)
|
||||
var intervalMap map[string]time.Time = make(map[string]time.Time)
|
||||
intervalDuration, _ := time.ParseDuration(opts.Interval)
|
||||
success := true
|
||||
for _, file := range opts.Files {
|
||||
hasher := sha256.New()
|
||||
|
@ -69,6 +80,13 @@ func main() {
|
|||
success = false
|
||||
break
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
s, err := os.Stat(file)
|
||||
if err != nil {
|
||||
success = false
|
||||
break
|
||||
}
|
||||
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -78,6 +96,7 @@ func main() {
|
|||
if err == nil {
|
||||
filesMap[abs] = false
|
||||
cksumMap[abs] = hasher.Sum(nil)
|
||||
intervalMap[abs] = s.ModTime()
|
||||
} else {
|
||||
success = false
|
||||
break
|
||||
|
@ -85,7 +104,7 @@ func main() {
|
|||
}
|
||||
|
||||
if success {
|
||||
l := Listen{filesMap, cksumMap, opts.Condition, opts.Checksum, opts.Interval, remaining}
|
||||
l := Listen{filesMap, cksumMap, intervalMap, opts.Condition, opts.Checksum, intervalDuration, remaining, opts.Quiet}
|
||||
l.Run()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue