Clean up code reuse, consistency, and efficiency issues

Merge readExistingSerial and readExistingContent into a single
readExisting function to eliminate duplicate file I/O. Extract dateBase
helper to deduplicate serial formula between defaultSerial and
bumpSerial. Cache hash results during collision check to avoid
recomputing per member. Normalize error prefixes (remove "error:" from
fmt.Errorf, add uniformly at print sites). Use filepath.Join instead of
manual "/" concatenation. Replace trivial containsStr wrapper with
strings.Contains. Simplify tokenize to a single return. Use writeTestFile
and fixedTime helpers consistently in tests.
This commit is contained in:
2026-03-01 17:38:26 -08:00
parent 1f2f39f40c
commit 0a460b975d
7 changed files with 75 additions and 117 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"hash/fnv"
"os"
"path/filepath"
"sort"
"strings"
"time"
@@ -29,12 +30,13 @@ func hashZoneName(zone string) string {
h := fnv.New32a()
h.Write([]byte(zone))
sum := h.Sum32()
b := make([]byte, 4)
b[0] = byte(sum >> 24)
b[1] = byte(sum >> 16)
b[2] = byte(sum >> 8)
b[3] = byte(sum)
return b32.EncodeToString(b)
b := [4]byte{
byte(sum >> 24),
byte(sum >> 16),
byte(sum >> 8),
byte(sum),
}
return b32.EncodeToString(b[:])
}
// generateCatalogZone builds the zone file content for a single catalog.
@@ -76,20 +78,22 @@ func generateCatalogZone(catName string, cfg *Config, members []ZoneEntry, seria
return sorted[i].Zone < sorted[j].Zone
})
// Check for hash collisions
hashToZone := make(map[string]string)
// Check for hash collisions and cache results
hashToZone := make(map[string]string, len(sorted))
zoneHash := make(map[string]string, len(sorted))
for _, entry := range sorted {
h := hashZoneName(entry.Zone)
if existing, ok := hashToZone[h]; ok && existing != entry.Zone {
return "", fmt.Errorf("error: %s:%d: hash collision between %s and %s in catalog %q",
return "", fmt.Errorf("%s:%d: hash collision between %s and %s in catalog %q",
entry.File, entry.Line, existing, entry.Zone, catName)
}
hashToZone[h] = entry.Zone
zoneHash[entry.Zone] = h
}
// Member records
for _, entry := range sorted {
h := hashZoneName(entry.Zone)
h := zoneHash[entry.Zone]
// PTR record
ptrOwner := fmt.Sprintf("%s.zones.%s", h, origin)
@@ -126,58 +130,48 @@ func generateCatalogZone(catName string, cfg *Config, members []ZoneEntry, seria
return strings.Join(records, "\n") + "\n", nil
}
// readExistingSerial reads an existing zone file and extracts the SOA serial.
// Returns 0, nil if the file doesn't exist.
func readExistingSerial(path string) (uint32, error) {
f, err := os.Open(path)
// readExisting reads an existing zone file and returns its content and SOA serial.
// Returns ("", 0, nil) if the file doesn't exist.
func readExisting(path string) (string, uint32, error) {
data, err := os.ReadFile(path)
if os.IsNotExist(err) {
return 0, nil
return "", 0, nil
}
if err != nil {
return 0, fmt.Errorf("reading existing zone %s: %w", path, err)
return "", 0, fmt.Errorf("reading existing zone %s: %w", path, err)
}
defer f.Close()
content := string(data)
zp := dns.NewZoneParser(f, "", path)
zp := dns.NewZoneParser(strings.NewReader(content), "", path)
for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
if soa, ok := rr.(*dns.SOA); ok {
return soa.Serial, nil
return content, soa.Serial, nil
}
}
if err := zp.Err(); err != nil {
return 0, fmt.Errorf("parsing existing zone %s: %w", path, err)
return "", 0, fmt.Errorf("parsing existing zone %s: %w", path, err)
}
return 0, nil
return content, 0, nil
}
// readExistingContent reads the full content of an existing zone file.
// Returns empty string if file doesn't exist.
func readExistingContent(path string) (string, error) {
data, err := os.ReadFile(path)
if os.IsNotExist(err) {
return "", nil
}
if err != nil {
return "", err
}
return string(data), nil
// dateBase returns the YYYYMMDD00 serial base for the given time.
func dateBase(now time.Time) uint32 {
return uint32(now.Year())*1000000 +
uint32(now.Month())*10000 +
uint32(now.Day())*100
}
// defaultSerial returns a serial for today with sequence 01: YYYYMMDD01.
func defaultSerial(now time.Time) uint32 {
return uint32(now.Year())*1000000 +
uint32(now.Month())*10000 +
uint32(now.Day())*100 + 1
return dateBase(now) + 1
}
// bumpSerial increments a serial. If same date, bumps the sequence number.
// If different date, starts at YYYYMMDD01.
// Returns error if sequence reaches 99 and needs another bump.
func bumpSerial(old uint32, now time.Time) (uint32, error) {
todayBase := uint32(now.Year())*1000000 +
uint32(now.Month())*10000 +
uint32(now.Day())*100
todayBase := dateBase(now)
if old >= todayBase && old < todayBase+100 {
// Same date, bump sequence
@@ -196,10 +190,10 @@ func bumpSerial(old uint32, now time.Time) (uint32, error) {
// Returns true if the file was written (changed), false if unchanged.
func processCatalog(catName string, cfg *Config, members []ZoneEntry, outputDir string, now time.Time) (bool, error) {
catCfg := cfg.Catalogs[catName]
outputPath := outputDir + "/" + catCfg.Zone + "zone"
outputPath := filepath.Join(outputDir, catCfg.Zone+"zone")
// Read existing serial
oldSerial, err := readExistingSerial(outputPath)
// Read existing file (content + serial in one pass)
existing, oldSerial, err := readExisting(outputPath)
if err != nil {
return false, err
}
@@ -217,11 +211,6 @@ func processCatalog(catName string, cfg *Config, members []ZoneEntry, outputDir
}
// Compare with existing file
existing, err := readExistingContent(outputPath)
if err != nil {
return false, err
}
if content == existing {
return false, nil
}