From dc19fa3a179f8ec7c2d401dc479d86d783b23111 Mon Sep 17 00:00:00 2001 From: David Dworken Date: Tue, 10 Oct 2023 07:44:15 -0700 Subject: [PATCH] Roll-forward "Make history entry start times more precise (down to the nanosecond) to make the recorded runtime more accurate, since currently start times are rounded to the nearest second. Though note that 'date' on MacOS doesn't support %N, so this doesn't apply to MacOS" This reverts commit 6281ae0601960a46c0d0ed9e52e3119f14141a6e. --- client/cmd/saveHistoryEntry.go | 23 ++++++++++++----------- client/cmd/saveHistoryEntry_test.go | 23 ++++++++++++----------- client/lib/config.fish | 2 +- client/lib/config.sh | 2 +- client/lib/config.zsh | 2 +- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/client/cmd/saveHistoryEntry.go b/client/cmd/saveHistoryEntry.go index aa90160..fe3db68 100644 --- a/client/cmd/saveHistoryEntry.go +++ b/client/cmd/saveHistoryEntry.go @@ -152,9 +152,7 @@ func presaveHistoryEntry(ctx context.Context) { // Don't save commands that start with a space return } - startTime, err := parseCrossPlatformInt(os.Args[4]) - lib.CheckFatalError(err) - entry.StartTime = time.Unix(startTime, 0).UTC() + entry.StartTime = parseCrossPlatformTime(os.Args[4]) entry.EndTime = time.Unix(0, 0).UTC() // And persist it locally. @@ -369,11 +367,7 @@ func buildHistoryEntry(ctx context.Context, args []string) (*data.HistoryEntry, entry.ExitCode = exitCode // start time - seconds, err := parseCrossPlatformInt(args[5]) - if err != nil { - return nil, fmt.Errorf("failed to parse start time %s as int: %w", args[5], err) - } - entry.StartTime = time.Unix(seconds, 0).UTC() + entry.StartTime = parseCrossPlatformTime(args[5]) // end time entry.EndTime = time.Now().UTC() @@ -549,9 +543,16 @@ func maybeSkipBashHistTimePrefix(cmdLine string) (string, error) { return re.ReplaceAllLiteralString(cmdLine, ""), nil } -func parseCrossPlatformInt(data string) (int64, error) { - data = strings.TrimSuffix(data, "N") - return strconv.ParseInt(data, 10, 64) +func parseCrossPlatformTime(data string) time.Time { + data = strings.TrimSuffix(data, "N") // Trim the N suffix that is present on MacOS where the date CLI doesn't support %N + startTime, err := strconv.ParseInt(data, 10, 64) + lib.CheckFatalError(err) + if len(data) >= 18 { + return time.Unix(0, startTime).UTC() + } else { + return time.Unix(startTime, 0).UTC() + } + } func getLastCommand(history string) (string, error) { diff --git a/client/cmd/saveHistoryEntry_test.go b/client/cmd/saveHistoryEntry_test.go index 5d92648..bb82744 100644 --- a/client/cmd/saveHistoryEntry_test.go +++ b/client/cmd/saveHistoryEntry_test.go @@ -135,17 +135,18 @@ func TestBuildHistoryEntryWithTimestampStripping(t *testing.T) { } } -func TestParseCrossPlatformInt(t *testing.T) { - res, err := parseCrossPlatformInt("123") - require.NoError(t, err) - if res != 123 { - t.Fatalf("failed to parse cross platform int %d", res) - } - res, err = parseCrossPlatformInt("123N") - require.NoError(t, err) - if res != 123 { - t.Fatalf("failed to parse cross platform int %d", res) - } +func TestParseCrossPlatformTime(t *testing.T) { + res := parseCrossPlatformTime("1696715149") + require.Equal(t, time.Unix(1696715149, 0).UTC(), res) + + res = parseCrossPlatformTime("1696715149N") + require.Equal(t, time.Unix(1696715149, 0).UTC(), res) + + res = parseCrossPlatformTime("1696715218277655463") + require.Equal(t, time.Unix(0, 1696715218277655463).UTC(), res) + + res = parseCrossPlatformTime("1696715218277655463N") + require.Equal(t, time.Unix(0, 1696715218277655463).UTC(), res) } func TestBuildRegexFromTimeFormat(t *testing.T) { diff --git a/client/lib/config.fish b/client/lib/config.fish index 0cb0d78..08205fc 100644 --- a/client/lib/config.fish +++ b/client/lib/config.fish @@ -1,7 +1,7 @@ function _hishtory_post_exec --on-event fish_preexec # Runs after , but before the command is executed set --global _hishtory_command $argv - set --global _hishtory_start_time (date +%s) + set --global _hishtory_start_time (date +%s%N) hishtory presaveHistoryEntry fish "$_hishtory_command" $_hishtory_start_time & # Background Run # hishtory presaveHistoryEntry fish "$_hishtory_command" $_hishtory_start_time # Foreground Run end diff --git a/client/lib/config.sh b/client/lib/config.sh index 7005ecd..f1d253e 100644 --- a/client/lib/config.sh +++ b/client/lib/config.sh @@ -13,7 +13,7 @@ function __hishtory_precommand() { unset HISHTORY_AT_PROMPT # Run before every command - HISHTORY_START_TIME=`date +%s` + HISHTORY_START_TIME=`date +%s%N` CMD=`history 1` if ! [ -z "CMD " ] ; then (hishtory presaveHistoryEntry bash "$CMD" $HISHTORY_START_TIME &) # Background Run diff --git a/client/lib/config.zsh b/client/lib/config.zsh index 346e7eb..fc2e498 100644 --- a/client/lib/config.zsh +++ b/client/lib/config.zsh @@ -8,7 +8,7 @@ function _hishtory_add() { # Runs after , but before the command is executed # $1 contains the command that was run _hishtory_command=$1 - _hishtory_start_time=`date +%s` + _hishtory_start_time=`date +%s%N` if ! [ -z "$_hishtory_command " ]; then (hishtory presaveHistoryEntry zsh "$_hishtory_command" $_hishtory_start_time &) # Background Run # hishtory presaveHistoryEntry zsh "$_hishtory_command" $_hishtory_start_time # Foreground Run