diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-14 10:39:16 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-14 10:39:16 +0300 |
| commit | ff749457e392288e29dbf553bf8e0e64cc8b6401 (patch) | |
| tree | 4d43b1de40007ebcc880bd596114e097a30cc590 /internal | |
| parent | b0ac28f90ddf85e85b0308229569292fd6f7f9a2 (diff) | |
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
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/goprecords/aggregate.go | 6 | ||||
| -rw-r--r-- | internal/goprecords/parse_test.go | 78 | ||||
| -rw-r--r-- | internal/goprecords/types.go | 44 | ||||
| -rw-r--r-- | internal/recordline/recordline.go | 49 | ||||
| -rw-r--r-- | internal/recordline/recordline_test.go | 83 | ||||
| -rw-r--r-- | internal/storage/db.go | 47 |
6 files changed, 138 insertions, 169 deletions
diff --git a/internal/goprecords/aggregate.go b/internal/goprecords/aggregate.go index c143426..cefb545 100644 --- a/internal/goprecords/aggregate.go +++ b/internal/goprecords/aggregate.go @@ -7,6 +7,8 @@ import ( "os" "path/filepath" "strings" + + "codeberg.org/snonux/goprecords/internal/recordline" ) // Aggregates holds all category maps. Host uses HostAggregate; others use Aggregate. @@ -81,7 +83,7 @@ func processRecordsFile(ctx context.Context, path, host string, out *Aggregates) return ctx.Err() default: } - rec, ok := parseRecordLine(sc.Text()) + rec, ok := recordline.Parse(sc.Text()) if !ok { continue } @@ -111,7 +113,7 @@ func lastKernelFromFile(ctx context.Context, path string) (string, error) { return "", ctx.Err() default: } - rec, ok := parseRecordLine(sc.Text()) + rec, ok := recordline.Parse(sc.Text()) if !ok { continue } diff --git a/internal/goprecords/parse_test.go b/internal/goprecords/parse_test.go index ce63e7a..a38012e 100644 --- a/internal/goprecords/parse_test.go +++ b/internal/goprecords/parse_test.go @@ -51,84 +51,6 @@ func TestParseMetric(t *testing.T) { } } -func TestParseRecordLine(t *testing.T) { - tests := []struct { - in string - want recordLine - ok bool - }{ - { - "12345:1700000000:Linux 6.5.0-generic", - recordLine{ - Uptime: 12345, - BootTime: 1700000000, - OS: "Linux 6.5.0-generic", - KernelName: "Linux", - KernelMajor: "Linux 6...", - }, - true, - }, - { - " 99:100:FreeBSD 14.0-RELEASE ", - recordLine{ - Uptime: 99, - BootTime: 100, - OS: "FreeBSD 14.0-RELEASE", - KernelName: "FreeBSD", - KernelMajor: "FreeBSD 14...", - }, - true, - }, - { - "500:200:SingleToken", - recordLine{ - Uptime: 500, - BootTime: 200, - OS: "SingleToken", - KernelName: "SingleToken", - KernelMajor: "SingleToken SingleToken...", - }, - true, - }, - { - "100:200:Linux 6.5.0:extra", - recordLine{ - Uptime: 100, - BootTime: 200, - OS: "Linux 6.5.0:extra", - KernelName: "Linux", - KernelMajor: "Linux 6...", - }, - true, - }, - { - "abc:def:Linux 6.5.0", - recordLine{ - Uptime: 0, - BootTime: 0, - OS: "Linux 6.5.0", - KernelName: "Linux", - KernelMajor: "Linux 6...", - }, - true, - }, - {"", recordLine{}, false}, - {" ", recordLine{}, false}, - {"only:two", recordLine{}, false}, - {"no-colons-at-all", recordLine{}, false}, - } - for _, tt := range tests { - got, ok := parseRecordLine(tt.in) - if ok != tt.ok { - t.Errorf("parseRecordLine(%q) ok=%v, want %v", tt.in, ok, tt.ok) - continue - } - if tt.ok && got != tt.want { - t.Errorf("parseRecordLine(%q) = %+v, want %+v", tt.in, got, tt.want) - } - } -} - func TestParseOutputFormat(t *testing.T) { tests := []struct { in string diff --git a/internal/goprecords/types.go b/internal/goprecords/types.go index 84e7f4f..6e5bf10 100644 --- a/internal/goprecords/types.go +++ b/internal/goprecords/types.go @@ -76,15 +76,6 @@ func NewHostAggregate(name, lastKernel string) *HostAggregate { } } -// recordLine holds the parsed fields from a single uptimed record line. -type recordLine struct { - Uptime uint64 - BootTime uint64 - OS string - KernelName string - KernelMajor string -} - // tableRow is one row in the report table. type tableRow struct { Pos string @@ -264,41 +255,6 @@ func ParseOutputFormat(s string) (OutputFormat, error) { } } -func parseRecordLine(line string) (recordLine, bool) { - line = strings.TrimSpace(line) - if line == "" { - return recordLine{}, false - } - parts := strings.SplitN(line, ":", 3) - if len(parts) != 3 { - return recordLine{}, 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 recordLine{ - Uptime: uptime, - BootTime: bootTime, - OS: osStr, - KernelName: kernelName, - KernelMajor: kernelMajor, - }, true -} - func wordWrap(s string, lineLimit int) string { if lineLimit <= 0 || len(s) <= lineLimit { return s 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) + } + } +} diff --git a/internal/storage/db.go b/internal/storage/db.go index ea9d764..14d7050 100644 --- a/internal/storage/db.go +++ b/internal/storage/db.go @@ -7,9 +7,9 @@ import ( "fmt" "os" "path/filepath" - "strconv" "strings" + "codeberg.org/snonux/goprecords/internal/recordline" _ "modernc.org/sqlite" ) @@ -128,14 +128,6 @@ func LoadRecords(ctx context.Context, db *sql.DB) ([]Record, error) { return out, nil } -type recordLine struct { - Uptime uint64 - BootTime uint64 - OS string - KernelName string - KernelMajor string -} - func importFile(ctx context.Context, insert *sql.Stmt, path, host string) error { f, err := os.Open(path) if err != nil { @@ -149,7 +141,7 @@ func importFile(ctx context.Context, insert *sql.Stmt, path, host string) error return ctx.Err() default: } - rec, ok := parseRecordLine(sc.Text()) + rec, ok := recordline.Parse(sc.Text()) if !ok { continue } @@ -162,38 +154,3 @@ func importFile(ctx context.Context, insert *sql.Stmt, path, host string) error } return nil } - -func parseRecordLine(line string) (recordLine, bool) { - line = strings.TrimSpace(line) - if line == "" { - return recordLine{}, false - } - parts := strings.SplitN(line, ":", 3) - if len(parts) != 3 { - return recordLine{}, 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 recordLine{ - Uptime: uptime, - BootTime: bootTime, - OS: osStr, - KernelName: kernelName, - KernelMajor: kernelMajor, - }, true -} |
