func Do(log func(string, ...interface{}), additional ...dir) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return fmt.Errorf("reload.Do: cannot setup watcher: %w", err)
	}
	closeWatcher = watcher.Close

	binSelf, err = self()
	if err != nil {
		return err
	}

	// Watch the directory, because a recompile renames the existing
	// file (rather than rewriting it), so we won't get events for that.
	dirs := make([]string, len(additional)+1)
	dirs[0] = filepath.Dir(binSelf)

	for i := range additional {
		path, err := filepath.Abs(additional[i].path)
		if err != nil {
			return fmt.Errorf("reload.Do: cannot get absolute path to %q: %w",
				additional[i].path, err)
		}

		s, err := os.Stat(path)
		if err != nil {
			return fmt.Errorf("reload.Do: %w", err)
		}
		if !s.IsDir() {
			return fmt.Errorf("reload.Do: not a directory: %q; can only watch directories",
				additional[i].path)
		}

		additional[i].path = path
		dirs[i+1] = path
	}

	done := make(chan bool)
	go func() {
		for {
			select {
			case err := <-watcher.Errors:
				log("reload error: %v", err)
			case event := <-watcher.Events:
				// Ensure that we use the correct events, as they are not uniform accross
				// platforms. See https://github.com/fsnotify/fsnotify/issues/74
				var trigger bool
				switch runtime.GOOS {
				case "darwin", "freebsd", "openbsd", "netbsd", "dragonfly":
					trigger = event.Op&fsnotify.Create == fsnotify.Create
				case "linux":
					trigger = event.Op&fsnotify.Write == fsnotify.Write
				default:
					trigger = event.Op&fsnotify.Create == fsnotify.Create
					log("reload: untested GOOS %q; this package may not work correctly", runtime.GOOS)
				}

				if !trigger {
					continue
				}

				if event.Name == binSelf {
					// Wait for writes to finish.
					time.Sleep(100 * time.Millisecond)
					Exec()
				}

				for _, a := range additional {
					if strings.HasPrefix(event.Name, a.path) {
						time.Sleep(100 * time.Millisecond)
						a.cb()
					}
				}
			}
		}
	}()

	for _, d := range dirs {
		if err := watcher.Add(d); err != nil {
			return fmt.Errorf("reload.Do: cannot add %q to watcher: %w", d, err)
		}
	}

	add := ""
	if len(additional) > 0 {
		reldirs := make([]string, len(dirs)-1)
		for i := range dirs[1:] {
			reldirs[i] = relpath(dirs[i+1])
		}
		add = fmt.Sprintf(" (additional dirs: %s)", strings.Join(reldirs, ", "))
	}
	log("restarting %q when it changes%s", relpath(binSelf), add)
	<-done
	return nil
}
// Do reload the current process when its binary changes.
//
// The log function is used to display an informational startup message and
// errors. It works well with e.g. the standard log package or Logrus.
//
// The error return will only return initialisation errors. Once initialized it
// will use the log function to print errors, rather than return.
Do reload the current process when its binary changes.

The log function is used to display an informational startup message and
errors. It works well with e.g. the standard log package or Logrus.

The error return will only return initialisation errors. Once initialized it
will use the log function to print errors, rather than return.
// Do reload the current process when its binary changes . // // The log function is used to display an informational startup message and // errors . It works well with e . g . the standard log package or Logrus . // // The error return will only return initialisation errors . Once initialized it // will use the log function to print errors rather than return .
func Do(log func(string, ...interface{}), additional ...dir) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return fmt.Errorf("reload.Do: cannot setup watcher: %w", err)
	}
	closeWatcher = watcher.Close
	binSelf, err = self()
	if err != nil {
		return err
	}
	dirs := make([]string, len(additional)+1)
	dirs[0] = filepath.Dir(binSelf)
	for i := range additional {
		path, err := filepath.Abs(additional[i].path)
		if err != nil {
			return fmt.Errorf("reload.Do: cannot get absolute path to %q: %w",
				additional[i].path, err)
		}
		s, err := os.Stat(path)
		if err != nil {
			return fmt.Errorf("reload.Do: %w", err)
		}
		if !s.IsDir() {
			return fmt.Errorf("reload.Do: not a directory: %q; can only watch directories",
				additional[i].path)
		}
		additional[i].path = path
		dirs[i+1] = path
	}
	done := make(chan bool)
	go func() {
		for {
			select {
			case err := <-watcher.Errors:
				log("reload error: %v", err)
			case event := <-watcher.Events:
				var trigger bool
				switch runtime.GOOS {
				case "darwin", "freebsd", "openbsd", "netbsd", "dragonfly":
					trigger = event.Op&fsnotify.Create == fsnotify.Create
				case "linux":
					trigger = event.Op&fsnotify.Write == fsnotify.Write
				default:
					trigger = event.Op&fsnotify.Create == fsnotify.Create
					log("reload: untested GOOS %q; this package may not work correctly", runtime.GOOS)
				}
				if !trigger {
					continue
				}
				if event.Name == binSelf {
					time.Sleep(100 * time.Millisecond)
					Exec()
				}
				for _, a := range additional {
					if strings.HasPrefix(event.Name, a.path) {
						time.Sleep(100 * time.Millisecond)
						a.cb()
					}
				}
			}
		}
	}()
	for _, d := range dirs {
		if err := watcher.Add(d); err != nil {
			return fmt.Errorf("reload.Do: cannot add %q to watcher: %w", d, err)
		}
	}
	add := ""
	if len(additional) > 0 {
		reldirs := make([]string, len(dirs)-1)
		for i := range dirs[1:] {
			reldirs[i] = relpath(dirs[i+1])
		}
		add = fmt.Sprintf(" (additional dirs: %s)", strings.Join(reldirs, ", "))
	}
	log("restarting %q when it changes%s", relpath(binSelf), add)
	<-done
	return nil
}
func Do ( log func ( string , ... interface { } ) , additional ... dir ) error { watcher , err := fsnotify . NewWatcher ( ) if err != nil { return fmt . Errorf ( " " , err ) } closeWatcher = watcher . Close binSelf , err = self ( ) if err != nil { return err } dirs := make ( [ ] string , len ( additional ) + 1 ) dirs [ 0 ] = filepath . Dir ( binSelf ) for i := range additional { path , err := filepath . Abs ( additional [ i ] . path ) if err != nil { return fmt . Errorf ( " " , additional [ i ] . path , err ) } s , err := os . Stat ( path ) if err != nil { return fmt . Errorf ( " " , err ) } if ! s . IsDir ( ) { return fmt . Errorf ( " " , additional [ i ] . path ) } additional [ i ] . path = path dirs [ i + 1 ] = path } done := make ( chan bool ) go func ( ) { for { select { case err := <- watcher . Errors : log ( " " , err ) case event := <- watcher . Events : var trigger bool switch runtime . GOOS { case " " , " " , " " , " " , " " : trigger = event . Op & fsnotify . Create == fsnotify . Create case " " : trigger = event . Op & fsnotify . Write == fsnotify . Write default : trigger = event . Op & fsnotify . Create == fsnotify . Create log ( " " , runtime . GOOS ) } if ! trigger { continue } if event . Name == binSelf { time . Sleep ( 100 * time . Millisecond ) Exec ( ) } for _ , a := range additional { if strings . HasPrefix ( event . Name , a . path ) { time . Sleep ( 100 * time . Millisecond ) a . cb ( ) } } } } } ( ) for _ , d := range dirs { if err := watcher . Add ( d ) ; err != nil { return fmt . Errorf ( " " , d , err ) } } add := " " if len ( additional ) > 0 { reldirs := make ( [ ] string , len ( dirs ) - 1 ) for i := range dirs [ 1 : ] { reldirs [ i ] = relpath ( dirs [ i + 1 ] ) } add = fmt . Sprintf ( " " , strings . Join ( reldirs , " " ) ) } log ( " " , relpath ( binSelf ) , add ) <- done return nil }
Do reload the current process when its binary changes.
Do reload the current process when its binary changes .
// Watch the directory, because a recompile renames the existing // file (rather than rewriting it), so we won't get events for that. // Ensure that we use the correct events, as they are not uniform accross // platforms. See https://github.com/fsnotify/fsnotify/issues/74 // Wait for writes to finish.