func Shell() { sighup := autorestart.NotifyOnSighup() args, err := flags.ParseArgs(&Opts, os.Args[1:]) if err != nil { err2, ok := err.(*flags.Error) if ok && err2.Type == flags.ErrHelp { return } alog.Printf("Error parsing command-line options: %s\n", err) return } if Opts.NoColor { alog.DisableColor() } ignorePart = stringset.New(filepath.SplitList(Opts.IgnorePart)...) ignoreSuffix = filepath.SplitList(Opts.IgnoreSuffix) ignoreSubstring = filepath.SplitList(Opts.IgnoreSubstring) deletePart = stringset.New(filepath.SplitList(Opts.DeletePart)...) deleteSuffix = filepath.SplitList(Opts.DeleteSuffix) deleteSubstring = filepath.SplitList(Opts.DeleteSubstring) if Opts.Child { if len(args) < 1 { alog.Fatalln("Not enough arguments, need 1") } RootPath = args[0] execChild() return } if len(args) < 2 { alog.Fatalln("Not enough arguments, need 2") } RootPath = args[0] remoteFullPath := args[1] remoteFullPathParts := strings.SplitN(remoteFullPath, ":", 2) remoteHost, remoteRoot := remoteFullPathParts[0], remoteFullPathParts[1] alog.Printf("@(dim:nsync started, syncing) @(cyan:%s) @(dim:to) @(cyan:%s)@(dim::)@(cyan:%s)\n", RootPath, remoteHost, remoteRoot) onChildExit := make(chan error) go connectChildForever(remoteHost, remoteRoot, onChildExit) go execParent() select { case <-sighup: killChildSshProcess() case <-onChildExit: // Restart everything if the child drops out (this is kludgy but effective) case <-time.After(20 * time.Minute): // Restart periodically, at least until I figure out what causes hangs } }
func WatchExecutable(pathish string) (<-chan string, error) { exePath, err := getExePath(pathish) if err != nil { return nil, err } notify, err := WatchPath(exePath) if err != nil { return nil, err } debounced := make(chan string) go func() { pathsChanged := stringset.New() for { if pathsChanged.Len() > 0 { select { case pe := <-notify: pathsChanged.Add(pe.Path) break case <-time.After(400 * time.Millisecond): for _, p := range pathsChanged.All() { debounced <- p } pathsChanged.Clear() } } else { pathsChanged.Add((<-notify).Path) } } }() return debounced, nil }
func (ctx *SyncContext) watchForChangesLocal(fileEventCallback func(string)) { status := ctx.NewLogger("watcher") listener := watcher.NewListener() listener.Path = ctx.syncPath listener.IgnorePart = stringset.New(".gut") err := listener.Start() status.BailIf(err) go func() { for pathEvent := range listener.NotifyChan { path := pathEvent.Path relPath, err := filepath.Rel(ctx.syncPath, path) if err != nil { status.Bail(err) } fileEventCallback(relPath) } }() }
"syscall", "archive", "archive/tar", "archive/tar/testdata", "archive/zip", "archive/zip/testdata", "html", "html/template", "hash", "hash/fnv", "hash/crc32", "hash/adler32", "hash/crc64", "bytes", "encoding", "encoding/gob", "encoding/hex", "encoding/csv", "encoding/json", "encoding/json/testdata", "encoding/binary", "encoding/asn1", "encoding/base32", "encoding/pem", "encoding/ascii85", "encoding/base64", "encoding/xml", } var goStdLibPackages = stringset.New(goStdLibPackagesSlice...)
func update(pkgName string) { pUpdate := NewPackage(pkgName) defer func() { updateFinished <- pUpdate }() pUpdate.UpdateStartTime = time.Now() absPkgPath := filepath.Join(srcRoot, pkgName) pkg, err := build.ImportDir(absPkgPath, build.ImportComment) if err != nil { pUpdate.UpdateError = err // If the directory no longer exists, then tell the dispatcher to remove this package from the index _, statErr := os.Stat(absPkgPath) if statErr != nil && os.IsNotExist(statErr) { pUpdate.RemovePackage = true } else if beVerbose() { alog.Printf("@(warn:Error parsing import of module %s: %s)\n", pkgName, err) } return } pUpdate.Imports = stringset.New() for _, importName := range pkg.Imports { if !goStdLibPackages.Has(importName) { pUpdate.Imports.Add(importName) } } statFiles := func(files []string) { for _, filename := range files { path := filepath.Join(absPkgPath, filename) fileinfo, err := os.Stat(path) if err != nil { alog.Printf("@(error:Error stat-ing %s: %v)\n", path, err) pUpdate.UpdateError = err return } modTime := fileinfo.ModTime() if modTime.After(pUpdate.UpdateStartTime) { if modTime.After(time.Now()) { alog.Printf("@(warn:File has future modification time: %q mod %s)\n", path, modTime.String()) alog.Printf("@(warn:Correct triggering of builds depends on correctly-set system clocks.)\n") // Assume that it was not actually modified in the future, but that the system clock is just wrong // This will allow us to build the package, but we'll keep re-building every time autoinstall // restarts until the system clock gets past the file's time. modTime = pUpdate.UpdateStartTime.Add(-1 * time.Microsecond) } } if modTime.After(pUpdate.SourceModTime) { pUpdate.SourceModTime = modTime pUpdate.RecentSrcName = fileinfo.Name() } } } statFiles(pkg.GoFiles) statFiles(pkg.CgoFiles) statFiles(pkg.CFiles) statFiles(pkg.CXXFiles) statFiles(pkg.MFiles) statFiles(pkg.HFiles) statFiles(pkg.SFiles) statFiles(pkg.SwigFiles) statFiles(pkg.SwigCXXFiles) statFiles(pkg.SysoFiles) if shouldRunTests() { statFiles(pkg.TestGoFiles) } if len(pkg.TestGoFiles) > 0 { pUpdate.HasTests = true } pUpdate.IsProgram = pkg.Name == "main" targetPath := pUpdate.getAbsTargetPath() fileinfo, err := os.Stat(targetPath) if err != nil && !os.IsNotExist(err) { alog.Printf("@(error:Error stat-ing %s: %v)\n", targetPath, err) pUpdate.UpdateError = err return } else if err == nil { pUpdate.BuiltModTime = fileinfo.ModTime() } }
func main() { sighup := autorestart.NotifyOnSighup() _, err := flags.ParseArgs(&Opts, os.Args) if err != nil { err2, ok := err.(*flags.Error) if ok && err2.Type == flags.ErrHelp { return } alog.Printf("Error parsing command-line options: %s\n", err) return } if goPath == "" { alog.Printf("GOPATH is not set in the environment. Please set GOPATH first, then retry.\n") alog.Printf("For help setting GOPATH, see https://golang.org/doc/code.html\n") return } if Opts.NoColor { alog.DisableColor() } else { alog.AddAnsiColorCode("time", alog.ColorBlue) } alog.Printf("@(dim:autoinstall started.)\n") if Opts.MaxWorkers == 0 { Opts.MaxWorkers = runtime.GOMAXPROCS(0) } pluralProcess := "" if Opts.MaxWorkers != 1 { pluralProcess = "es" } alog.Printf("@(dim:Building all packages in) @(dim,cyan:%s)@(dim: using up to )@(dim,cyan:%d)@(dim: process%s.)\n", goPath, Opts.MaxWorkers, pluralProcess) if !Opts.Verbose { alog.Printf("@(dim:Use) --verbose @(dim:to show all messages during startup.)\n") } listener := watcher.NewListener() listener.Path = srcRoot // "_workspace" is a kludge to avoid recursing into Godeps workspaces // "node_modules" is a kludge to avoid walking into typically-huge node_modules trees listener.IgnorePart = stringset.New(".git", ".hg", "node_modules", "_workspace", "etld") listener.NotifyOnStartup = true listener.DebounceDuration = 200 * time.Millisecond listener.Start() // Delete any straggler tmp files, carefully files, err := ioutil.ReadDir(tmpdir) if err == nil { for _, file := range files { if filepath.Ext(file.Name()) == ".tmp" { os.Remove(filepath.Join(tmpdir, file.Name())) } } } else if os.IsNotExist(err) { err = os.MkdirAll(tmpdir, 0700) if err != nil { alog.Printf("@(error:Error creating temp directory at %s: %v)\n", tmpdir, err) return } } else { alog.Printf("@(error:Error checking contents of temp directory at %s: %v)\n", tmpdir, err) return } go processPathTriggers(listener.NotifyChan) go dispatcher() <-sighup startupLogger.Close() }
} func printStartupSummary() { alog.Printf("@(dim:Finished initial pass of all packages.)\n") updateStartupText(true) } func beVerbose() bool { return finishedInitialPass || Opts.Verbose } func shouldRunTests() bool { return finishedInitialPass && Opts.RunTests } var buildExtensions = stringset.New(".go", ".c", ".cc", ".cxx", ".cpp", ".h", ".hh", ".hpp", ".hxx", ".s", ".swig", ".swigcxx", ".syso") func processPathTriggers(notifyChan chan watcher.PathEvent) { for pathEvent := range notifyChan { path := pathEvent.Path moduleName, err := filepath.Rel(srcRoot, filepath.Dir(path)) if err != nil { alog.Bail(err) } if buildExtensions.Has(filepath.Ext(path)) { if Opts.Verbose { alog.Printf("@(dim:Triggering module) @(cyan:%s) @(dim:due to update of) @(cyan:%s)\n", moduleName, path) } moduleUpdateChan <- moduleName } }