]> Cypherpunks.ru repositories - goredo.git/blobdiff - run.go
Trace only non-dependant targets
[goredo.git] / run.go
diff --git a/run.go b/run.go
index fab67374eb24cb9bb14793cea1622d090098303a..bb455e845df4b20abc91be0a10c584367b43a301 100644 (file)
--- 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
+}