X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=run.go;h=d31c8a0c5a4ffb52816cb74d90de5536c8fe515b;hb=46e189a9c6398c1ab1245ab1e9827b959db29219;hp=1c1b0d7759295786f9e1237975a5a8e18064bd1f;hpb=c41fe0fbd726f397636b569161f286821e221885;p=goredo.git diff --git a/run.go b/run.go index 1c1b0d7..d31c8a0 100644 --- a/run.go +++ b/run.go @@ -25,10 +25,12 @@ import ( "flag" "fmt" "io" + "log" "os" "os/exec" "path" "path/filepath" + "strconv" "strings" "sync" "syscall" @@ -42,6 +44,7 @@ import ( const ( EnvDepFd = "REDO_DEP_FD" EnvDirPrefix = "REDO_DIRPREFIX" + EnvDepCwd = "REDO_DEP_CWD" EnvBuildUUID = "REDO_BUILD_UUID" EnvStderrPrefix = "REDO_STDERR_PREFIX" EnvTrace = "REDO_TRACE" @@ -63,14 +66,28 @@ var ( StderrPrefix string Jobs sync.WaitGroup - flagTrace = flag.Bool("x", false, "trace (sh -x) current targets") - flagTraceAll = flag.Bool("xx", false, fmt.Sprintf("trace (sh -x) all targets (%s=1)", EnvTrace)) - flagStderrKeep = flag.Bool("logs", false, fmt.Sprintf("keep job's stderr (%s=1)", EnvStderrKeep)) - flagStderrSilent = flag.Bool("silent", false, fmt.Sprintf("do not print job's stderr (%s=1)", EnvStderrSilent)) + flagTrace *bool + flagTraceAll *bool + flagStderrKeep *bool + flagStderrSilent *bool TracedAll bool ) +func init() { + cmdName := CmdName() + if !(cmdName == CmdNameRedo || cmdName == CmdNameRedoIfchange) { + return + } + flagTrace = flag.Bool("x", false, "trace (sh -x) current targets") + flagTraceAll = flag.Bool("xx", false, + fmt.Sprintf("trace (sh -x) all targets (%s=1)", EnvTrace)) + flagStderrKeep = flag.Bool("k", false, + fmt.Sprintf("keep job's stderr (%s=1)", EnvStderrKeep)) + flagStderrSilent = flag.Bool("s", false, + fmt.Sprintf("silent, do not print job's stderr (%s=1)", EnvStderrSilent)) +} + type RunErr struct { Tgt string DoFile string @@ -403,6 +420,8 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { FdStatus.Write([]byte{StatusRun}) } + var finished time.Time + var exitErr *exec.ExitError started := time.Now() runErr.Started = &started fdStdout, err = os.OpenFile(stdoutPath, os.O_RDWR, os.FileMode(0666)) @@ -421,15 +440,86 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { cmd.ExtraFiles = append(cmd.ExtraFiles, fdDep) cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvDepFd, 3+fdNum)) fdNum++ + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", EnvDepCwd, cwd)) defer func() { jsRelease(shCtx, jsToken) - lockRelease() fdDep.Close() fdStdout.Close() if fdStderr != nil { fdStderr.Close() + logRecPath := path.Join(redoDir, tgt+LogSuffix+DepSuffix) + if fdStderr, err = os.OpenFile( + logRecPath, + os.O_WRONLY|os.O_CREATE, + 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}, + } + ts := new(tai64n.TAI64N) + ts.FromTime(started) + fields = append(fields, + recfile.Field{Name: "Started", Value: tai64n.Encode(ts[:])}, + ) + ts.FromTime(finished) + fields = append(fields, + recfile.Field{Name: "Finished", Value: tai64n.Encode(ts[:])}) + fields = append(fields, recfile.Field{ + Name: "Duration", + Value: strconv.FormatInt(finished.Sub(started).Nanoseconds(), 10), + }) + fields = append(fields, recfile.Field{Name: "Cmd", Value: cmdName}) + for _, arg := range args { + fields = append(fields, recfile.Field{Name: "Cmd", Value: arg}) + } + for _, env := range cmd.Env { + fields = append(fields, recfile.Field{Name: "Env", Value: env}) + } + if exitErr != nil { + fields = append(fields, recfile.Field{ + Name: "ExitCode", + Value: strconv.Itoa(exitErr.ProcessState.ExitCode()), + }) + } + w := bufio.NewWriter(fdStderr) + + var depInfo *DepInfo + fdDep, err = os.Open(fdDep.Name()) + 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...) + 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() os.Remove(fdDep.Name()) os.Remove(fdStdout.Name()) os.Remove(tmpPath) @@ -488,9 +578,10 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { // Wait for job completion <-stderrTerm err = cmd.Wait() - finished := time.Now() + finished = time.Now() runErr.Finished = &finished if err != nil { + exitErr = err.(*exec.ExitError) runErr.Err = err errs <- runErr return