X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=run.go;h=57401ce627a54c83d6bfac2320c00a1ccc06a655;hb=a1394bc35f4473f55d6e56afa720c490d3e7f6bd;hp=1dc937dedb6313a469420fafe6137194ebda262e;hpb=ebd96d2c56c742d9d00bccb9faee5fc1a7db664a;p=goredo.git diff --git a/run.go b/run.go index 1dc937d..57401ce 100644 --- a/run.go +++ b/run.go @@ -1,5 +1,5 @@ /* -goredo -- redo implementation on pure Go +goredo -- djb's redo implementation on pure Go Copyright (C) 2020-2021 Sergey Matveev This program is free software: you can redistribute it and/or modify @@ -35,13 +35,14 @@ import ( "time" "go.cypherpunks.ru/recfile" - "go.cypherpunks.ru/tai64n" + "go.cypherpunks.ru/tai64n/v2" "golang.org/x/sys/unix" ) const ( EnvDepFd = "REDO_DEP_FD" EnvDirPrefix = "REDO_DIRPREFIX" + EnvDepCwd = "REDO_DEP_CWD" EnvBuildUUID = "REDO_BUILD_UUID" EnvStderrPrefix = "REDO_STDERR_PREFIX" EnvTrace = "REDO_TRACE" @@ -51,7 +52,7 @@ const ( RedoDir = ".redo" LockSuffix = ".lock" - DepSuffix = ".dep" + DepSuffix = ".rec" TmpPrefix = ".redo." LogSuffix = ".log" ) @@ -67,6 +68,8 @@ var ( 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)) + + TracedAll bool ) type RunErr struct { @@ -87,7 +90,7 @@ func (e *RunErr) Name() string { if e.Finished == nil { return name } - return fmt.Sprintf("%s (%fsec)", name, e.Finished.Sub(*e.Started).Seconds()) + return fmt.Sprintf("%s (%.3fs)", name, e.Finished.Sub(*e.Started).Seconds()) } func (e RunErr) Error() string { @@ -204,7 +207,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { fdDep, err := os.Open(path.Join(redoDir, tgt+DepSuffix)) if err != nil { if os.IsNotExist(err) { - err = errors.New("was not built: no .dep") + err = errors.New("was not built: no .rec") } goto Finish } @@ -240,12 +243,13 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { return nil } - // Start preparing .dep + // Start preparing .rec fdDep, err := tempfile(redoDir, tgt+DepSuffix) if err != nil { lockRelease() return TgtErr{tgtOrig, err} } + fdDepPath := fdDep.Name() cleanup := func() { lockRelease() fdDep.Close() @@ -292,6 +296,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { cleanup() return TgtErr{tgtOrig, err} } + fdDep.Close() trace(CWait, "%s", runErr.Name()) // Prepare command line @@ -302,7 +307,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { args = make([]string, 0, 3) } else { cmdName = "/bin/sh" - if traced { + if traced || TracedAll { args = append(args, "-ex") } else { args = append(args, "-e") @@ -316,7 +321,9 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { cleanup() return TgtErr{tgtOrig, err} } - tmpPath := fdStdout.Name() + ".3" // and for $3 + stdoutPath := fdStdout.Name() + fdStdout.Close() + tmpPath := stdoutPath + ".3" // and for $3 tmpPathRel, err := filepath.Rel(cwd, tmpPath) if err != nil { panic(err) @@ -330,7 +337,6 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { cmd := exec.Command(cmdName, args...) cmd.Dir = cwd - cmd.Stdout = fdStdout // cmd.Stdin reads from /dev/null by default cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%d", EnvLevel, Level+1)) cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", EnvDirPrefix, dirPrefix)) @@ -342,8 +348,11 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { )) fdNum := 0 - cmd.ExtraFiles = append(cmd.ExtraFiles, fdDep) - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvDepFd, 3+fdNum)) + cmd.ExtraFiles = append(cmd.ExtraFiles, FdOODTgts) + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvOODTgtsFd, 3+fdNum)) + fdNum++ + cmd.ExtraFiles = append(cmd.ExtraFiles, FdOODTgtsLock) + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvOODTgtsLockFd, 3+fdNum)) fdNum++ if FdStatus == nil { @@ -354,23 +363,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { fdNum++ } - if JSR == nil { - // infinite jobs - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=NO", EnvJSFd)) - } 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, - )) - fdNum += 2 - } - // Preparing stderr - stderr, err := cmd.StderrPipe() - if err != nil { - panic(err) - } var fdStderr *os.File if StderrKeep { fdStderr, err = os.OpenFile( @@ -392,12 +385,47 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { Jobs.Add(1) go func() { - jsAcquire(shCtx) + jsToken := jsAcquire(shCtx) + if JSR == nil { + // infinite jobs + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=NO", EnvJobs)) + } 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, + )) + fdNum += 2 + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvJSToken, jsToken)) + } + if FdStatus != nil { FdStatus.Write([]byte{StatusRun}) } + + started := time.Now() + runErr.Started = &started + fdStdout, err = os.OpenFile(stdoutPath, os.O_RDWR, os.FileMode(0666)) + if err != nil { + runErr.Err = err + errs <- runErr + return + } + cmd.Stdout = fdStdout + fdDep, err = os.OpenFile(fdDepPath, os.O_WRONLY|os.O_APPEND, os.FileMode(0666)) + if err != nil { + runErr.Err = err + errs <- runErr + return + } + 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) + jsRelease(shCtx, jsToken) lockRelease() fdDep.Close() fdStdout.Close() @@ -413,9 +441,14 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { } Jobs.Done() }() - started := time.Now() - runErr.Started = &started - err := cmd.Start() + stderr, err := cmd.StderrPipe() + if err != nil { + runErr.Err = err + errs <- runErr + return + } + started = time.Now() + err = cmd.Start() if err != nil { runErr.Err = err errs <- runErr @@ -437,9 +470,9 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { continue } if fdStderr != nil { - tai64n.FromTime(time.Now(), ts) + ts.FromTime(time.Now()) LogMutex.Lock() - fmt.Fprintf(fdStderr, "%s %s\n", ts.Encode(), line) + fmt.Fprintln(fdStderr, tai64n.Encode(ts[:]), line) LogMutex.Unlock() } if StderrSilent { @@ -473,7 +506,6 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { if err == nil && !inode.Equals(inodePrev) { runErr.Err = errors.New("$1 was explicitly touched") errs <- runErr - fd.Close() return } } @@ -543,7 +575,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { } } - // Commit .dep + // Commit .rec if !NoSync { err = fdDep.Sync() if err != nil {