From 3592fcb93da8d4dd38a1673440dc5f9fc36a7470 Mon Sep 17 00:00:00 2001 From: Alan Hamlett Date: Tue, 29 Oct 2024 19:06:48 +0100 Subject: [PATCH] Prevent crash when loading zoneinfo on Windows --- cmd/params/params.go | 14 ++++++++++-- cmd/params/params_internal_test.go | 34 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/cmd/params/params.go b/cmd/params/params.go index c9a971fc..e6627b97 100644 --- a/cmd/params/params.go +++ b/cmd/params/params.go @@ -225,7 +225,7 @@ func LoadAPIParams(v *viper.Viper) (API, error) { backoffAtStr := vipertools.GetString(v, "internal.backoff_at") if backoffAtStr != "" { - parsed, err := time.Parse(ini.DateFormat, backoffAtStr) + parsed, err := safeTimeParse(ini.DateFormat, backoffAtStr) // nolint:gocritic if err != nil { log.Warnf("failed to parse backoff_at: %s", err) @@ -666,7 +666,7 @@ func LoadOfflineParams(v *viper.Viper) Offline { lastSentAtStr := vipertools.GetString(v, "internal.heartbeats_last_sent_at") if lastSentAtStr != "" { - parsed, err := time.Parse(ini.DateFormat, lastSentAtStr) + parsed, err := safeTimeParse(ini.DateFormat, lastSentAtStr) // nolint:gocritic if err != nil { log.Warnf("failed to parse heartbeats_last_sent_at: %s", err) @@ -720,6 +720,16 @@ func LoadStatusBarParams(v *viper.Viper) (StatusBar, error) { }, nil } +func safeTimeParse(format string, s string) (parsed time.Time, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("time.Parse panic: %v", r) + } + }() + + return time.Parse(format, s) +} + func readAPIKeyFromCommand(cmdStr string) (string, error) { if cmdStr == "" { return "", nil diff --git a/cmd/params/params_internal_test.go b/cmd/params/params_internal_test.go index 5cc736b9..25b7866f 100644 --- a/cmd/params/params_internal_test.go +++ b/cmd/params/params_internal_test.go @@ -3,7 +3,9 @@ package params import ( "regexp" "testing" + "time" + "github.com/wakatime/wakatime-cli/pkg/ini" "github.com/wakatime/wakatime-cli/pkg/regex" "github.com/stretchr/testify/assert" @@ -59,3 +61,35 @@ func TestParseBoolOrRegexList(t *testing.T) { }) } } + +func TestSafeTimeParse(t *testing.T) { + parsed, err := safeTimeParse(ini.DateFormat, "2024-01-13T13:35:58Z") + require.NoError(t, err) + + assert.Equal(t, time.Date(2024, 1, 13, 13, 35, 58, 0, time.UTC), parsed) +} + +func TestSafeTimeParse_Err(t *testing.T) { + tests := map[string]struct { + Input string + Expected string + }{ + "empty string": { + Input: "", + Expected: `parsing time "" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "2006"`, + }, + "invalid time": { + Input: "invalid", + Expected: `parsing time "invalid" as "2006-01-02T15:04:05Z07:00": cannot parse "invalid" as "2006"`, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + parsed, err := safeTimeParse(ini.DateFormat, test.Input) + require.Equal(t, time.Time{}, parsed) + + assert.EqualError(t, err, test.Expected) + }) + } +}