- 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>
59 lines
1.3 KiB
Go
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
|
|
}
|