X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=run.go;h=0178d726b9d9b476dbd01d1db45e713d0f5c80c0;hb=bf96757828d2ae663f5f54147c0e229f74fc9357;hp=fe78a87e68198abb8f63d20383394a3f50c37121;hpb=7492a39768035abafa55be738649a8dd035a89bd;p=goredo.git diff --git a/run.go b/run.go index fe78a87..0178d72 100644 --- a/run.go +++ b/run.go @@ -25,6 +25,7 @@ import ( "flag" "fmt" "io" + "log" "os" "os/exec" "path" @@ -51,11 +52,12 @@ const ( EnvStderrSilent = "REDO_SILENT" EnvNoSync = "REDO_NO_SYNC" - RedoDir = ".redo" - LockSuffix = ".lock" - DepSuffix = ".rec" - TmpPrefix = ".redo." - LogSuffix = ".log" + RedoDir = ".redo" + LockSuffix = ".lock" + DepSuffix = ".rec" + TmpPrefix = ".redo." + LogSuffix = ".log" + LogRecSuffix = ".log-rec" ) var ( @@ -71,6 +73,9 @@ var ( flagStderrSilent *bool TracedAll bool + + RunningProcs = map[int]*os.Process{} + RunningProcsM sync.Mutex ) func init() { @@ -138,7 +143,7 @@ func isModified(cwd, redoDir, tgt string) (bool, *Inode, error) { } return false, nil, err } - if m["Target"] != tgt { + if m["Type"] != DepTypeIfchange || m["Target"] != tgt { continue } fd, err := os.Open(path.Join(cwd, tgt)) @@ -383,14 +388,13 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { if StderrKeep { fdStderr, err = os.OpenFile( path.Join(redoDir, tgt+LogSuffix), - os.O_WRONLY|os.O_CREATE, + os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(0666), ) if err != nil { cleanup() return TgtErr{tgtOrig, err} } - fdStderr.Truncate(0) } shCtx := fmt.Sprintf( "sh: %s: %s %s cwd:%s dirprefix:%s", @@ -407,10 +411,11 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { } else { cmd.ExtraFiles = append(cmd.ExtraFiles, JSR) cmd.ExtraFiles = append(cmd.ExtraFiles, JSW) - cmd.Env = append(cmd.Env, fmt.Sprintf( - "%s=%s %s%d,%d", - MakeFlagsName, MakeFlags, MakeJSArg, 3+fdNum+0, 3+fdNum+1, - )) + makeFlags := fmt.Sprintf( + "%s %s%d,%d", MakeFlags, MakeJSArg, 3+fdNum+0, 3+fdNum+1, + ) + makeFlags = strings.Trim(makeFlags, " ") + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", MakeFlagsName, makeFlags)) fdNum += 2 cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvJSToken, jsToken)) } @@ -447,19 +452,22 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { fdStdout.Close() if fdStderr != nil { fdStderr.Close() - logRecPath := path.Join(redoDir, tgt+LogSuffix+DepSuffix) + logRecPath := path.Join(redoDir, tgt+LogRecSuffix) if fdStderr, err = os.OpenFile( logRecPath, - os.O_WRONLY|os.O_CREATE, + os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(0666), ); err == nil { - fdStderr.Truncate(0) fields := []recfile.Field{ {Name: "Build", Value: BuildUUID}, - {Name: "PID", Value: strconv.Itoa(cmd.Process.Pid)}, {Name: "PPID", Value: strconv.Itoa(os.Getpid())}, {Name: "Cwd", Value: cwd}, } + if cmd.Process != nil { + fields = append(fields, recfile.Field{ + Name: "PID", Value: strconv.Itoa(cmd.Process.Pid), + }) + } ts := new(tai64n.TAI64N) ts.FromTime(started) fields = append(fields, @@ -474,10 +482,10 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { }) fields = append(fields, recfile.Field{Name: "Cmd", Value: cmdName}) for _, arg := range args { - fields = append(fields, recfile.Field{Name: "Cmd", Value: arg}) + fields = append(fields, recfile.Field{Name: "Arg", Value: arg}) } - for _, e := range cmd.Env { - fields = append(fields, recfile.Field{Name: "Env", Value: e}) + for _, env := range cmd.Env { + fields = append(fields, recfile.Field{Name: "Env", Value: env}) } if exitErr != nil { fields = append(fields, recfile.Field{ @@ -486,12 +494,36 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { }) } w := bufio.NewWriter(fdStderr) + + var depInfo *DepInfo + fdDep, err := os.Open(fdDepPath) + if err != nil { + goto Err + } + depInfo, err = depRead(fdDep) + fdDep.Close() + if err != nil { + goto Err + } + for _, dep := range depInfo.ifchanges { + fields = append(fields, recfile.Field{ + Name: "Ifchange", + Value: dep["Target"], + }) + } _, err = recfile.NewWriter(w).WriteFields(fields...) - w.Flush() - fdStderr.Close() if err != nil { + goto Err + } + err = w.Flush() + Err: + if err != nil { + log.Println(err) os.Remove(logRecPath) } + fdStderr.Close() + } else { + log.Println("can not open", logRecPath, ":", err) } } lockRelease() @@ -517,6 +549,9 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { errs <- runErr return } + RunningProcsM.Lock() + RunningProcs[cmd.Process.Pid] = cmd.Process + RunningProcsM.Unlock() pid := fmt.Sprintf("[%d]", cmd.Process.Pid) trace(CDebug, "%s runs %s", tgtOrig, pid) @@ -553,18 +588,12 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { // Wait for job completion <-stderrTerm err = cmd.Wait() + RunningProcsM.Lock() + delete(RunningProcs, cmd.Process.Pid) + RunningProcsM.Unlock() finished = time.Now() runErr.Finished = &finished if err != nil { - // Try to commit .rec anyway - if !NoSync { - fdDep.Sync() - } - os.Rename(fdDep.Name(), path.Join(redoDir, tgt+DepSuffix)) - if !NoSync { - err = syncDir(redoDir) - } - exitErr = err.(*exec.ExitError) runErr.Err = err errs <- runErr @@ -572,6 +601,29 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { } // Was $1 touched? + if fd, err := os.Open(path.Join(cwdOrig, tgt)); err == nil { + errTouched := errors.New("$1 was explicitly touched") + 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 + } + } + } + if inodePrev != nil { if fd, err := os.Open(path.Join(cwdOrig, tgt)); err == nil { inode, err := inodeFromFile(fd) @@ -655,7 +707,8 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { goto Finish } } - err = os.Rename(fdDep.Name(), path.Join(redoDir, tgt+DepSuffix)) + fdDepPath = path.Join(redoDir, tgt+DepSuffix) + err = os.Rename(fdDep.Name(), fdDepPath) if err != nil { goto Finish }