import (
"bufio"
+ "bytes"
"crypto/rand"
"encoding/hex"
"errors"
"flag"
"fmt"
"io"
+ "io/fs"
"log"
"os"
"os/exec"
return os.MkdirAll(pth, os.FileMode(0777))
}
-func isModified(cwd, redoDir, tgt string) (bool, *Inode, string, error) {
- fdDep, err := os.Open(path.Join(redoDir, tgt+DepSuffix))
- if err != nil {
- if os.IsNotExist(err) {
- return false, nil, "", nil
- }
- return false, nil, "", ErrLine(err)
+func isModified(depInfo *DepInfo, cwd, tgt string) (
+ modified bool, ourInode *Inode, hshPrev []byte, err error,
+) {
+ if depInfo == nil {
+ return
}
- defer fdDep.Close()
- r := recfile.NewReader(fdDep)
- var modified bool
- var ourInode *Inode
- var hshPrev string
- for {
- m, err := r.NextMap()
- if err != nil {
- if errors.Is(err, io.EOF) {
- break
- }
- return false, nil, "", ErrLine(err)
- }
- if m["Type"] != DepTypeIfchange || m["Target"] != tgt {
+ for _, dep := range depInfo.ifchanges {
+ if dep.tgt != tgt {
continue
}
ourInode, err = inodeFromFileByPath(path.Join(cwd, tgt))
if err != nil {
if os.IsNotExist(err) {
- return false, nil, "", nil
+ err = nil
+ return
}
- return false, nil, "", ErrLine(err)
- }
- theirInode, err := inodeFromRec(m)
- if err != nil {
- return false, nil, "", ErrLine(err)
+ err = ErrLine(err)
+ return
}
- hshPrev = m["Hash"]
- modified = !ourInode.Equals(theirInode)
+ hshPrev = dep.hash
+ modified = !ourInode.Equals(dep.inode)
break
}
- return modified, ourInode, hshPrev, nil
+ return
}
func syncDir(dir string) error {
return nil
}
- // Check if it was already built in parallel
- if !forced {
- if build, err := depReadBuild(path.Join(redoDir, tgt+DepSuffix)); err == nil && build == BuildUUID {
+ depInfo, err := depRead(path.Join(redoDir, tgt+DepSuffix))
+ if err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ err = nil
+ } else {
lockRelease()
- errs <- nil
- return nil
+ return TgtError{tgtOrig, err}
}
}
+ // Check if it was already built in parallel
+ if !forced && depInfo != nil && depInfo.build == BuildUUID {
+ lockRelease()
+ errs <- nil
+ return nil
+ }
+
// Check if target is not modified externally
- modified, inodePrev, hshPrev, err := isModified(cwd, redoDir, tgt)
+ modified, inodePrev, hshPrev, err := isModified(depInfo, cwd, tgt)
if err != nil {
lockRelease()
return TgtError{tgtOrig, err}
}()
return nil
}
+ depInfo = nil
// Start preparing .rec
fdDep, err := tempfile(redoDir, tgt+DepSuffix)
runErr.DoFile = doFileRelPath
}
- if err = depWrite(fdDep, cwdOrig, doFileRelPath, ""); err != nil {
+ if err = depWrite(fdDep, cwdOrig, doFileRelPath, nil); err != nil {
cleanup()
return TgtError{tgtOrig, ErrLine(err)}
}
}
w := bufio.NewWriter(fdStderr)
- var depInfo *DepInfo
- fdDep, err := os.Open(fdDepPath)
- if err != nil {
- err = ErrLine(err)
- goto Err
- }
- depInfo, err = depRead(fdDep)
- fdDep.Close()
+ depInfo, err := depRead(fdDepPath)
if err != nil {
err = ErrLine(err)
goto Err
for _, dep := range depInfo.ifchanges {
fields = append(fields, recfile.Field{
Name: "Ifchange",
- Value: dep["Target"],
+ Value: dep.tgt,
})
}
_, err = recfile.NewWriter(w).WriteFields(fields...)
goto Finish
}
} else {
- var hsh string
- if hshPrev != "" {
+ var hsh []byte
+ if hshPrev != nil {
_, err = fd.Seek(0, io.SeekStart)
if err != nil {
err = ErrLine(err)
err = ErrLine(err)
goto Finish
}
- if hsh == hshPrev {
+ if bytes.Equal(hsh, hshPrev) {
tracef(CDebug, "%s has same hash, not renaming", tgtOrig)
err = ErrLine(os.Remove(fd.Name()))
if err != nil {
goto Finish
}
}
- err = ErrLine(depWrite(fdDep, cwdOrig, tgt, hshPrev))
+ err = ErrLine(depWrite(fdDep, cwdOrig, tgt, hsh))
if err != nil {
goto Finish
}
goto Finish
}
}
+ fdDep.Close()
// Post-commit .rec sanitizing
- fdDep.Close()
- if fdDepR, err := os.Open(fdDepPath); err == nil {
- depInfo, err := depRead(fdDepR)
- fdDepR.Close()
- if err != nil {
- err = ErrLine(err)
- goto Finish
- }
+ if depInfo, err := depRead(fdDepPath); err == nil {
ifchangeSeen := make(map[string]struct{}, len(depInfo.ifchanges))
for _, dep := range depInfo.ifchanges {
- ifchangeSeen[dep["Target"]] = struct{}{}
+ ifchangeSeen[dep.tgt] = struct{}{}
}
for _, dep := range depInfo.ifcreates {
if _, exists := ifchangeSeen[dep]; exists {
tracef(CWarn, "simultaneous ifcreate and ifchange records: %s", tgt)
}
}
+ } else if errors.Is(err, fs.ErrNotExist) {
+ err = nil
+ } else {
+ err = ErrLine(err)
+ goto Finish
}
Finish: