dep.go | 41 +++++++++++++++++++++++------------------ dot.go | 3 ++- ifchange.go | 28 ++++++++++++++-------------- inode.go | 2 +- js.go | 15 ++++++++------- log.go | 4 ++-- main.go | 43 +++++++++++++++++++++++-------------------- ood.go | 73 ++++++++++++++++++++++++++++------------------------- run.go | 126 +++++++++++++++++++++++++++++------------------------ sources.go | 3 +++ diff --git a/dep.go b/dep.go index 9389bee14cf0971c5f5b1c59506a890c129a01145c794da999c538ebbd37dbf6..3907b1a8b2a8705802d325319a4894eaec1a0d8a38065b92891af9c01c4c8245 100644 --- a/dep.go +++ b/dep.go @@ -35,9 +35,11 @@ var ( DirPrefix string DepCwd string + + ErrBadRecFormat = errors.New("invalid format of .rec") ) -func recfileWrite(fdDep *os.File, fields ...recfile.Field) error { +func recfileWrite(fdDep io.StringWriter, fields ...recfile.Field) error { w := recfile.NewWriter(fdDep) if _, err := w.RecordStart(); err != nil { return err @@ -49,7 +51,7 @@ return nil } func ifcreate(fdDep *os.File, tgt string) error { - trace(CDebug, "ifcreate: %s <- %s", fdDep.Name(), tgt) + tracef(CDebug, "ifcreate: %s <- %s", fdDep.Name(), tgt) return recfileWrite( fdDep, recfile.Field{Name: "Type", Value: DepTypeIfcreate}, @@ -58,17 +60,17 @@ ) } func always(fdDep *os.File) error { - trace(CDebug, "always: %s", fdDep.Name()) + tracef(CDebug, "always: %s", fdDep.Name()) return recfileWrite(fdDep, recfile.Field{Name: "Type", Value: DepTypeAlways}) } func stamp(fdDep, src *os.File) error { var hsh string - hsh, err := fileHash(os.Stdin) + hsh, err := fileHash(src) if err != nil { return err } - trace(CDebug, "stamp: %s <- %s", fdDep.Name(), hsh) + tracef(CDebug, "stamp: %s <- %s", fdDep.Name(), hsh) return recfileWrite( fdDep, recfile.Field{Name: "Type", Value: DepTypeStamp}, @@ -85,7 +87,7 @@ return hex.EncodeToString(h.Sum(nil)), nil } func writeDep(fdDep *os.File, cwd, tgt string) error { - trace(CDebug, "ifchange: %s <- %s", fdDep.Name(), tgt) + tracef(CDebug, "ifchange: %s <- %s", fdDep.Name(), tgt) fd, err := os.Open(path.Join(cwd, tgt)) if err != nil { return err @@ -115,9 +117,9 @@ fields = append(fields, inode.RecfileFields()...) return recfileWrite(fdDep, fields...) } -func writeDeps(fdDep *os.File, tgts []string) (err error) { +func writeDeps(fdDep *os.File, tgts []string) error { if fdDep == nil { - trace(CDebug, "no opened fdDep: %s", tgts) + tracef(CDebug, "no opened fdDep: %s", tgts) return nil } for _, tgt := range tgts { @@ -137,7 +139,7 @@ } if _, errStat := os.Stat(tgt); errStat == nil { err = writeDep(fdDep, tgtDir, tgtRel) } else { - trace(CDebug, "ifchange: %s <- %s (non-existing)", fdDep.Name(), tgtRel) + tracef(CDebug, "ifchange: %s <- %s (non-existing)", fdDep.Name(), tgtRel) fields := []recfile.Field{ {Name: "Type", Value: DepTypeIfchange}, {Name: "Target", Value: tgtRel}, @@ -146,8 +148,11 @@ inodeDummy := Inode{} fields = append(fields, inodeDummy.RecfileFields()...) err = recfileWrite(fdDep, fields...) } + if err != nil { + return err + } } - return + return nil } type DepInfo struct { @@ -158,22 +163,22 @@ ifcreates []string ifchanges []map[string]string } -func depRead(fdDep *os.File) (*DepInfo, error) { +func depRead(fdDep io.Reader) (*DepInfo, error) { r := recfile.NewReader(fdDep) m, err := r.NextMap() if err != nil { return nil, err } depInfo := DepInfo{} - if b := m["Build"]; b == "" { + b := m["Build"] + if b == "" { return nil, errors.New(".rec missing Build:") - } else { - depInfo.build = b } + depInfo.build = b for { m, err := r.NextMap() if err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { break } return nil, err @@ -184,7 +189,7 @@ depInfo.always = true case DepTypeIfcreate: dep := m["Target"] if dep == "" { - return nil, errors.New("invalid format of .rec") + return nil, ErrBadRecFormat } depInfo.ifcreates = append(depInfo.ifcreates, dep) case DepTypeIfchange: @@ -193,11 +198,11 @@ depInfo.ifchanges = append(depInfo.ifchanges, m) case DepTypeStamp: hsh := m["Hash"] if hsh == "" { - return nil, errors.New("invalid format of .rec") + return nil, ErrBadRecFormat } depInfo.stamp = hsh default: - return nil, errors.New("invalid format of .rec") + return nil, ErrBadRecFormat } } return &depInfo, nil diff --git a/dot.go b/dot.go index 51703a6f25818b336ed959cf53d8ed8f9a84d2f10f263483b1fd20d06c28e8a1..88923188d1ba0d1cd9cedc30c97b573ccee5aa25c69476dc9cd8c64c37bc97ec 100644 --- a/dot.go +++ b/dot.go @@ -20,6 +20,7 @@ package main import ( + "errors" "fmt" "io" "os" @@ -46,7 +47,7 @@ r := recfile.NewReader(fdDep) for { m, err := r.NextMap() if err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { break } return nil, err diff --git a/ifchange.go b/ifchange.go index 32876110b0c199520ab0444657463d9ef48bea7ecbeea3d27a91e5939609dfb2..4421c87086c46856cac999c8f7b27452e57746750b005737c095cbe2d4679b85 100644 --- a/ifchange.go +++ b/ifchange.go @@ -45,13 +45,13 @@ returnReady := false tgtRel := cwdMustRel(cwd, tgt) if depInfo.always { if depInfo.build == BuildUUID { - trace( + tracef( CDebug, "ood: %s%s always, but already build", strings.Repeat(". ", level), tgtOrig, ) returnReady = true } else { - trace(CDebug, "ood: %s%s always", strings.Repeat(". ", level), tgtOrig) + tracef(CDebug, "ood: %s%s always", strings.Repeat(". ", level), tgtOrig) alwayses = append(alwayses, tgtRel) returnReady = true } @@ -87,7 +87,7 @@ } func buildDependants(tgts []string) map[string]struct{} { defer Jobs.Wait() - trace(CDebug, "collecting deps") + tracef(CDebug, "collecting deps") seen := map[string]struct{}{} deps := map[string]map[string]struct{}{} for _, tgtInitial := range tgts { @@ -106,11 +106,11 @@ defer func() { Level = levelOrig }() Level = 1 - trace(CDebug, "building %d alwayses: %v", len(seen), seen) + tracef(CDebug, "building %d alwayses: %v", len(seen), seen) errs := make(chan error, len(seen)) for tgt := range seen { if err := runScript(tgt, errs, false); err != nil { - trace(CErr, "always run error: %s, skipping dependants", err) + tracef(CErr, "always run error: %s, skipping dependants", err) return nil } } @@ -121,7 +121,7 @@ } Jobs.Wait() close(errs) if !ok { - trace(CDebug, "alwayses failed, skipping dependants") + tracef(CDebug, "alwayses failed, skipping dependants") return nil } @@ -134,28 +134,28 @@ return seen } RebuildDeps: - trace(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc) + tracef(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc) queue := []string{} for _, tgt := range queueSrc { for dep := range deps[tgt] { queue = append(queue, dep) } } - trace(CDebug, "building %d dependant targets: %v", len(queue), queue) + tracef(CDebug, "building %d dependant targets: %v", len(queue), queue) errs = make(chan error, len(queue)) jobs := 0 queueSrc = []string{} for _, tgt := range queue { ood, err := isOODWithTrace(Cwd, tgt, 0, seen) if err != nil { - trace(CErr, "dependant error: %s, skipping dependants", err) + tracef(CErr, "dependant error: %s, skipping dependants", err) return nil } if !ood { continue } if err := runScript(tgt, errs, false); err != nil { - trace(CErr, "dependant error: %s, skipping dependants", err) + tracef(CErr, "dependant error: %s, skipping dependants", err) return nil } queueSrc = append(queueSrc, tgt) @@ -166,7 +166,7 @@ for i := 0; i < jobs; i++ { ok = isOkRun(<-errs) && ok } if !ok { - trace(CDebug, "dependants failed, skipping them") + tracef(CDebug, "dependants failed, skipping them") return nil } Jobs.Wait() @@ -186,14 +186,14 @@ } defer Jobs.Wait() seen := buildDependants(tgts) oodTgtsClear() - trace(CDebug, "building %d targets: %v", len(tgts), tgts) + tracef(CDebug, "building %d targets: %v", len(tgts), tgts) jobs := 0 errs := make(chan error, len(tgts)) var ood bool var err error for _, tgt := range tgts { if _, ok := seen[tgt]; ok { - trace(CDebug, "%s was already build as a dependant", tgt) + tracef(CDebug, "%s was already build as a dependant", tgt) continue } ood = true @@ -207,7 +207,7 @@ if !ood { continue } if isSrc(Cwd, tgt) { - trace(CDebug, "%s is source, not redoing", tgt) + tracef(CDebug, "%s is source, not redoing", tgt) continue } if err = runScript(tgt, errs, traced); err != nil { diff --git a/inode.go b/inode.go index aa2510491067b1f9a029d0e3545d93165fc1d388777a18743da8464b673b65d0..fdf730f8a882e0727c0580961b21fa16f382057cf938d78ec2dfc87136a40ca3 100644 --- a/inode.go +++ b/inode.go @@ -30,7 +30,7 @@ ) const EnvInodeNoTrust = "REDO_INODE_NO_TRUST" -var InodeTrust bool = false +var InodeTrust = false type Inode struct { Size int64 diff --git a/js.go b/js.go index c7123f41d71942b864ef2c4017152d95d33208fed368a57cae9bf575faf23210..61f2acfc589ce17f0a07b144bfbc5a562545e50afd4a729e1b1142482b66f996 100644 --- a/js.go +++ b/js.go @@ -82,11 +82,12 @@ func jsStart(jobsEnv string) { jobs := uint64(1) var err error - if *flagJobs == 0 { + switch { + case *flagJobs == 0: jobs = 0 - } else if *flagJobs > 0 { + case *flagJobs > 0: jobs = uint64(*flagJobs) - } else if jobsEnv != "" { + case jobsEnv != "": jobs, err = strconv.ParseUint(jobsEnv, 10, 64) if err != nil { log.Fatalln("can not parse", EnvJobs, err) @@ -100,7 +101,7 @@ JSR, JSW, err = os.Pipe() if err != nil { log.Fatalln(err) } - trace(CJS, "initial fill with %d", jobs) + tracef(CJS, "initial fill with %d", jobs) jsTokens[BMakeGoodToken] = int(jobs) for ; jobs > 0; jobs-- { jsReleaseNoLock(BMakeGoodToken) @@ -180,7 +181,7 @@ func jsRelease(ctx string, token byte) { if JSW == nil { return } - trace(CJS, "release from %s", ctx) + tracef(CJS, "release from %s", ctx) jsTokensM.Lock() jsTokens[token]-- jsReleaseNoLock(token) @@ -201,7 +202,7 @@ func jsAcquire(ctx string) byte { if JSR == nil { return BMakeGoodToken } - trace(CJS, "acquire for %s", ctx) + tracef(CJS, "acquire for %s", ctx) token := []byte{0} if n, err := JSR.Read(token); err != nil || n != 1 { log.Fatalln("can not read JSR:", err) @@ -209,6 +210,6 @@ } jsTokensM.Lock() jsTokens[token[0]]++ jsTokensM.Unlock() - trace(CJS, "acquired for %s", ctx) + tracef(CJS, "acquired for %s", ctx) return token[0] } diff --git a/log.go b/log.go index 2f74f912278928b9e6fda6a171f738f6081a59492d3d88610f9a5b02f28d909e..33f3dfae565c1dc49286e129dcefd853b6e7334b7b885cc905d73357da0917a9 100644 --- a/log.go +++ b/log.go @@ -59,7 +59,7 @@ CErr string CWarn string CJS string CReset string - CNone string = "NONE" + CNone = "NONE" flagDebug = flag.Bool("d", false, fmt.Sprintf("enable debug logging (%s=1)", EnvDebug)) flagNoProgress *bool @@ -108,7 +108,7 @@ } return s + KeyEraseLine + end } -func trace(level, format string, args ...interface{}) { +func tracef(level, format string, args ...interface{}) { var p string if MyPid != 0 { p = fmt.Sprintf("[%d] ", MyPid) diff --git a/main.go b/main.go index bc62bc436b3f6dccef4022fdb56bc23aefae72f9a4dee82745ebc588e1646f49..4491bbaff86b55d520b92c64969f97aa6a96675a34ec27a1035245b5bbee9fe8 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ import ( "bufio" "bytes" "crypto/rand" + "errors" "flag" "fmt" "io" @@ -62,8 +63,8 @@ BuildUUID string IsTopRedo bool // is it the top redo instance ) -func mustSetenv(key, value string) { - if err := os.Setenv(key, value); err != nil { +func mustSetenv(key string) { + if err := os.Setenv(key, "1"); err != nil { panic(err) } } @@ -154,28 +155,28 @@ DirPrefix = os.Getenv(EnvDirPrefix) DepCwd = os.Getenv(EnvDepCwd) if flagStderrKeep != nil && *flagStderrKeep { - mustSetenv(EnvStderrKeep, "1") + mustSetenv(EnvStderrKeep) } if flagStderrSilent != nil && *flagStderrSilent { - mustSetenv(EnvStderrSilent, "1") + mustSetenv(EnvStderrSilent) } if flagNoProgress != nil && *flagNoProgress { - mustSetenv(EnvNoProgress, "1") + mustSetenv(EnvNoProgress) } if flagDebug != nil && *flagDebug { - mustSetenv(EnvDebug, "1") + mustSetenv(EnvDebug) } if flagLogWait != nil && *flagLogWait { - mustSetenv(EnvLogWait, "1") + mustSetenv(EnvLogWait) } if flagLogLock != nil && *flagLogLock { - mustSetenv(EnvLogLock, "1") + mustSetenv(EnvLogLock) } if flagLogPid != nil && *flagLogPid { - mustSetenv(EnvLogPid, "1") + mustSetenv(EnvLogPid) } if flagLogJS != nil && *flagLogJS { - mustSetenv(EnvLogJS, "1") + mustSetenv(EnvLogJS) } StderrKeep = os.Getenv(EnvStderrKeep) == "1" StderrSilent = os.Getenv(EnvStderrSilent) == "1" @@ -189,7 +190,7 @@ MyPid = os.Getpid() } var traced bool if flagTraceAll != nil && *flagTraceAll { - mustSetenv(EnvTrace, "1") + mustSetenv(EnvTrace) } if os.Getenv(EnvTrace) == "1" { TracedAll = true @@ -227,7 +228,9 @@ tgtsRaw, err := ioutil.ReadAll(bufio.NewReader(fd)) if err != nil { log.Fatalln(err) } - unix.Flock(int(fdLock.Fd()), unix.LOCK_UN) + if err = unix.Flock(int(fdLock.Fd()), unix.LOCK_UN); err != nil { + log.Fatalln(err) + } OODTgts = map[string]struct{}{} for _, tgtRaw := range bytes.Split(tgtsRaw, []byte{0}) { t := string(tgtRaw) @@ -235,7 +238,7 @@ if t == "" { continue } OODTgts[t] = struct{}{} - trace(CDebug, "ood: known to be: %s", t) + tracef(CDebug, "ood: known to be: %s", t) } } @@ -284,23 +287,23 @@ tgts[i] = cwdMustRel(tgt) } } - killed := make(chan os.Signal, 0) + killed := make(chan os.Signal, 1) signal.Notify(killed, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) go func() { <-killed - trace(CDebug, "[%s] killed", BuildUUID) + tracef(CDebug, "[%s] killed", BuildUUID) jsReleaseAll() RunningProcsM.Lock() for pid, proc := range RunningProcs { - trace(CDebug, "[%s] killing child %d", BuildUUID, pid) - proc.Signal(syscall.SIGTERM) + tracef(CDebug, "[%s] killing child %d", BuildUUID, pid) + _ = proc.Signal(syscall.SIGTERM) } os.Exit(1) }() ok := true err = nil - trace( + tracef( CDebug, "[%s] run: %s %s cwd:%s dirprefix:%s", BuildUUID, cmdName, tgts, Cwd, DirPrefix, ) @@ -386,7 +389,7 @@ r := recfile.NewReader(fdTmp) for { m, err := r.NextMap() if err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { break } break CmdSwitch @@ -487,6 +490,6 @@ rc := 0 if !ok || err != nil { rc = 1 } - trace(CDebug, "[%s] finished: %s %s", BuildUUID, cmdName, tgts) + tracef(CDebug, "[%s] finished: %s %s", BuildUUID, cmdName, tgts) os.Exit(rc) } diff --git a/ood.go b/ood.go index feb800c5f4417946d963cc76e927a453de95446416aae389f2c6aaec0bad5800..55519056c218d922ce569373d3ab2f9b6c2af7e04d02faaf4d9e4200e4193da6 100644 --- a/ood.go +++ b/ood.go @@ -48,14 +48,14 @@ FdOODTgts *os.File FdOODTgtsLock *os.File ) -type TgtErr struct { +type TgtError struct { Tgt string Err error } -func (e TgtErr) Unwrap() error { return e.Err } +func (e TgtError) Unwrap() error { return e.Err } -func (e TgtErr) Error() string { +func (e TgtError) Error() string { return fmt.Sprintf("%s: %s", e.Tgt, e.Err) } @@ -107,33 +107,33 @@ } func isOOD(cwd, tgtOrig string, level int, seen map[string]struct{}) (bool, error) { indent := strings.Repeat(". ", level) - trace(CDebug, "ood: %s%s checking", indent, tgtOrig) + tracef(CDebug, "ood: %s%s checking", indent, tgtOrig) cwd, tgt := cwdAndTgt(path.Join(cwd, tgtOrig)) depPath := path.Join(cwd, RedoDir, tgt+DepSuffix) fdDep, err := os.Open(depPath) if err != nil { - trace(CDebug, "ood: %s%s -> no dep: %s", indent, tgtOrig, depPath) + tracef(CDebug, "ood: %s%s -> no dep: %s", indent, tgtOrig, depPath) return true, nil } depInfo, err := depRead(fdDep) fdDep.Close() if err != nil { - return true, TgtErr{tgtOrig, err} + return true, TgtError{tgtOrig, err} } if depInfo.build == BuildUUID { - trace(CDebug, "ood: %s%s -> already built", indent, tgtOrig) + tracef(CDebug, "ood: %s%s -> already built", indent, tgtOrig) return false, nil } if _, err := os.Stat(path.Join(cwd, tgt)); err != nil && os.IsNotExist(err) { - trace(CDebug, "ood: %s%s -> non-existent", indent, tgtOrig) + tracef(CDebug, "ood: %s%s -> non-existent", indent, tgtOrig) return true, nil } ood := false for _, dep := range depInfo.ifcreates { if _, err := os.Stat(path.Join(cwd, dep)); err == nil { - trace(CDebug, "ood: %s%s -> %s created", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s created", indent, tgtOrig, dep) ood = true goto Done } @@ -142,80 +142,80 @@ for _, m := range depInfo.ifchanges { dep := m["Target"] if dep == "" { - return ood, TgtErr{tgtOrig, errors.New("invalid format of .rec: missing Target")} + return ood, TgtError{tgtOrig, errors.New("invalid format of .rec: missing Target")} } theirInode, err := inodeFromRec(m) if err != nil { - return ood, TgtErr{tgtOrig, fmt.Errorf("invalid format of .rec: %w", err)} + return ood, TgtError{tgtOrig, fmt.Errorf("invalid format of .rec: %w", err)} } theirHsh := m["Hash"] - trace(CDebug, "ood: %s%s -> %s: checking", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: checking", indent, tgtOrig, dep) fd, err := os.Open(path.Join(cwd, dep)) if err != nil { if os.IsNotExist(err) { - trace(CDebug, "ood: %s%s -> %s: not exists", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: not exists", indent, tgtOrig, dep) ood = true goto Done } - return ood, TgtErr{tgtOrig, err} + return ood, TgtError{tgtOrig, err} } defer fd.Close() inode, err := inodeFromFile(fd) if err != nil { - return ood, TgtErr{tgtOrig, err} + return ood, TgtError{tgtOrig, err} } if inode.Size != theirInode.Size { - trace(CDebug, "ood: %s%s -> %s: size differs", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: size differs", indent, tgtOrig, dep) ood = true goto Done } if InodeTrust && inode.Equals(theirInode) { - trace(CDebug, "ood: %s%s -> %s: same inode", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: same inode", indent, tgtOrig, dep) } else { - trace(CDebug, "ood: %s%s -> %s: inode differs", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: inode differs", indent, tgtOrig, dep) hsh, err := fileHash(fd) if err != nil { - return ood, TgtErr{tgtOrig, err} + return ood, TgtError{tgtOrig, err} } if theirHsh != hsh { - trace(CDebug, "ood: %s%s -> %s: hash differs", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: hash differs", indent, tgtOrig, dep) ood = true goto Done } - trace(CDebug, "ood: %s%s -> %s: same hash", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: same hash", indent, tgtOrig, dep) } fd.Close() // optimization not to hold it for long if dep == tgt { - trace(CDebug, "ood: %s%s -> %s: same target", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: same target", indent, tgtOrig, dep) continue } if isSrc(cwd, dep) { - trace(CDebug, "ood: %s%s -> %s: is source", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: is source", indent, tgtOrig, dep) continue } if _, ok := seen[cwdMustRel(cwd, dep)]; ok { - trace(CDebug, "ood: %s%s -> %s: was always built", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: was always built", indent, tgtOrig, dep) continue } depOod, err := isOODWithTrace(cwd, dep, level+1, seen) if err != nil { - return ood, TgtErr{tgtOrig, err} + return ood, TgtError{tgtOrig, err} } if depOod { - trace(CDebug, "ood: %s%s -> %s: ood", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: ood", indent, tgtOrig, dep) ood = true goto Done } - trace(CDebug, "ood: %s%s -> %s: !ood", indent, tgtOrig, dep) + tracef(CDebug, "ood: %s%s -> %s: !ood", indent, tgtOrig, dep) } Done: - trace(CDebug, "ood: %s%s: %v", indent, tgtOrig, ood) + tracef(CDebug, "ood: %s%s: %v", indent, tgtOrig, ood) return ood, nil } @@ -231,14 +231,14 @@ } _, ood := OODTgts[p] if ood { if !isOODByBuildUUID(cwd, tgtOrig) { - trace( + tracef( CDebug, "ood: %s%s -> already built", strings.Repeat(". ", level), tgtOrig, ) return false, nil } - trace( + tracef( CDebug, "ood: %s%s true, external decision", strings.Repeat(". ", level), tgtOrig, @@ -259,16 +259,21 @@ } if _, err := FdOODTgts.WriteString(p + "\x00"); err != nil { log.Fatalln(err) } - unix.Flock(int(FdOODTgtsLock.Fd()), unix.LOCK_UN) + if err = unix.Flock(int(FdOODTgtsLock.Fd()), unix.LOCK_UN); err != nil { + log.Fatalln(err) + } return true, nil } func oodTgtsClear() { - if err := unix.Flock(int(FdOODTgtsLock.Fd()), unix.LOCK_EX); err != nil { + var err error + if err = unix.Flock(int(FdOODTgtsLock.Fd()), unix.LOCK_EX); err != nil { + log.Fatalln(err) + } + if err = FdOODTgts.Truncate(0); err != nil { log.Fatalln(err) } - if err := FdOODTgts.Truncate(0); err != nil { + if err = unix.Flock(int(FdOODTgtsLock.Fd()), unix.LOCK_UN); err != nil { log.Fatalln(err) } - unix.Flock(int(FdOODTgtsLock.Fd()), unix.LOCK_UN) } diff --git a/run.go b/run.go index e2b629dad6e3c79752e167ef8271957e5200b66890bc9b3935e35e5ba2f6ff8f..97dd39be9198b10c8c068a5551be3f22ec74808c4a6aeac1b0729fcf5abf57eb 100644 --- a/run.go +++ b/run.go @@ -61,9 +61,9 @@ LogRecSuffix = ".log-rec" ) var ( - NoSync bool = false - StderrKeep bool = false - StderrSilent bool = false + NoSync = false + StderrKeep = false + StderrSilent = false StderrPrefix string Jobs sync.WaitGroup @@ -76,6 +76,8 @@ TracedAll bool RunningProcs = map[int]*os.Process{} RunningProcsM sync.Mutex + + Err1WasTouched = errors.New("$1 was explicitly touched") ) func init() { @@ -92,7 +94,7 @@ flagStderrSilent = flag.Bool("s", false, fmt.Sprintf("silent, do not print job's stderr (%s=1)", EnvStderrSilent)) } -type RunErr struct { +type RunError struct { Tgt string DoFile string Started *time.Time @@ -100,7 +102,7 @@ Finished *time.Time Err error } -func (e *RunErr) Name() string { +func (e *RunError) Name() string { var name string if e.DoFile == "" { name = e.Tgt @@ -113,7 +115,7 @@ } return fmt.Sprintf("%s (%.3fs)", name, e.Finished.Sub(*e.Started).Seconds()) } -func (e RunErr) Error() string { +func (e RunError) Error() string { return fmt.Sprintf("%s: %s", e.Name(), e.Err) } @@ -138,7 +140,7 @@ var ourInode *Inode for { m, err := r.NextMap() if err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { break } return false, nil, err @@ -184,7 +186,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { cwd, tgt := cwdAndTgt(tgtOrig) redoDir := path.Join(cwd, RedoDir) if err := mkdirs(redoDir); err != nil { - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } // Acquire lock @@ -194,34 +196,42 @@ os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.FileMode(0666), ) if err != nil { - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } lockRelease := func() { - trace(CLock, "LOCK_UN: %s", fdLock.Name()) - unix.Flock(int(fdLock.Fd()), unix.LOCK_UN) + tracef(CLock, "LOCK_UN: %s", fdLock.Name()) + if err := unix.Flock(int(fdLock.Fd()), unix.LOCK_UN); err != nil { + log.Fatalln(err) + } fdLock.Close() } - trace(CLock, "LOCK_NB: %s", fdLock.Name()) + tracef(CLock, "LOCK_NB: %s", fdLock.Name()) // Waiting for job completion, already taken by someone else if err = unix.Flock(int(fdLock.Fd()), unix.LOCK_EX|unix.LOCK_NB); err != nil { if uintptr(err.(syscall.Errno)) != uintptr(unix.EWOULDBLOCK) { fdLock.Close() - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } Jobs.Add(1) - trace(CDebug, "waiting: %s", tgtOrig) + tracef(CDebug, "waiting: %s", tgtOrig) if FdStatus != nil { - FdStatus.Write([]byte{StatusWait}) + if _, err = FdStatus.Write([]byte{StatusWait}); err != nil { + log.Fatalln(err) + } } go func() { defer Jobs.Done() - trace(CLock, "LOCK_EX: %s", fdLock.Name()) - unix.Flock(int(fdLock.Fd()), unix.LOCK_EX) + tracef(CLock, "LOCK_EX: %s", fdLock.Name()) + if err := unix.Flock(int(fdLock.Fd()), unix.LOCK_EX); err != nil { + log.Fatalln(err) + } lockRelease() - trace(CDebug, "waiting done: %s", tgtOrig) + tracef(CDebug, "waiting done: %s", tgtOrig) if FdStatus != nil { - FdStatus.Write([]byte{StatusWaited}) + if _, err = FdStatus.Write([]byte{StatusWaited}); err != nil { + log.Fatalln(err) + } } var depInfo *DepInfo fdDep, err := os.Open(path.Join(redoDir, tgt+DepSuffix)) @@ -241,7 +251,7 @@ err = errors.New("was not built: build differs") } Finish: if err != nil { - err = TgtErr{tgtOrig, err} + err = TgtError{tgtOrig, err} } errs <- err }() @@ -252,10 +262,10 @@ // Check if target is not modified externally modified, inodePrev, err := isModified(cwd, redoDir, tgt) if err != nil { lockRelease() - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } if modified { - trace(CWarn, "%s externally modified: not redoing", tgtOrig) + tracef(CWarn, "%s externally modified: not redoing", tgtOrig) lockRelease() go func() { errs <- nil @@ -267,7 +277,7 @@ // Start preparing .rec fdDep, err := tempfile(redoDir, tgt+DepSuffix) if err != nil { lockRelease() - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } fdDepPath := fdDep.Name() cleanup := func() { @@ -279,18 +289,18 @@ if _, err = recfile.NewWriter(fdDep).WriteFields( recfile.Field{Name: "Build", Value: BuildUUID}, ); err != nil { cleanup() - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } // Find .do doFile, upLevels, err := findDo(fdDep, cwd, tgt) if err != nil { cleanup() - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } if doFile == "" { cleanup() - return TgtErr{tgtOrig, errors.New("no .do found")} + return TgtError{tgtOrig, errors.New("no .do found")} } // Determine basename and DIRPREFIX @@ -306,7 +316,7 @@ } cwd = path.Clean(cwd) doFilePath := path.Join(cwd, doFile) basename := tgt - runErr := RunErr{Tgt: tgtOrig} + runErr := RunError{Tgt: tgtOrig} if strings.HasPrefix(doFile, "default.") { basename = tgt[:len(tgt)-(len(doFile)-len("default.")-len(".do"))-1] runErr.DoFile = doFileRelPath @@ -314,10 +324,10 @@ } if err = writeDep(fdDep, cwdOrig, doFileRelPath); err != nil { cleanup() - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } fdDep.Close() - trace(CWait, "%s", runErr.Name()) + tracef(CWait, "%s", runErr.Name()) // Prepare command line var cmdName string @@ -339,7 +349,7 @@ // Temporary file for stdout fdStdout, err := tempfile(cwdOrig, tgt) if err != nil { cleanup() - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } stdoutPath := fdStdout.Name() fdStdout.Close() @@ -393,14 +403,14 @@ os.FileMode(0666), ) if err != nil { cleanup() - return TgtErr{tgtOrig, err} + return TgtError{tgtOrig, err} } } shCtx := fmt.Sprintf( "sh: %s: %s %s cwd:%s dirprefix:%s", tgtOrig, cmdName, args, cwd, dirPrefix, ) - trace(CDebug, "%s", shCtx) + tracef(CDebug, "%s", shCtx) Jobs.Add(1) go func() { @@ -421,7 +431,9 @@ cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvJSToken, jsToken)) } if FdStatus != nil { - FdStatus.Write([]byte{StatusRun}) + if _, err = FdStatus.Write([]byte{StatusRun}); err != nil { + log.Fatalln(err) + } } var finished time.Time @@ -532,7 +544,9 @@ os.Remove(fdStdout.Name()) os.Remove(tmpPath) os.Remove(fdLock.Name()) if FdStatus != nil { - FdStatus.Write([]byte{StatusDone}) + if _, err = FdStatus.Write([]byte{StatusDone}); err != nil { + log.Fatalln(err) + } } Jobs.Done() }() @@ -553,9 +567,9 @@ RunningProcsM.Lock() RunningProcs[cmd.Process.Pid] = cmd.Process RunningProcsM.Unlock() pid := fmt.Sprintf("[%d]", cmd.Process.Pid) - trace(CDebug, "%s runs %s", tgtOrig, pid) + tracef(CDebug, "%s runs %s", tgtOrig, pid) - stderrTerm := make(chan struct{}, 0) + stderrTerm := make(chan struct{}) go func() { scanner := bufio.NewScanner(stderr) var line string @@ -577,9 +591,9 @@ if StderrSilent { continue } if MyPid == 0 { - trace(CNone, "%s", line) + tracef(CNone, "%s", line) } else { - trace(CNone, "%s %s", pid, line) + tracef(CNone, "%s %s", pid, line) } } close(stderrTerm) @@ -602,25 +616,24 @@ } // Was $1 touched? if fd, err := os.Open(path.Join(cwdOrig, tgt)); err == nil { - errTouched := errors.New("$1 was explicitly touched") + errTouched := Err1WasTouched if inodePrev == nil { fd.Close() runErr.Err = errTouched errs <- runErr return - } else { - inode, err := inodeFromFile(fd) - fd.Close() - if err != nil { - runErr.Err = err - errs <- runErr - return - } - if !inode.Equals(inodePrev) { - runErr.Err = errTouched - errs <- runErr - return - } + } + inode, err := inodeFromFile(fd) + fd.Close() + if err != nil { + runErr.Err = err + errs <- runErr + return + } + if !inode.Equals(inodePrev) { + runErr.Err = errTouched + errs <- runErr + return } } @@ -629,7 +642,7 @@ if fd, err := os.Open(path.Join(cwdOrig, tgt)); err == nil { inode, err := inodeFromFile(fd) fd.Close() if err == nil && !inode.Equals(inodePrev) { - runErr.Err = errors.New("$1 was explicitly touched") + runErr.Err = Err1WasTouched errs <- runErr return } @@ -729,10 +742,11 @@ func isOkRun(err error) bool { if err == nil { return true } - if err, ok := err.(RunErr); ok && err.Err == nil { - trace(CRedo, "%s", err.Name()) + var runErr RunError + if errors.As(err, &runErr) && runErr.Err == nil { + tracef(CRedo, "%s", runErr.Name()) return true } - trace(CErr, "%s", err) + tracef(CErr, "%s", err) return false } diff --git a/sources.go b/sources.go index 04f5efb22f274b6b571c6eb8bf81bc878a1b01e4b28f5d4377510078574d197a..77efe32fd8ad0ae484d51524cfafec14db4841a6420af8e9ad99e6fbe3d3828a 100644 --- a/sources.go +++ b/sources.go @@ -40,6 +40,9 @@ } return nil, err } depInfo, err := depRead(fdDep) + if err != nil { + return nil, err + } fdDep.Close() for _, m := range depInfo.ifchanges { depTgt := m["Target"]