homelab/services/ha-sync/internal/sync/compare.go
Dan V deb6c38d7b chore: commit homelab setup — deployment, services, orchestration, skill
- Add .gitignore: exclude compiled binaries, build artifacts, and Helm
  values files containing real secrets (authentik, prometheus)
- Add all Kubernetes deployment manifests (deployment/)
- Add services source code: ha-sync, device-inventory, games-console,
  paperclip, parts-inventory
- Add Ansible orchestration: playbooks, roles, inventory, cloud-init
- Add hardware specs, execution plans, scripts, HOMELAB.md
- Add skills/homelab/SKILL.md + skills/install.sh to preserve Copilot skill
- Remove previously-tracked inventory-cli binary from git index

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 08:10:32 +02:00

59 lines
1.3 KiB
Go

package sync
import (
"crypto/md5"
"encoding/hex"
"io"
"os"
"time"
)
// NeedsSync returns true when src should be copied to dest.
//
// Decision logic:
// - sizes differ → true (fast path)
// - src is newer than dest by more than threshold → true
// - sizes equal and mtime within threshold → delegate to MD5Changed
func NeedsSync(src, dest FileInfo, threshold time.Duration) bool {
if src.Size != dest.Size {
return true
}
diff := src.ModTime.Sub(dest.ModTime)
if diff < 0 {
diff = -diff
}
if diff > threshold {
return src.ModTime.After(dest.ModTime)
}
return MD5Changed(src.AbsPath, dest.AbsPath)
}
// MD5File computes the MD5 digest of the file at path using a streaming read.
// Returns the digest as a lowercase hex string.
func MD5File(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close()
h := md5.New()
if _, err := io.Copy(h, f); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}
// MD5Changed returns true when the two files have different MD5 hashes.
// Any IO error is treated as "changed" so the file will be re-copied.
func MD5Changed(srcPath, destPath string) bool {
srcHash, err := MD5File(srcPath)
if err != nil {
return true
}
destHash, err := MD5File(destPath)
if err != nil {
return true
}
return srcHash != destHash
}