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
}
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.
package reload  
import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
	"time"
	"github.com/fsnotify/fsnotify"
)
var (
	binSelf string
	closeWatcher func() error
)
type dir struct {
	path string
	cb   func()
}
func Dir(path string, cb func()) dir { return dir{path, cb} }