From ff749457e392288e29dbf553bf8e0e64cc8b6401 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 14 Apr 2026 10:39:16 +0300 Subject: refactor: extract record line parser to internal/recordline (m3) Deduplicate parseRecordLine from goprecords and storage; shared recordline.Parse with Fields type. Tests live in recordline package; DB import path still covered by goprecords TestImportFromDir. Made-with: Cursor --- internal/recordline/recordline.go | 49 ++++++++++++++++++++ internal/recordline/recordline_test.go | 83 ++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 internal/recordline/recordline.go create mode 100644 internal/recordline/recordline_test.go (limited to 'internal/recordline') diff --git a/internal/recordline/recordline.go b/internal/recordline/recordline.go new file mode 100644 index 0000000..940f235 --- /dev/null +++ b/internal/recordline/recordline.go @@ -0,0 +1,49 @@ +package recordline + +import ( + "strconv" + "strings" +) + +type Fields struct { + Uptime uint64 + BootTime uint64 + OS string + KernelName string + KernelMajor string +} + +func Parse(line string) (Fields, bool) { + line = strings.TrimSpace(line) + if line == "" { + return Fields{}, false + } + parts := strings.SplitN(line, ":", 3) + if len(parts) != 3 { + return Fields{}, false + } + uptime, _ := strconv.ParseUint(parts[0], 10, 64) + bootTime, _ := strconv.ParseUint(parts[1], 10, 64) + osStr := parts[2] + kernelName := osStr + if i := strings.Index(osStr, " "); i > 0 { + kernelName = osStr[:i] + } + kernelMajor := kernelName + " " + rest := osStr + if i := strings.Index(osStr, " "); i >= 0 { + rest = osStr[i+1:] + } + if j := strings.Index(rest, "."); j >= 0 { + kernelMajor += rest[:j] + "..." + } else { + kernelMajor += rest + "..." + } + return Fields{ + Uptime: uptime, + BootTime: bootTime, + OS: osStr, + KernelName: kernelName, + KernelMajor: kernelMajor, + }, true +} diff --git a/internal/recordline/recordline_test.go b/internal/recordline/recordline_test.go new file mode 100644 index 0000000..4fcc152 --- /dev/null +++ b/internal/recordline/recordline_test.go @@ -0,0 +1,83 @@ +package recordline + +import ( + "testing" +) + +func TestParse(t *testing.T) { + tests := []struct { + in string + want Fields + ok bool + }{ + { + "12345:1700000000:Linux 6.5.0-generic", + Fields{ + Uptime: 12345, + BootTime: 1700000000, + OS: "Linux 6.5.0-generic", + KernelName: "Linux", + KernelMajor: "Linux 6...", + }, + true, + }, + { + " 99:100:FreeBSD 14.0-RELEASE ", + Fields{ + Uptime: 99, + BootTime: 100, + OS: "FreeBSD 14.0-RELEASE", + KernelName: "FreeBSD", + KernelMajor: "FreeBSD 14...", + }, + true, + }, + { + "500:200:SingleToken", + Fields{ + Uptime: 500, + BootTime: 200, + OS: "SingleToken", + KernelName: "SingleToken", + KernelMajor: "SingleToken SingleToken...", + }, + true, + }, + { + "100:200:Linux 6.5.0:extra", + Fields{ + Uptime: 100, + BootTime: 200, + OS: "Linux 6.5.0:extra", + KernelName: "Linux", + KernelMajor: "Linux 6...", + }, + true, + }, + { + "abc:def:Linux 6.5.0", + Fields{ + Uptime: 0, + BootTime: 0, + OS: "Linux 6.5.0", + KernelName: "Linux", + KernelMajor: "Linux 6...", + }, + true, + }, + {"", Fields{}, false}, + {" ", Fields{}, false}, + {"only:two", Fields{}, false}, + {"no-colons-at-all", Fields{}, false}, + } + for _, tt := range tests { + got, ok := Parse(tt.in) + if ok != tt.ok { + t.Errorf("Parse(%q) ok=%v, want %v", tt.in, ok, tt.ok) + continue + } + if tt.ok && got != tt.want { + t.Errorf("Parse(%q) = %+v, want %+v", tt.in, got, tt.want) + } + } +} -- cgit v1.2.3