return hex.EncodeToString(h.Sum(nil)), nil
}
-func depWrite(fdDep *os.File, cwd, tgt string) error {
+func depWrite(fdDep *os.File, cwd, tgt, hsh string) error {
tracef(CDebug, "ifchange: %s <- %s", fdDep.Name(), tgt)
fd, err := os.Open(path.Join(cwd, tgt))
if err != nil {
if err != nil {
return err
}
- hsh, err := fileHash(fd)
- if err != nil {
- return err
+ if hsh == "" {
+ hsh, err = fileHash(fd)
+ if err != nil {
+ return err
+ }
}
fields := []recfile.Field{
{Name: "Type", Value: DepTypeIfchange},
panic(err)
}
if _, errStat := os.Stat(tgt); errStat == nil {
- err = depWrite(fdDep, tgtDir, tgtRel)
+ err = depWrite(fdDep, tgtDir, tgtRel, "")
} else {
tracef(CDebug, "ifchange: %s <- %s (non-existing)", fdDep.Name(), tgtRel)
fields := []recfile.Field{
return os.MkdirAll(pth, os.FileMode(0777))
}
-func isModified(cwd, redoDir, tgt string) (bool, *Inode, error) {
+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, "", nil
}
- return false, nil, err
+ return false, nil, "", err
}
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, err
+ return false, nil, "", err
}
if m["Type"] != DepTypeIfchange || m["Target"] != tgt {
continue
fd, err := os.Open(path.Join(cwd, tgt))
if err != nil {
if os.IsNotExist(err) {
- return false, nil, nil
+ return false, nil, "", nil
}
- return false, nil, err
+ return false, nil, "", err
}
ourInode, err = inodeFromFile(fd)
fd.Close()
if err != nil {
- return false, nil, err
+ return false, nil, "", err
}
theirInode, err := inodeFromRec(m)
if err != nil {
- return false, nil, err
- }
- if !ourInode.Equals(theirInode) {
- return true, ourInode, nil
+ return false, nil, "", err
}
+ hshPrev = m["Hash"]
+ modified = !ourInode.Equals(theirInode)
break
}
- return false, ourInode, nil
+ return modified, ourInode, hshPrev, nil
}
func syncDir(dir string) error {
}
// Check if target is not modified externally
- modified, inodePrev, err := isModified(cwd, redoDir, tgt)
+ modified, inodePrev, hshPrev, err := isModified(cwd, redoDir, tgt)
if err != nil {
lockRelease()
return TgtError{tgtOrig, err}
runErr.DoFile = doFileRelPath
}
- if err = depWrite(fdDep, cwdOrig, doFileRelPath); err != nil {
+ if err = depWrite(fdDep, cwdOrig, doFileRelPath, ""); err != nil {
cleanup()
return TgtError{tgtOrig, err}
}
goto Finish
}
} else {
+ var hsh string
+ if hshPrev != "" {
+ _, err = fd.Seek(0, io.SeekStart)
+ if err != nil {
+ goto Finish
+ }
+ hsh, err = fileHash(fd)
+ if err != nil {
+ goto Finish
+ }
+ if hsh == hshPrev {
+ tracef(CDebug, "%s has same hash, not renaming", tgtOrig)
+ err = os.Remove(fd.Name())
+ if err != nil {
+ goto Finish
+ }
+ err = os.Chtimes(path.Join(cwdOrig, tgt), finished, finished)
+ if err != nil {
+ goto Finish
+ }
+ if !NoSync {
+ err = syncDir(cwdOrig)
+ if err != nil {
+ goto Finish
+ }
+ }
+ err = depWrite(fdDep, cwdOrig, tgt, hshPrev)
+ if err != nil {
+ goto Finish
+ }
+ goto RecCommit
+ }
+ }
if !NoSync {
err = fd.Sync()
if err != nil {
goto Finish
}
}
- err = depWrite(fdDep, cwdOrig, tgt)
+ err = depWrite(fdDep, cwdOrig, tgt, hsh)
if err != nil {
goto Finish
}
}
+ RecCommit:
// Commit .rec
if !NoSync {
err = fdDep.Sync()