Giter VIP home page Giter VIP logo

watcher's People

Contributors

ch00k avatar ciolfr avatar ericmdantas avatar fvosberg avatar gmccue avatar harshavardhana avatar le-g avatar phantas0s avatar radovskyb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

watcher's Issues

To list all new files since last watcher run

Hi,

Is watcher able to list all new files created since last watcher run ? We have a situation we are continuously watching a directory and if the watcher was stopped interrupted and resume again, are anyway to to list all new files creation in between or any alternatives ?

Thank you !

Path is empty

image

Interestingly the Path is empty so I can't be sure of the absolute path of the file.

Support debouncing watch events

When I modify multiple files in one shot (such as using "save all" in an IDE), multiple events are fired and the command is executed for each event. It would be nice if there is the ability to debounce the events so that if multiple files are modified together, the command is only executed once.

Use watcher on virtualbox synced folders

Hello,

@radovskyb Thank you very much for the great software!

I use Vagrant over Virtualbox with synced folder of type Virtualbox.
My host system is Windows 10 Creator's Update, my guest system is Ubuntu 16.04 with Go 1.8.3.
As described, watcher does not work with synced folders on Virtualbox if I trigger an event from the host OS in the synchronized folder while running watcher in the guest OS.

Is that logical? What should I do to workaround this?

Thank you! :)

how ignore errors adding folder recursively

Hello @radovskyb , hope you're fine, I'm having this error when I run a recursive watcher

error agregando directorio  open C:\$RECYCLE.BIN\S-1-5-18: Access is denied.

that means error adding a directory, after that the file walker seems exit because it doesn't add any other file

	i := 0
	fmt.Println(len(w.WatchedFiles()))
	fmt.Println("first 10 watched files are:")
	for path,_ := range w.WatchedFiles(){
		i+=1

		fmt.Println(path)
		if i>10{
			break
		}

	}

//print 0 

Could I ignore those files which cause error and keep running the file walker?

thank you so much!!!

Max_Path error in isHidden_windows.go

isHidden_windows.go was throwing the error: "The system cannot find the path specified."

I discovered this was due to syscall.UTF16PtrFromString(pointer) not working with file paths longer than 260 characters.*

I fixed it by changing syscall.UTF16PtrFromString(path) to syscall.UTF16PtrFromString(fixLongPath(path)), and adding an extra file containing this:
https://golang.org/src/os/path_windows.go?h=fixLongPath#L139

* https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#maximum-path-length-limitation

startcmd ignores keepalive

Hi,

first of all, thanks for implementing a watcher, which is as small and concise, as I want it to be!!

I've found a little bug in my humble opinion, though:

If you start the watcher with keepalive flag and startcmd flag, and the command returns a non zero.

watcher -cmd="false" --keepalive --startcmd

Help wanted

Hi, radovskyb!

I am learning your code. I cannot understand these code :

go func() {
		w.Wait()
		w.TriggerEvent(watcher.Create, nil)
		w.TriggerEvent(watcher.Remove, nil)
	}()

go func() {
w.Wait()
w.TriggerEvent(watcher.Create, nil)
w.TriggerEvent(watcher.Remove, nil)
}()
.

What I don't understand is why w.Wait() can use more than once. I searched by google, but no useful answer. so, I hope get you help.

Thank you very much!

Filewatcher hangs on error

When encountering an error (in my case an ErrWatchedFileDeleted), the filewatcher seems to stop (even though it's not Closed, so I cannot restart it) and I'm not receiving any more events.

Is this a bug or am I not handling errors properly ?

My code looks very much like the examples provided, and I encounter this error because a temp file is quickly added and removed from the fs (and I just want to ignore it).

Thanks !

Renamed files

Hi, how can I know the renamed file name?
Where I rename a file, the event "created" is thrown but I get only the old name of the file. This is the code:

go func() {
	defer wg.Done()

	for {
		select {
		case event := <-w.Event:

			fmt.Println(event)

			fileType := func() string {
				if event.IsDir() {
					return "Directory"
				} else {
					return "File"
				}
			}

			switch event.Op {
			case watcher.Write:
				s := fmt.Sprintf("Wrote %v: %v", fileType(), event.Name())
				fmt.Println(s)
			case watcher.Create:
				s := fmt.Sprintf("Created %v: %v", fileType(), event.Name())
				fmt.Println(s)
			case watcher.Remove:
				s := fmt.Sprintf("Removed %v: %v", fileType(), event.Name())
				fmt.Println(s)
			case watcher.Rename:
				s := fmt.Sprintf("Renamed %v: %v", fileType(), event.Name())
				fmt.Println(s)
			case watcher.Chmod:
				s := fmt.Sprintf("Chmoded %v: %v", fileType(), event.Name())
				fmt.Println(s)
			}
		case err := <-w.Error:
			log.Fatalln(err)
		}
	}
}()

I need to know the name of the file after it was renamed. I tried to comment out the line w.SetMaxEvents(1) so I thought that All event would be sent but doesn't work

Thanks

Watcher stops working when you delete watched files

@radovskyb Currently watcher stops working when you delete the watched file/directory. It's a bumper for my upcoming release.

It gives an error.

2017-07-21 12:01:02.729 ERROR Watch error:error: watched file or folder deleted

Doesn't return any events there after. And If you call w.Close() at this moment, program gets stuck.

Please let me know if you need further info.

PS: wether you call Close or not, watcher stops working

Renaming on windows

It would seem that on windows there is no rename event but rather the following:

  • rename file/folder
  • CREATE event (new name)
  • REMOVE event (old name)

So there is never a RENAME event actually ever firing.

Close watcher

Is there any way we can close the watcher? I was thinking that since we have Start, we could also have a Close method.

There's a module for Node.js called chokidar (https://github.com/paulmillr/chokidar) who does the following:

Methods and events
[...]
.close(): Removes all listeners from watched files

In my opinion, it'd make sense to have this in watcher too.

ignoreHidden not working on windows

Ignor hiden files not working on windows.
I belive strings.HasPrefix(info.Name(), ".") work on linux, but not on windows.
On windows system app get stok for example on c:\System Volume Information
How to avoid this problem?

2018/11/22 17:14:23 error: (EXTRA *os.PathError=open \......\d$\System Volume Information: Access is denied.)

WatchedFiles thread safety

WatchedFiles() creates a possible race condition. Reading the returned map while simultaneously calling any functions that mutate files (Add/AddRecursive/Remove/RemoveRecursive) is not thread safe. Locking the mutex in WatchedFiles does not help.

support parameter deep

Hi...would be great if you could support a deep parameter, what do you think???

thank you...

Observing high CPU Usage when watching on large directories. Expected?

I have a few questions regarding the library itself

  • Since there is a constant file walking don't you think crawling in this manner
    would spin the disks up all the time?
  • There are no asynchronous awake events, is there a possibility events might get lost?
  • Some small tests seem to work fine, but i am worried about large directories and deep d
    directory structures?

No close_write event in watcher - need to move a large file but only if it's closed

I have a scenario, where I want to move a large file (4GB) to an S3 bucket once it's written to a watched directory on the local disk. The process of writing a file to the local directory is time-consuming.

I am waiting for the Create event and then I run 'move to s3 bucket' process, which will, unfortunately, only upload a portion of the file (as the rest of the file is still being written to the disk).

I have tested using Create and Write event, but those two trigger before a file is completed.

Look like we'd need close_write event to be implemented into the watcher, so it works similar to :
inotifywait -e close_write /path/to/file
https://unix.stackexchange.com/questions/176387/move-file-but-only-if-its-closed

Watching sub-directories by design?

I noticed that by default, calling Add() on a directory will also watch any sub-directories, but not files within those sub-directories. That means if I have a directory structure like this:

โ”œโ”€โ”€ root_dir
โ”‚ย ย  โ”œโ”€โ”€ sub_dir

and then do this:

w := watcher.New()
...
w.Add('/root_dir')

And then run touch root_dir/sub_dir, a WRITE event is fired.

Just wondering.... is this by design? Or should nested dirs be ignored unless added explicitly or recursively?

watcher misses events for the same file if they were generated within one pollInterval

This code will reproduce the problem:

package main

import (
	"log"
	"time"

	"github.com/radovskyb/watcher"
)

const watchDir = "/Users/ay/tmp/watch"

func main() {
	w := watcher.New()

	go func() {
		for {
			select {
			case event := <-w.Event:
				log.Println(event, event.Name(), event.ModTime())
			case err := <-w.Error:
				panic(err)
			}
		}
	}()

	if err := w.Add(watchDir); err != nil {
		panic(err)
	}

	if err := w.Start(time.Millisecond * 100); err != nil {
		panic(err)
	}
}

Run it, then in another terminal cd to the watched directory (/Users/ay/tmp/watch in this case) and execute touch 1; rm 1, which will miss both events, or touch 1; echo "test" > 1, which will miss the CREATE event.

Support regular expressions as filters

Would be handy to be able to filter recursivley watching newly created files based on regular expressions. When watching a folder recursively it would be nice to be able to not set watches on subfolders or files that get created but match a regular expression added to the filters list.

Support for globs

Would it be possible for the watcher API to support Globs as arguments to the Add and Ignore methods? This would make watching specific directories for only certain file types much easier:

w.Add("./**/*.go")

Or is there a way to achieve this with the current interface?

Support ability to terminate previous invocation of command on new event

It would be nice if there is an option to terminate the previous invocation of the command when the command is still executing and a file changes. This would be extremely useful when the command is a task that takes a while to complete and we do not wish to wait for it to finish and want to invoke the command immediate again.

Signal that a watching process was started

Problema

How to figure out that a watching process started?
I have such construction. It don't like it. But it's pretty fast for me.

  1. I set up a watcher on a directory.
  2. Then I call a exe which write files inside the directory.
    If some reason the exe will write before the watcher start to watch I will lost data.
    I am worry some people can do it without suspecting of problem.
    I don't set some block operations between Start and gorutine. But any:heavy_exclamation_mark:block operation will ruin all logic.
w := watcher.New()
...

go func () {
	time.Sleep(time.Second) // now I use timer for sure
	cmd := exec.Command(
		"python",
		"emulate_renderer.py",
		d.req,
	)
	err := cmd.Run()
}()
// Start the watching process - it'll check for changes every 100ms.
if err := w.Start(time.Millisecond * 100); err != nil {
	println(err.Error())
	... // handling
}
...

Proposal

Set some block element like chan int

w := watcher.New()
...

go func () {
	<-w.Started // block until watcher will be started
	cmd := exec.Command(
		"python",
		"emulate_renderer.py",
		d.req,
	)
	err := cmd.Run()
}()
// Start the watching process - it'll check for changes every 100ms.
if err := w.Start(time.Millisecond * 100); err != nil {
	println(err.Error())
	... // handling
}
...

But channel is not very good for it. (I mean not so easy understandable)
Maybe more explicit will be approach like wg.Wait()

I saw that you wrote that you wanted to rewrite all Start code #6 (comment). Otherwise I could do try to figure out it and do a pull request.
Thanks for your work!

How can I get only the events from the source not the parent director

Sorry am very new to Go
based on the code below when an event occurred the first event will be "WRITE" from the parent folder followed by the event source.
Is there a way to identify the initial event

// Package watcher hey
package watcher

import (
	"fmt"
	"log"
	"time"

	"github.com/radovskyb/watcher"
)

//ExampleNewWatcher work
func ExampleNewWatcher() {
	w := watcher.New()

	// SetMaxEvents to 1 to allow at most 1 event's to be received
	// on the Event channel per watching cycle.
	//
	// If SetMaxEvents is not set, the default is to send all events.
	// w.SetMaxEvents(1)

	// Only notify rename and move events.
	w.FilterOps(watcher.Rename, watcher.Write, watcher.Create, watcher.Remove)

	go func() {
		for {
			select {
			case event := <-w.Event:
				// if name := event.Op; name == watcher.Write {
				fmt.Println(event.Path) // Print the event's info.
				// fmt.Println(watcher.Write)
				// }
			case err := <-w.Error:
				log.Fatalln(err)
			case <-w.Closed:
				return
			}
		}
	}()

	// Watch test_folder recursively for changes.
	if err := w.AddRecursive("/home/akumzy/Documents"); err != nil {
		log.Fatalln(err)
	}

	// Print a list of all of the files and folders currently
	// being watched and their paths.
	for path, f := range w.WatchedFiles() {
		fmt.Printf("%s: %s\n", path, f.Name())
	}

	fmt.Println()
	// Start the watching process - it'll check for changes every 100ms.
	if err := w.Start(time.Millisecond * 100); err != nil {
		log.Fatalln(err)
	}

}

Suggestion: the basic example confuses beginners easily

I spent 20 minutes to figure out why the basic example doesn't work when I write to a file. Then I found these lines:

// SetMaxEvents to 1 to allow at most 1 event's to be received
// on the Event channel per watching cycle.
//
// If SetMaxEvents is not set, the default is to send all events.
w.SetMaxEvents(1)
// Only notify rename and move events.
w.FilterOps(watcher.Rename, watcher.Move)

So only one event per second is allowed, and only renaming and moving are shown.

This will easily make beginners confused, because I suppose the basic example should notify every event for me like a Hello-World for a file notification library.

If it is necessary to show these advanced use, It's better to comment them.

Consider Versioning

@radovskyb Let me introduce myself. My name is Jeeva, I'm the author of aah framework.

For upcoming release v0.7 of my framework I'm working on Hot Reload functionality. I have been doing study and research around monitoring file and directory changes for a while. I know, there is a library fsnotify, it is good one. Then I come across your library, pretty interesting. Good work.

I have evaluated your library for aah framework purpose and went through your code file. After that I'm leaning towards your library.

I would like to clarify following-

  • Can you please version, tag and release your library per semver.org, that I can binding to certain git tag via gopkg.in.
  • If aah framework users come across any issues, are you okay to help out as best as you can. I know everyone has their priority. Even if delayed its fine, as long as their is solution/fix. I will try my best to send PR if I fix it.

If above points are not feasible (I'm hoping not), are you okay with forking your library into go-aah org.

Please let me know. Thanks.

Run watcher script only once per interval in pipe mode

Currently the-cmd script is run once for each event, even when -pipe=true is specified.

It would be great if there were an option to send all events from a single interval to the cmds stdin in one call, so that the cmd can do batch processing.

Centos: SIGSEGV when change occurs with -cmd

Thanks for implementing this tool. I've been trying to get watcher to follow up what is happening in a specific directory, and simply just print number of files left. I added the counter shell to the -cmd, but directly after first change happens in the directory, I get a SIGSEGV error.

watcher -dotfiles=false -recursive=false -cmd="./countzips.sh"
Watching 40 files
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x4b550c]
goroutine 6 [running]:
os.(*ProcessState).os.success(...)
/usr/local/go/src/os/exec_posix.go:74
os.(*ProcessState).Success(...)
/usr/local/go/src/os/exec.go:150
main.main.func1(0xc42007a240, 0xc42008c000, 0xc420058280, 0x7ffd9483e732, 0xe, 0xc42000a070, 0x1, 0x1, 0xc4200160a4, 0xc4200160a5)
$HOME/go/src/github.com/radovskyb/watcher/cmd/watcher/main.go:76 +0x49c
created by main.main
$HOME/go/src/github.com/radovskyb/watcher/cmd/watcher/main.go:56 +0x39a

go version go1.10.3 linux/amd64

The countzips.sh contains just ls -1 *.zip | wc -l

Is there something wrong with our Go installation, or did I just misunderstand how to utilize that cmd parameter? (Tried also having a go script for the counter, but got same message with that, too.) All help is greatly appreciated.

Allow CLI users to ignore files

Hey, would you accept a PR to add support for an --ignore flag? It would take a comma-separated list of paths which would not trigger the command specified by the user.

pipeline for events

I little bit have mess in my head. I will modify it. Feel free ask questions before.
I will push code. It's not compilable and absolutely not workable:warning:. Just ideas.

update Sorry , there are a lot of mistypes.

problem

Work flow got a awful monster.

Infinite loop is out of control.

Mutex hell.

review of dev branch

I reviewed ec08eb0.

Your loop got more tricky.

I started to implement this patternhttps://blog.golang.org/pipelines. And implemented it as possible.

But after I've finished I got that it's redundant. Code got clearer with pipeline. But there are no really
advantages of using gorutines. WRITE and CHMOD operation can be parralel but these operations so light.
Gorutines are overhead for them. Only one advantage I liked

f, ok = <-w.pipeline // if chanel was closed ok was false
if ok {
} else {
	return
}

But it can be easily done via extra explicit chanel.

CREATE, REMOVE, RENAME operation require be consequences. And anyway necessary have extra explicit chanel for
canceling them on the fly.

I decided that it's not good idea implement pipelines. But with using pipelines I got a lot of ideas.

First I describe my realization.

ideas

Check gorutines part only for example. Gorutines are redundant.

  1. I believe that any call to os much longer then using any golang construction

  2. Remove all mutexes ass possible. There are really some hell!

  3. I start rewrite from Start function

func (w *Watcher) Start2(pollInterval time.Duration) error {
	if pollInterval <= time.Millisecond {
		pollInterval = time.Millisecond * 100
	}
	tick := time.Tick(pollInterval)
	for i := 0; i < 4; i++ {
	    w.wg.Add(1)
		go w.handler() 
	}
	w.wg.Done()
	for {
		select {
		case <-tick:
		        w.iteration()
		case <-updateState:
		        w.someHow()
		case <-w.close:
			close(w.pipeline)
			w.Destroy() //or w.Clean()
			return
		}
	}
}

3.1 Laconic ass possible.
3.2 All managing via channels!
3.3 No mutexes!
3.4 No time.Sleep only ticker
3.5 ticker local . All stuff that can be local should be local
3.6 I don't sure really how much gorutines were necessary. In reality gorutines don't necessary.

  1. Iteration (check)[#About your algorithm]. All logic linear.
func (w *Watcher) Iteration() {
			w.retrieveFileList2() // I send fileInfo directly in retrieveFileList2
			w.created = map[string]os.FileInfo{}
			w.removed = w.files // should be links
			w.wg.Wait()
			// RENAMED, REMOVED, CREATED
		// it should be sync operation I think
		// RENAMED
		// compare w.created and rest of items in w.files
		// if event exist delete() item from both maps
		// REMOVED
		// check rest of items in w.files
		// CREATED
		// created check w.created
				w.Event <- Event{}
				}
  1. w.retrieveFileList2()
type _fileInfo struct {
	pathID string
	fileInfo os.FileInfo
}

....
if err == nil {
			for k, v := range list {
				fileList[k] = v
				for _k, _v := range list {
					w.pipeline <- _fileInfo{_k, _v}
					w.Add(1)
				}
			}
			continue
		}

I creted extratype _fileInfo for sending all data inside channel

  1. And gorutine!
func (w *Watcher) handler() {
	var f _fileInfo
	var ok bool
	for {
		f, ok = <-w.pipeline
		if ok {
			// check name in previous files
			if fileInfo, found := w.files[f.key]; found {
				// check Write and Chmode
				// CHANGED
				println(fileInfo[""].Name())
				w.Event <- Event{}
				delete(w.files, f.key)
			} else {
				w.created[f.key] = f.value
			}
			w.wg.Done()

		} else {
			return
		}
	}
}

proposes

I propose use the same flow but without gorutines and pipelane channel.

About your algorithm

All files could be stored in map[string]os.FileInfo. Where key is absolute path to file. Now you store it as map[string]map[string]os.FileInfo.
It's too complicated and bad for algorithms.

I will suppose that w.files is *map[string]os.FileInfo

  1. w.removed = w.files (don't forget I suppose it's pointers)
  2. During retrieveFileList check WRITE and CHMOD in the same time and immediately sent event to w.Event
  3. If file CREATE w.created[pathID]= fileInfo
  4. If event exist delete(w.removed, pathID)
  5. When retrieveFileList is finished. Swap pointers w.files = fileList
  6. Compare w.created and w.removed emit RENAMED
  7. emit CREATE and REMOVED
  8. flush w.created , w.removed should be linked to w.files in begining

I don't believe that it will it a lot of memory. But definitely simpler and faster.

When you check WRITE and CHMOD. It should be done in the same time.

show full path file changed and fix error python code readme

Hi..I'm curious: It's possible show the full path for the file change, right now with the samples I only get the file name

  1. seems than there is a small error in the python code, must be
import sys

for line in sys.stdin:
    print (line + " - python")
  1. How would be the performance in a very deep folder structure?...can I watch for my whole filesystem?

thanks!!

Option for ignoring exit > 0

First thanks this is sweet! but for running tests I noticed if a test fails it'll exit entirely, an option to remain active would be handy

restarting web server causes watcher to break

Hi

I am trying to build and restart a webserver on every file change using the command go run basic-page.go
It seems to work the first time I make a file change but then watcher hangs after this and it does not build and restart the webserver on any other changes.
This seems to only happen when i use this particular command go run basic-page.go
Any ideas why the watcher cannot run this command

Here is some code to help recreate the situation

watcher.go

package watcher

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
	"time"
	"github.com/radovskyb/watcher"
)

func command(binaryName string, args []string, entryPoint string) *exec.Cmd {
	binary, lookErr := exec.LookPath(binaryName)
	if lookErr != nil {
		panic(lookErr)
	}

	cmd := exec.Command(binary, args...)
	cmd.Dir = entryPoint
	errBuf := &bytes.Buffer{}
	cmd.Stderr = errBuf

	err := cmd.Run()
	if err != nil {
		log.Printf("Command finished with error: %v", err)
	}

	return cmd
}

func main() {
	w := watcher.New()
	w.IgnoreHiddenFiles(true)

	go func() {
		for {
			select {
			case event := <-w.Event:
				command("go", []string{"run", "webserver.go"}, ".")
				fmt.Println(event)
			case err := <-w.Error:
				log.Fatalln(err)
			case <-w.Closed:
				return
			}
		}
	}()

	// Watch this folder for changes.
	if err := w.Add("."); err != nil {
		log.Fatalln(err)
	}

	fmt.Println()

	// Start the watching process - it'll check for changes every 100ms.
	if err := w.Start(time.Millisecond * 1); err != nil {
		log.Fatalln(err)
	}
}

webserver.go

package main

import (
	"fmt"
	"net/http"
)

func helloWorld(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World")
}

func main() {
	http.HandleFunc("/", helloWorld)
	http.ListenAndServe(":8080", nil)
}

Ignore paths

When watching folders recursively, there might be some folders where I don't want the watcher to touch.

These folders can be dependencies (which were downloaded by some package manager), folders meant to be used as example, folders that keep the app tests (not the case in Go happens in mostly of other languages).

So, I think that we could have some way to ignore those paths, so we don't increase our slice of paths/files that's being watched without necessity.

Example

For example, say that right now I'm using the watcher in a rather simple web app. In this app I have two folders that contain the libs used for both development (like tasks and suchs - that's in node_modules) and libs that I really use in the app (that's in bower_components).

The number of folders in node_modules is: 825. Inside each of these folders there's a bunch of other folders/files.

The number of folders in bower_components is: 27. Inside each of these, there are also a bunch of other folders/files.

So, when I watch the root of my app (which contains both of these folders), right off the bat, I'm watching thousands of stuff I either don't care or won't change - which makes the watcher take longer to report the events going on in the files I really want to watch.

I know I could solve that by specifying exactly what I want to watch, like: w.Add("path_1"), w.Add("path_2"), w.Add("path_3"), etc. But sometimes inside those paths there might be something I'd also like to ignore.

Proprosal

Either refactor way Options work, using a real struct so the user can have something like this when creating a new watcher:

opt := &Options{
   NonRecursive: true,
   Ignore: []string{"a", "b", "c", "d/f/g/h"},
   SomethingElse: false,
}

w := watcher.New(opt)

Or use the same approach, but not at the moment to create a watcher, but when the user wants to Add a path to be watched:

w := watcher.New()

optPath1 := &Options{
   NonRecursive: true,
   Ignore: []string{"a"},
   SomethingElse: false,
}

optPath2 := &Options{
   NonRecursive: false,
   Ignore: []string{"a", "b", "c", "d/f/g/h"},
}

optPath3 := &Options{
   Ignore: []string{"xyz/123"},
}

w.Add("path_1", optPath1)
w.Add("path_2", optPath2)
w.Add("path_3", optPath3)

Automatically execute cmd at start

Is there a possibility to automatically execute cmd at the start of watcher? I am trying to use watcher with multiple microservices and it's painful to change every service for the first time just to get everything up.

Watch all files

Is there any way to watch all files in given folder? Say I'm in the root of my app and I want to watch everything, is there such thing as passing a single dot (.)? Some libs in node-land do that, not sure what's the convention for go?

Release tags not including the leading `v` are unreachable by Go modules

Hi @radovskyb. Thanks for making this project available to the public!

I've found one minor issue when importing github.com/radovskyb/watcher as a Go module. Go can't find releases tagged in this repo when the tag name does not include the leading v character. Namely: tags 1.0.3, 1.0.4 and 1.0.5 are missing the leading v character. Go believes that v1.0.2 is the latest release since that's the highest version within the subset where the the leading v character is present.

This is what I'm seeing:

$ go mod init github.com/sevein/foobar
$ go get github.com/radovskyb/[email protected]
go: finding github.com/radovskyb/watcher v1.0.5
go get github.com/radovskyb/[email protected]: unknown revision v1.0.5
$ go get github.com/radovskyb/watcher
go: finding github.com/radovskyb/watcher v1.0.2
go: downloading github.com/radovskyb/watcher v1.0.2

Tagging 3818ec2 as v1.0.5 (in addition to the existing tags) may be enough to solve the problem.

Issue with links to directories

When there is link to a directory, containing a numer of files, watch does not recognice changes in that directory. Utilizing the same application to watch a dirctory without a link alle changed files will be recognized.

Is this a bug, or are filesystem links not supported?

Add file or path to watch at runtime

Is this project support add/remove watch items at run time? Can I find the sample code?

I have a website and back-end database to save the watch items, so my code will check the database table to add/remove watch items when data changed.

Thanks.

Need a FINISH event

I find it useful to have a FINISH event which fires when a newly created file finish being written. The use cases include automatically trigger processing when a file finishes downloading or being fully generated (e.g, some media file cannot be processed on the fly).

The filesystem event notifications cannot solve this and polling is somehow required, which matches this watcher's polling nature. Should be a helpful feature?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.