コード例 #1
2
ファイル: file.go プロジェクト: toksea/iris
// 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(rootPath 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 but I dont know if works for linux 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())
			}
		}
	}()

	werr = watcher.Add(rootPath)
	if werr != nil {
		logger.Dangerf(werr.Error())

	}

}
コード例 #2
1
ファイル: shards.go プロジェクト: tadeuszwojcik/zoekt
func (s *shardedSearcher) watch() error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	if err := watcher.Add(s.dir); err != nil {
		return err
	}

	go func() {
		for {
			select {
			case <-watcher.Events:
				s.scan()
			case err := <-watcher.Errors:
				if err != nil {
					log.Println("watcher error:", err)
				}
			case <-s.quit:
				watcher.Close()
				return
			}
		}
	}()
	return nil
}
コード例 #3
1
ファイル: watcher.go プロジェクト: qrtz/livedev
// New creates a new Watcher and begins watching events
func New() (*Watcher, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	w := &Watcher{
		watcher: watcher,
		watches: make(map[string][]chan<- Event),
		stop:    make(chan struct{}, 1),
	}
	go w.run()
	return w, nil
}
コード例 #4
0
ファイル: editor.go プロジェクト: nelsam/vidar
func (e *CodeEditor) watcherSetup() {
	var err error
	e.watcher, err = fsnotify.NewWatcher()
	if err != nil {
		log.Printf("Error creating new fsnotify watcher: %s", err)
	}
}
コード例 #5
0
ファイル: example_test.go プロジェクト: vsayer/fsnotify
func ExampleNewWatcher() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				log.Println("event:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					log.Println("modified file:", event.Name)
				}
			case err := <-watcher.Errors:
				log.Println("error:", err)
			}
		}
	}()

	err = watcher.Add("/tmp/foo")
	if err != nil {
		log.Fatal(err)
	}
	<-done
}
コード例 #6
0
ファイル: fsnotify.go プロジェクト: soarpenguin/go-scripts
func NewWatcher(file string) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				if event.Op&fsnotify.Write == fsnotify.Write {
					log.Println("modified file:", event.Name)
				} else if event.Op&fsnotify.Rename == fsnotify.Rename {
					log.Println("rename file:", event.Name)
				} else {
					log.Println("event:", event)
				}
			case err := <-watcher.Errors:
				log.Println("error:", err)
			}
		}
	}()

	err = watcher.Add(file)
	if err != nil {
		log.Fatal(err)
	}
	<-done
}
コード例 #7
0
ファイル: filenotify.go プロジェクト: jfrazelle/docker
// NewEventWatcher returns an fs-event based file watcher
func NewEventWatcher() (FileWatcher, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	return &fsNotifyWatcher{watcher}, nil
}
コード例 #8
0
ファイル: build.go プロジェクト: moul/advanced-ssh-config
func NewSession(options *Options) *Session {
	if options.GOROOT == "" {
		options.GOROOT = build.Default.GOROOT
	}
	if options.GOPATH == "" {
		options.GOPATH = build.Default.GOPATH
	}
	options.Verbose = options.Verbose || options.Watch

	s := &Session{
		options:  options,
		Archives: make(map[string]*compiler.Archive),
	}
	s.Types = make(map[string]*types.Package)
	if options.Watch {
		if out, err := exec.Command("ulimit", "-n").Output(); err == nil {
			if n, err := strconv.Atoi(strings.TrimSpace(string(out))); err == nil && n < 1024 {
				fmt.Printf("Warning: The maximum number of open file descriptors is very low (%d). Change it with 'ulimit -n 8192'.\n", n)
			}
		}

		var err error
		s.Watcher, err = fsnotify.NewWatcher()
		if err != nil {
			panic(err)
		}
	}
	return s
}
コード例 #9
0
func startFileWatcher(file string) *fsnotify.Watcher {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				log.Println("evt:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					log.Println("modified file:", event.Name)
				}
			case err := <-watcher.Errors:
				log.Println("error:", err)
			}
		}
	}()
	err = watcher.Add(file)
	if err != nil {
		log.Fatal(err)
	}

	return watcher
}
コード例 #10
0
ファイル: filewatch.go プロジェクト: BlackEspresso/ServeJS
func registerVM(vm *modules.JsVm) otto.Value {
	watcher, err := fsnotify.NewWatcher()
	//defer watcher.Close()
	if err != nil {
		log.Println(pluginName + " " + err.Error())
	}
	obj, _ := vm.Object("({})")

	obj.Set("watchDir", func(c otto.FunctionCall) otto.Value {
		path, _ := c.Argument(0).ToString()
		err := watcher.Add(path)
		return modules.ToResult(vm, true, err)
	})

	obj.Set("start", func(c otto.FunctionCall) otto.Value {
		log.Println(pluginName + " start")
		go func() {
			for {
				select {
				case ev := <-watcher.Events:
					log.Println("event:", ev.String())
				case err := <-watcher.Errors:
					log.Println("error:", err)
				}
			}
		}()
		return otto.TrueValue()
	})
	return obj.Value()
}
コード例 #11
0
ファイル: project_tree.go プロジェクト: nelsam/vidar
func (p *ProjectTree) SetRoot(path string) {
	p.layout.RemoveAll()
	p.SetTOC(nil)
	p.tocCtl = nil

	if p.watcher != nil {
		p.watcher.Close()
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Printf("Error creating project tree watcher: %s", err)
	}
	p.watcher = watcher
	p.startWatch(path)

	p.dirs = newDirectory(p, path)
	scrollable := p.theme.CreateScrollLayout()
	// Disable horiz scrolling until we can figure out an accurate
	// way to calculate our width.
	scrollable.SetScrollAxis(false, true)
	scrollable.SetChild(p.dirs)
	p.layout.AddChild(scrollable)
	p.layout.SetChildWeight(p.dirs, 1)

	// Expand the top level
	p.dirs.button.Click(gxui.MouseEvent{})
}
コード例 #12
0
ファイル: jitome.go プロジェクト: kohkimakimoto/jitome
func (jitome *Jitome) Start() error {
	// check init task
	// register watchers
	for name, target := range jitome.config.Targets {
		if name == "init" {
			continue
		}

		target.Name = name
		target.events = make(chan *Event, 30)
		target.jitome = jitome

		log.Print("evaluating target '" + FgCB(name) + "'.")

		// register watched directories
		for i, watchConfig := range target.Watch {
			watchConfig.InitPatterns()
			w, err := fsnotify.NewWatcher()
			if err != nil {
				return err
			}

			err = watch(watchConfig.Base, watchConfig.ignoreRegs, w)
			if err != nil {
				return err
			}

			watcher, err := NewWatcher(jitome, target, watchConfig, w, i)
			if err != nil {
				return err
			}

			jitome.watchers = append(jitome.watchers, watcher)
			go watcher.Wait()
		}
		go target.Wait()
	}
	defer jitome.Close()

	go func() {
		log.Print("watching files...")
		for {
			event := <-jitome.events
			runTarget(event)
		}
	}()

	go func() {
		err := jitome.restartCommand()
		if err != nil {
			log.Print(FgRB(fmt.Sprintf("[warning] %v", err)))
		}
	}()

	// wait infinitely.
	select {}
}
コード例 #13
0
ファイル: local.go プロジェクト: johnsiilver/golib
func newDispatcher() (*dispatcher, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	d := &dispatcher{watcher: watcher, closer: make(chan struct{}), routes: map[string]chan struct{}{}}
	go d.listen()
	return d, nil
}
コード例 #14
0
ファイル: main.go プロジェクト: esell/deb-simple
func main() {
	flag.Parse()
	file, err := ioutil.ReadFile(*configFile)
	if err != nil {
		log.Fatal("unable to read config file, exiting...")
	}
	if err := json.Unmarshal(file, &parsedConfig); err != nil {
		log.Fatal("unable to marshal config file, exiting...")
	}

	// fire up filesystem watcher
	mywatcher, err = fsnotify.NewWatcher()
	if err != nil {
		log.Fatal("error creating fswatcher: ", err)
	}

	if err := createDirs(parsedConfig); err != nil {
		log.Println(err)
		log.Fatalf("error creating directory structure, exiting")
	}

	go func() {
		for {
			select {
			case event := <-mywatcher.Events:
				if (event.Op&fsnotify.Write == fsnotify.Write) || (event.Op&fsnotify.Create == fsnotify.Create) || (event.Op&fsnotify.Remove == fsnotify.Remove) {
					log.Println("modified file:", event.Name)
					mutex.Lock()

					log.Println("got lock, updating package list...")
					distroArch := destructPath(event.Name)
					if filepath.Base(event.Name) != "Packages.gz" {
						if err := createPackagesGz(parsedConfig, distroArch[0], distroArch[1]); err != nil {
							log.Println("error creating package: %s", err)
						}
					}
					mutex.Unlock()
				}
			case err := <-mywatcher.Errors:
				log.Println("error:", err)
			}
		}
	}()

	http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir(parsedConfig.RootRepoPath))))
	http.Handle("/upload", uploadHandler(parsedConfig))
	http.Handle("/delete", deleteHandler(parsedConfig))

	if parsedConfig.EnableSSL {
		log.Println("running with SSL enabled")
		log.Fatal(http.ListenAndServeTLS(":"+parsedConfig.ListenPort, parsedConfig.SSLCert, parsedConfig.SSLKey, nil))
	} else {
		log.Println("running without SSL enabled")
		log.Fatal(http.ListenAndServe(":"+parsedConfig.ListenPort, nil))
	}
}
コード例 #15
0
ファイル: fileWatcher.go プロジェクト: Simbory/wemvc
// NewWatcher create the new watcher
func NewWatcher() (*FileWatcher, error) {
	tmpWatcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	w := &FileWatcher{
		watcher: tmpWatcher,
	}
	return w, nil
}
コード例 #16
0
ファイル: watchlql.go プロジェクト: lytics/go-lytics
func newLql(c *Cli) *lql {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err.Error())
	}
	return &lql{
		c:     c,
		w:     watcher,
		files: make(map[string]*datafile),
	}
}
コード例 #17
0
//start filesystem watcher
func (engine *Engine) StartFSWatcher() error {
	var err error
	engine.watcher, err = fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {

		for {

			select {
			case event := <-engine.watcher.Events:
				if event.Op&fsnotify.Write == fsnotify.Write {
					if strings.HasSuffix(event.Name, engine.sqlTemplate.Extension) {
						err = engine.reloadSqlTemplate(event.Name)
						if err != nil {
							engine.logger.Error(err)
						}
					}

					if strings.HasSuffix(event.Name, engine.sqlMap.Extension) {
						err = engine.reloadSqlMap(event.Name)
						if err != nil {
							engine.logger.Error(err)
						}
					}
				}

			case err := <-engine.watcher.Errors:
				if err != nil {
					engine.logger.Error(err)
				}
			}
		}
	}()

	if engine.sqlMap.SqlMapRootDir != "" {
		err = engine.watcher.Add(engine.sqlMap.SqlMapRootDir)
		if err != nil {
			return err
		}
	}

	if engine.sqlTemplate.SqlTemplateRootDir != "" {
		err = engine.watcher.Add(engine.sqlTemplate.SqlTemplateRootDir)
		if err != nil {
			return err
		}
	}

	return nil
}
コード例 #18
0
ファイル: updater.go プロジェクト: mwitkow/go-flagz
func New(flagSet *flag.FlagSet, dirPath string, logger loggerCompatible) (*Updater, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("flagz: error initializing fsnotify watcher.")
	}
	return &Updater{
		flagSet: flagSet,
		logger:  logger,
		dirPath: dirPath,
		watcher: watcher,
	}, nil
}
コード例 #19
0
ファイル: vm.go プロジェクト: taskcluster/taskcluster-worker
// waitForSockets will monitor socketFolder and return a channel that is closed
// when vncSocketFile and qmpSocketFile have been created.
func (vm *VirtualMachine) waitForSockets() (<-chan error, error) {
	done := make(chan error)

	// Cache socket folder here to avoid race conditions
	socketFolder := vm.socketFolder

	// Setup file monitoring, if there is an error here we panic, this should
	// always be reliable.
	w, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("Failed to setup file system monitoring, error: %s", err)
	}
	err = w.Add(socketFolder)
	if err != nil {
		return nil, fmt.Errorf("Failed to monitor socket folder, error: %s", err)
	}

	// Handle events, and close the done channel when sockets are ready
	go func() {
		vncReady := false
		qmpReady := false
		for !vncReady || !qmpReady {
			select {
			case e := <-w.Events:
				debug("fs-event: %s", e)
				if e.Op == fsnotify.Create {
					if e.Name == filepath.Join(socketFolder, vncSocketFile) {
						vncReady = true
					}
					if e.Name == filepath.Join(socketFolder, qmpSocketFile) {
						qmpReady = true
					}
				}
			case <-vm.Done:
				// Stop monitoring if QEMU has crashed
				w.Close()
				return
			case <-time.After(90 * time.Second):
				done <- fmt.Errorf("vnc and qmp sockets didn't show up in 90s")
				w.Close()
				return
			case err := <-w.Errors:
				done <- fmt.Errorf("Error monitoring file system, error: %s", err)
				w.Close()
				return
			}
		}
		w.Close()
		close(done)
	}()

	return done, nil
}
func ExampleNewWatcher(paths []string) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		fmt.Println(err.Error())
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
					iscompress := true
					if !checkIfWatchExt(event.Name) {
						continue
					}
					mt := getFileModTime(event.Name)
					if t := eventTime[event.Name]; mt == t {
						//fmt.Println("[SKIP] # %s #", event.String())
						iscompress = false
					}
					//fmt.Println("file:", event.Name, iscompress, event.Op, fsnotify.Write, event.Op&fsnotify.Write)
					if iscompress {
						fmt.Println("modified file:", event.Name)
						icmd := exec.Command("uglifyjs", event.Name, "-m", "-o", event.Name)
						err1 := icmd.Run()

						if err1 != nil {
							fmt.Println(err1.Error())
						} else {
							eventTime[event.Name] = time.Now().Unix()
						}
					}
				}
			case err := <-watcher.Errors:
				fmt.Println("error:", err)
			}
		}
	}()
	for _, path := range paths {
		fmt.Println("[TRAC] Directory( %s )", path)
		err = watcher.Add(path)
		if err != nil {
			fmt.Println("[ERRO] Fail to watch directory[ %s ]", err.Error())
			//os.Exit(2)
		}
	}
	<-done
}
コード例 #21
0
ファイル: batcher.go プロジェクト: CowPanda/hugo
func New(interval time.Duration) (*Batcher, error) {
	watcher, err := fsnotify.NewWatcher()

	batcher := &Batcher{}
	batcher.Watcher = watcher
	batcher.interval = interval
	batcher.done = make(chan struct{}, 1)
	batcher.Events = make(chan []fsnotify.Event, 1)

	if err == nil {
		go batcher.run()
	}

	return batcher, err
}
コード例 #22
0
ファイル: main_test.go プロジェクト: esell/deb-simple
func TestCreateDirs(t *testing.T) {
	pwd, err := os.Getwd()
	if err != nil {
		t.Errorf("Unable to get current working directory: %s", err)
	}
	config := Conf{ListenPort: "9666", RootRepoPath: pwd + "/testing", SupportArch: []string{"cats", "dogs"}, DistroNames: []string{"stable"}, EnableSSL: false}
	// sanity check...
	if config.RootRepoPath != pwd+"/testing" {
		t.Errorf("RootRepoPath is %s, should be %s\n ", config.RootRepoPath, pwd+"/testing")
	}
	mywatcher, err = fsnotify.NewWatcher()
	if err != nil {
		log.Fatal("error creating fswatcher: ", err)
	}
	t.Log("creating temp dirs in ", config.RootRepoPath)
	if err := createDirs(config); err != nil {
		t.Errorf("createDirs() failed ")
	}
	for _, archDir := range config.SupportArch {
		if _, err := os.Stat(config.RootRepoPath + "/dists/stable/main/binary-" + archDir); err != nil {
			if os.IsNotExist(err) {
				t.Errorf("Directory for %s does not exist", archDir)
			}
		}
	}

	// cleanup
	if err := os.RemoveAll(config.RootRepoPath); err != nil {
		t.Errorf("error cleaning up after createDirs(): %s", err)
	}

	// create temp file
	tempFile, err := os.Create(pwd + "/tempFile")
	if err != nil {
		t.Fatalf("create %s: %s", pwd+"/tempFile", err)
	}
	defer tempFile.Close()
	config.RootRepoPath = pwd + "/tempFile"
	// Can't make directory named after file.
	if err := createDirs(config); err == nil {
		t.Errorf("createDirs() should have failed but did not")
	}
	// cleanup
	if err := os.RemoveAll(pwd + "/tempFile"); err != nil {
		t.Errorf("error cleaning up after createDirs(): %s", err)
	}

}
コード例 #23
0
ファイル: filewatcher.go プロジェクト: scofieldpeng/go-libs
// Init 初始化文件监听
func (fw *fWatcher) Init(debug ...bool) error {
	var err error = nil

	if len(debug) > 0 {
		debug = make([]bool, 1)
		debug[0] = false
	}

	fw.status = STATUS_INIT
	fw.watcher, err = fsnotify.NewWatcher()
	fw.debug = debug[0]
	if err != nil {
		return errors.New("初始化filewatcher失败,失败原因:" + err.Error())
	}
	return nil
}
コード例 #24
0
ファイル: filemonitor_fsnotify.go プロジェクト: burke/zeus
func NewFileMonitor(fileChangeDelay time.Duration) (FileMonitor, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	f := fsnotifyMonitor{
		watcher: watcher,
	}
	f.fileChangeDelay = fileChangeDelay
	f.changes = make(chan string)

	go f.serveListeners()
	go f.watch()

	return &f, nil
}
コード例 #25
0
ファイル: zone.go プロジェクト: yuewko/coredns
func (z *Zone) Reload(shutdown chan bool) error {
	if z.NoReload {
		return nil
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	err = watcher.Add(path.Dir(z.file))
	if err != nil {
		return err
	}

	go func() {
		// TODO(miek): needs to be killed on reload.
		for {
			select {
			case event := <-watcher.Events:
				if path.Clean(event.Name) == z.file {
					reader, err := os.Open(z.file)
					if err != nil {
						log.Printf("[ERROR] Failed to open `%s' for `%s': %v", z.file, z.origin, err)
						continue
					}
					z.reloadMu.Lock()
					zone, err := Parse(reader, z.origin, z.file)
					if err != nil {
						log.Printf("[ERROR] Failed to parse `%s': %v", z.origin, err)
						z.reloadMu.Unlock()
						continue
					}
					// copy elements we need
					z.Apex = zone.Apex
					z.Tree = zone.Tree
					z.reloadMu.Unlock()
					log.Printf("[INFO] Successfully reloaded zone `%s'", z.origin)
					z.Notify()
				}
			case <-shutdown:
				watcher.Close()
				return
			}
		}
	}()
	return nil
}
コード例 #26
0
ファイル: watch.go プロジェクト: SpectoLabs/hoverfly
func NewRecursiveWatcher(path string, recursive bool) (*RecursiveWatcher, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	rw := &RecursiveWatcher{watcher, make(map[string]bool)}
	if recursive {
		if err = rw.AddPath(path); err != nil {
			return nil, err
		}
	} else {
		if err := rw.watcher.Add(path); err != nil {
			return nil, err
		}
		rw.paths[path] = true
	}
	return rw, nil
}
コード例 #27
0
ファイル: watcher.go プロジェクト: vsco/dcdr
// Init creates a new `fsnotify` watcher observing `path`.
func (w *Watcher) Init() error {
	watcher, err := fsnotify.NewWatcher()

	if err != nil {
		return err
	}

	err = watcher.Add(w.path)

	if err != nil {
		return err
	}

	w.mu.Lock()
	defer w.mu.Unlock()
	w.watcher = watcher

	return nil
}
コード例 #28
0
ファイル: viper.go プロジェクト: luizbafilho/fusis
func (v *Viper) WatchConfig() {
	go func() {
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Fatal(err)
		}
		defer watcher.Close()

		// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
		filename, err := v.getConfigFile()
		if err != nil {
			log.Println("error:", err)
			return
		}

		configFile := filepath.Clean(filename)
		configDir, _ := filepath.Split(configFile)

		done := make(chan bool)
		go func() {
			for {
				select {
				case event := <-watcher.Events:
					// we only care about the config file
					if filepath.Clean(event.Name) == configFile {
						if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
							err := v.ReadInConfig()
							if err != nil {
								log.Println("error:", err)
							}
							v.onConfigChange(event)
						}
					}
				case err := <-watcher.Errors:
					log.Println("error:", err)
				}
			}
		}()

		watcher.Add(configDir)
		<-done
	}()
}
コード例 #29
0
ファイル: motitor.go プロジェクト: CafeChair/gochair
func NewRecursiveWatcher(path string) (*RecursiveWatcher, error) {
	folders := Subfolders(path)
	if len(folders) == 0 {
		return nil, errors.New("No folder to watch.")
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	rw := &RecursiveWatcher{Watcher: watcher}
	rw.Files = make(chan string, 10)
	rw.Folders = make(chan string, len(folders))
	for _, folder := range folders {
		if err = rw.AddFolder(folder); err != nil {
			return nil, err
		}
	}
	return rw, nil
}
コード例 #30
0
ファイル: watch.go プロジェクト: thought-machine/please
// Watch starts watching the sources of the given labels for changes and triggers
// rebuilds whenever they change.
// It never returns successfully, it will either watch forever or die.
func Watch(state *core.BuildState, labels []core.BuildLabel) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatalf("Error setting up watcher: %s", err)
	}
	// This sets up the actual watches. It must be done in a separate goroutine.
	files := cmap.New()
	go startWatching(watcher, state, labels, files)

	// If any of the targets are tests, we'll run plz test, otherwise just plz build.
	command := "build"
	for _, label := range labels {
		if state.Graph.TargetOrDie(label).IsTest {
			command = "test"
			break
		}
	}
	log.Notice("Command: %s", command)

	for {
		select {
		case event := <-watcher.Events:
			log.Info("Event: %s", event)
			if !files.Has(event.Name) {
				log.Notice("Skipping notification for %s", event.Name)
				continue
			}
			// Quick debounce; poll and discard all events for the next brief period.
		outer:
			for {
				select {
				case <-watcher.Events:
				case <-time.After(debounceInterval):
					break outer
				}
			}
			runBuild(state, command, labels)
		case err := <-watcher.Errors:
			log.Error("Error watching files:", err)
		}
	}
}