Skip recording empty history commands

This commit is contained in:
David Dworken 2022-10-23 15:40:30 -07:00
parent 73807746a7
commit aa3f449885
5 changed files with 54 additions and 5 deletions

View File

@ -681,8 +681,10 @@ func testRepeatedCommandThenQuery(t *testing.T, tester shellTester) {
t.Fatalf("hishtory query has the wrong number of commands=%d, out=%#v", strings.Count(out, "echo mycommand"), out) t.Fatalf("hishtory query has the wrong number of commands=%d, out=%#v", strings.Count(out, "echo mycommand"), out)
} }
// Run a few more commands // Run a few more commands including some empty lines that don't get recorded
tester.RunInteractiveShell(t, `echo mycommand-30 tester.RunInteractiveShell(t, `echo mycommand-30
echo mycommand-31 echo mycommand-31
echo mycommand-3`) echo mycommand-3`)

View File

@ -26,6 +26,8 @@ var (
getLoggerOnce sync.Once getLoggerOnce sync.Once
) )
// TODO: Can we auto-rotate the log file?
func GetLogger() *log.Logger { func GetLogger() *log.Logger {
getLoggerOnce.Do(func() { getLoggerOnce.Do(func() {
homedir, err := os.UserHomeDir() homedir, err := os.UserHomeDir()

View File

@ -145,6 +145,10 @@ func BuildHistoryEntry(ctx *context.Context, args []string) (*data.HistoryEntry,
} else { } else {
return nil, fmt.Errorf("tried to save a hishtory entry from an unsupported shell=%#v", shell) return nil, fmt.Errorf("tried to save a hishtory entry from an unsupported shell=%#v", shell)
} }
if strings.TrimSpace(entry.Command) == "" {
// Skip recording empty commands where the user just hits enter in their terminal
return nil, nil
}
// hostname // hostname
hostname, err := os.Hostname() hostname, err := os.Hostname()
@ -278,7 +282,15 @@ func parseCrossPlatformInt(data string) (int64, error) {
} }
func getLastCommand(history string) (string, error) { func getLastCommand(history string) (string, error) {
return strings.SplitN(strings.SplitN(strings.TrimSpace(history), " ", 2)[1], " ", 2)[1], nil split := strings.SplitN(strings.TrimSpace(history), " ", 2)
if len(split) <= 1 {
return "", fmt.Errorf("got unexpected bash history line: %#v, please open a bug", history)
}
split = strings.SplitN(split[1], " ", 2)
if len(split) <= 1 {
return "", fmt.Errorf("got unexpected bash history line: %#v, please open a bug", history)
}
return split[1], nil
} }
func shouldSkipHiddenCommand(ctx *context.Context, historyLine string) (bool, error) { func shouldSkipHiddenCommand(ctx *context.Context, historyLine string) (bool, error) {

View File

@ -92,9 +92,41 @@ func TestBuildHistoryEntry(t *testing.T) {
if entry.StartTime.Unix() != 1641774958 { if entry.StartTime.Unix() != 1641774958 {
t.Fatalf("history entry has incorrect Unix time in the start time: %v", entry.StartTime.Unix()) t.Fatalf("history entry has incorrect Unix time in the start time: %v", entry.StartTime.Unix())
} }
// Test building an entry for fish
entry, err = BuildHistoryEntry(hctx.MakeContext(), []string{"unused", "saveHistoryEntry", "fish", "120", "ls /foo\n", "1641774958"})
shared.Check(t, err)
if entry.ExitCode != 120 {
t.Fatalf("history entry has unexpected exit code: %v", entry.ExitCode)
}
if entry.LocalUsername != user.Username {
t.Fatalf("history entry has unexpected user name: %v", entry.LocalUsername)
}
if !strings.HasPrefix(entry.CurrentWorkingDirectory, "/") && !strings.HasPrefix(entry.CurrentWorkingDirectory, "~/") {
t.Fatalf("history entry has unexpected cwd: %v", entry.CurrentWorkingDirectory)
}
if !strings.HasPrefix(entry.HomeDirectory, "/") {
t.Fatalf("history entry has unexpected home directory: %v", entry.HomeDirectory)
}
if entry.Command != "ls /foo" {
t.Fatalf("history entry has unexpected command: %v", entry.Command)
}
if !strings.HasPrefix(entry.StartTime.Format(time.RFC3339), "2022-01-09T") && !strings.HasPrefix(entry.StartTime.Format(time.RFC3339), "2022-01-10T") {
t.Fatalf("history entry has incorrect date in the start time: %v", entry.StartTime.Format(time.RFC3339))
}
if entry.StartTime.Unix() != 1641774958 {
t.Fatalf("history entry has incorrect Unix time in the start time: %v", entry.StartTime.Unix())
} }
func TestBuildHistoryEntryWithRedaction(t *testing.T) { // Test building an entry that is empty, and thus not saved
entry, err = BuildHistoryEntry(hctx.MakeContext(), []string{"unused", "saveHistoryEntry", "zsh", "120", " \n", "1641774958"})
shared.Check(t, err)
if entry != nil {
t.Fatalf("expected history entry to be nil")
}
}
func TestBuildHistoryEntryWithTimestampStripping(t *testing.T) {
defer shared.BackupAndRestoreEnv("HISTTIMEFORMAT")() defer shared.BackupAndRestoreEnv("HISTTIMEFORMAT")()
defer shared.BackupAndRestore(t)() defer shared.BackupAndRestore(t)()
defer shared.RunTestServer()() defer shared.RunTestServer()()
@ -231,7 +263,9 @@ func TestGetLastCommand(t *testing.T) {
testcases := []struct { testcases := []struct {
input, expectedOutput string input, expectedOutput string
}{ }{
{" 0 ls", "ls"},
{" 33 ls", "ls"}, {" 33 ls", "ls"},
{" 33 ls --aaaa foo bar ", "ls --aaaa foo bar"},
{" 2389 [2022-09-28 04:38:32 +0000] echo", "[2022-09-28 04:38:32 +0000] echo"}, {" 2389 [2022-09-28 04:38:32 +0000] echo", "[2022-09-28 04:38:32 +0000] echo"},
} }
for _, tc := range testcases { for _, tc := range testcases {

View File

@ -274,7 +274,7 @@ func saveHistoryEntry(ctx *context.Context) {
entry, err := lib.BuildHistoryEntry(ctx, os.Args) entry, err := lib.BuildHistoryEntry(ctx, os.Args)
lib.CheckFatalError(err) lib.CheckFatalError(err)
if entry == nil { if entry == nil {
hctx.GetLogger().Printf("Skipping saving a history entry because we failed to build a history entry (was the command prefixed with a space?)\n") hctx.GetLogger().Printf("Skipping saving a history entry because we did not build a history entry (was the command prefixed with a space and/or empty?)\n")
return return
} }
@ -348,4 +348,3 @@ func export(ctx *context.Context, query string) {
} }
// TODO(feature): Add a session_id column that corresponds to the shell session the command was run in // TODO(feature): Add a session_id column that corresponds to the shell session the command was run in
// TODO: Skip recording of empty commands