X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=run.go;h=bb455e845df4b20abc91be0a10c584367b43a301;hb=e14100898b08c312919f58f712f19f623f602748;hp=fab67374eb24cb9bb14793cea1622d090098303a;hpb=634ee31ae35a2eaac517e0ffa1b7caede4b27ac5;p=goredo.git diff --git a/run.go b/run.go index fab6737..bb455e8 100644 --- a/run.go +++ b/run.go @@ -31,6 +31,7 @@ import ( "path" "strconv" "strings" + "sync" "syscall" "time" @@ -56,11 +57,11 @@ const ( ) var ( - Trace bool = false NoSync bool = false StderrKeep bool = false StderrSilent bool = false StderrPrefix string + Jobs sync.WaitGroup flagTrace = flag.Bool("x", false, "trace current target (sh -x) (set REDO_TRACE=1 for others too)") flagStderrKeep = flag.Bool("logs", false, "keep job's stderr (REDO_LOGS=1)") @@ -111,23 +112,24 @@ func tempfile(dir, prefix string) (*os.File, error) { return os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, os.FileMode(0666)) } -func isModified(cwd, redoDir, tgt string) (bool, error) { +func isModified(cwd, redoDir, tgt string) (bool, string, error) { fdDep, err := os.Open(path.Join(redoDir, tgt+DepSuffix)) if err != nil { if os.IsNotExist(err) { - return false, nil + return false, "", nil } - return false, err + return false, "", err } defer fdDep.Close() r := recfile.NewReader(fdDep) + var ourTs string for { m, err := r.NextMap() if err != nil { if err == io.EOF { break } - return false, err + return false, "", err } if m["Target"] != tgt { continue @@ -135,21 +137,21 @@ func isModified(cwd, redoDir, tgt string) (bool, error) { fd, err := os.Open(path.Join(cwd, tgt)) if err != nil { if os.IsNotExist(err) { - return false, nil + return false, "", nil } - return false, err + return false, "", err } defer fd.Close() - ourTs, err := fileCtime(fd) + ourTs, err = fileCtime(fd) if err != nil { - return false, err + return false, "", err } if ourTs != m["Ctime"] { - return true, nil + return true, ourTs, nil } break } - return false, nil + return false, ourTs, nil } func syncDir(dir string) error { @@ -162,9 +164,8 @@ func syncDir(dir string) error { return err } -func runScript(tgt string, errs chan error) error { - tgtOrig := tgt - cwd, tgt := cwdAndTgt(tgt) +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} @@ -200,20 +201,21 @@ func runScript(tgt string, errs chan error) error { unix.Flock(int(fdLock.Fd()), unix.LOCK_EX) lockRelease() trace(CDebug, "waiting done: %s", tgtOrig) - var builtNow bool + var depInfo *DepInfo fdDep, err := os.Open(path.Join(redoDir, tgt+DepSuffix)) if err != nil { if os.IsNotExist(err) { - err = errors.New("was not built") + err = errors.New("was not built: no .dep") } goto Finish } - builtNow, _, err = isBuiltNow(fdDep) + defer fdDep.Close() + depInfo, err = depRead(fdDep) if err != nil { goto Finish } - if !builtNow { - err = errors.New("was not built") + if depInfo.build != BuildUUID { + err = errors.New("was not built: build differs") } Finish: if err != nil { @@ -225,7 +227,7 @@ func runScript(tgt string, errs chan error) error { } // Check if target is not modified externally - modified, err := isModified(cwd, redoDir, tgt) + modified, tsPrev, err := isModified(cwd, redoDir, tgt) if err != nil { lockRelease() return TgtErr{tgtOrig, err} @@ -233,8 +235,10 @@ func runScript(tgt string, errs chan error) error { if modified { trace(CWarn, "%s externally modified: not redoing", tgtOrig) lockRelease() - errs <- nil - return TgtErr{tgtOrig, err} + go func() { + errs <- nil + }() + return nil } // Start preparing .dep @@ -320,7 +324,7 @@ func runScript(tgt string, errs chan error) error { } else { // Shell cmdName = "/bin/sh" - if Trace { + if traced { args = append(args, "-ex") } else { args = append(args, "-e") @@ -344,6 +348,7 @@ func runScript(tgt string, errs chan error) error { cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%d", EnvLevel, Level+1)) cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", EnvDirPrefix, dirPrefix)) cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", EnvBuildUUID, BuildUUID)) + childStderrPrefix := tempsuffix() cmd.Env = append(cmd.Env, fmt.Sprintf( "%s=%s", EnvStderrPrefix, childStderrPrefix, @@ -359,7 +364,9 @@ func runScript(tgt string, errs chan error) error { } else { cmd.ExtraFiles = append(cmd.ExtraFiles, JSR) cmd.ExtraFiles = append(cmd.ExtraFiles, JSW) - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d,%d", EnvJSFd, 3+fdNum+0, 3+fdNum+1)) + cmd.Env = append(cmd.Env, fmt.Sprintf( + "%s=%d,%d", EnvJSFd, 3+fdNum+0, 3+fdNum+1, + )) fdNum += 2 } @@ -451,6 +458,18 @@ func runScript(tgt string, errs chan error) error { return } + // Was $1 touched? + if fd, err := os.Open(path.Join(cwdOrig, tgt)); err == nil { + ts, err := fileCtime(fd) + fd.Close() + if err == nil && ts != tsPrev { + runErr.Err = errors.New("$1 was explicitly touched") + errs <- runErr + fd.Close() + return + } + } + // Does it produce both stdout and tmp? fiStdout, err := os.Stat(fdStdout.Name()) if err != nil { @@ -537,3 +556,15 @@ func runScript(tgt string, errs chan error) error { }() return nil } + +func isOkRun(err error) bool { + if err == nil { + return true + } + if err, ok := err.(RunErr); ok && err.Err == nil { + trace(CRedo, "%s", err.Name()) + return true + } + trace(CErr, "%s", err) + return false +}