"flag"
"fmt"
"io"
+ "log"
"os"
"os/exec"
"path"
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 (
flagStderrSilent *bool
TracedAll bool
+
+ RunningProcs = map[int]*os.Process{}
+ RunningProcsM sync.Mutex
)
func init() {
}
return false, nil, err
}
- if m["Target"] != tgt {
+ if m["Type"] != DepTypeIfchange || m["Target"] != tgt {
continue
}
fd, err := os.Open(path.Join(cwd, tgt))
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",
} 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))
}
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,
})
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{
})
}
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()
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)
// 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
}
// 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)
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
}