X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=run.go;h=af71b3b8b3b4c4b08d39082e295d2fa48316ed62;hb=314f58ec690c7321535d6718e8d3a0ecb4cac019;hp=d8e439de5b0dcaabf7f38d76c0cf8f8529d9c279;hpb=5fca30b6ac4e7a59f8e271a34ee2c441daf1959c;p=goredo.git diff --git a/run.go b/run.go index d8e439d..af71b3b 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 @@ -51,7 +51,7 @@ const ( RedoDir = ".redo" LockSuffix = ".lock" - DepSuffix = ".dep" + DepSuffix = ".rec" TmpPrefix = ".redo." LogSuffix = ".log" ) @@ -101,24 +101,24 @@ func mkdirs(pth string) error { return os.MkdirAll(pth, os.FileMode(0777)) } -func isModified(cwd, redoDir, tgt string) (bool, string, error) { +func isModified(cwd, redoDir, tgt string) (bool, *Inode, error) { fdDep, err := os.Open(path.Join(redoDir, tgt+DepSuffix)) if err != nil { if os.IsNotExist(err) { - return false, "", nil + return false, nil, nil } - return false, "", err + return false, nil, err } defer fdDep.Close() r := recfile.NewReader(fdDep) - var ourTs string + var ourInode *Inode for { m, err := r.NextMap() if err != nil { if err == io.EOF { break } - return false, "", err + return false, nil, err } if m["Target"] != tgt { continue @@ -126,21 +126,25 @@ func isModified(cwd, redoDir, tgt string) (bool, string, error) { fd, err := os.Open(path.Join(cwd, tgt)) if err != nil { if os.IsNotExist(err) { - return false, "", nil + return false, nil, nil } - return false, "", err + return false, nil, err } - defer fd.Close() - ourTs, err = fileCtime(fd) + ourInode, err = inodeFromFile(fd) + fd.Close() if err != nil { - return false, "", err + return false, nil, err } - if ourTs != m["Ctime"] { - return true, ourTs, nil + theirInode, err := inodeFromRec(m) + if err != nil { + return false, nil, err + } + if !ourInode.Equals(theirInode) { + return true, ourInode, nil } break } - return false, ourTs, nil + return false, ourInode, nil } func syncDir(dir string) error { @@ -200,7 +204,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 } @@ -222,7 +226,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { } // Check if target is not modified externally - modified, tsPrev, err := isModified(cwd, redoDir, tgt) + modified, inodePrev, err := isModified(cwd, redoDir, tgt) if err != nil { lockRelease() return TgtErr{tgtOrig, err} @@ -236,12 +240,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() @@ -288,6 +293,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 @@ -312,7 +318,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) @@ -326,7 +334,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)) @@ -338,8 +345,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 { @@ -363,10 +373,6 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { } // Preparing stderr - stderr, err := cmd.StderrPipe() - if err != nil { - panic(err) - } var fdStderr *os.File if StderrKeep { fdStderr, err = os.OpenFile( @@ -392,6 +398,26 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { 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++ + defer func() { jsRelease(shCtx) lockRelease() @@ -409,9 +435,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 @@ -462,14 +493,13 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { } // Was $1 touched? - if tsPrev != "" { + if inodePrev != nil { if fd, err := os.Open(path.Join(cwdOrig, tgt)); err == nil { - ts, err := fileCtime(fd) + inode, err := inodeFromFile(fd) fd.Close() - if err == nil && ts != tsPrev { + if err == nil && !inode.Equals(inodePrev) { runErr.Err = errors.New("$1 was explicitly touched") errs <- runErr - fd.Close() return } } @@ -539,7 +569,7 @@ func runScript(tgtOrig string, errs chan error, traced bool) error { } } - // Commit .dep + // Commit .rec if !NoSync { err = fdDep.Sync() if err != nil {