Files

84 lines
1.8 KiB
Go

package dbm
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
)
// FingerprintForGroups calculates a stable fingerprint for the provided file groups.
// It inspects the current file list managed by DBManager, collects their size and
// modification timestamp, and hashes the aggregated metadata. If none of the
// requested groups contain files, an empty string is returned without error.
func (d *DBManager) FingerprintForGroups(names ...string) (string, error) {
if len(names) == 0 {
return "", nil
}
type fileFingerprint struct {
group string
rel string
size int64
mod int64
}
entries := make([]fileFingerprint, 0)
for _, name := range names {
paths, err := d.GetDBPath(name)
if err != nil {
// When the underlying error indicates the files are simply missing,
// treat it as an empty group rather than a hard failure.
if strings.Contains(err.Error(), "db file not found") {
continue
}
return "", err
}
for _, p := range paths {
info, statErr := os.Stat(p)
if statErr != nil {
if os.IsNotExist(statErr) {
continue
}
return "", statErr
}
rel := p
if relPath, relErr := filepath.Rel(d.path, p); relErr == nil {
rel = relPath
}
rel = filepath.ToSlash(rel)
entries = append(entries, fileFingerprint{
group: name,
rel: rel,
size: info.Size(),
mod: info.ModTime().UnixNano(),
})
}
}
if len(entries) == 0 {
return "", nil
}
sort.Slice(entries, func(i, j int) bool {
if entries[i].group == entries[j].group {
return entries[i].rel < entries[j].rel
}
return entries[i].group < entries[j].group
})
hasher := sha256.New()
for _, e := range entries {
fmt.Fprintf(hasher, "%s|%s|%d|%d;", e.group, e.rel, e.size, e.mod)
}
return hex.EncodeToString(hasher.Sum(nil)), nil
}