Better timestamp stripping

This commit is contained in:
David Dworken 2022-09-01 23:22:53 -07:00
parent 614b024658
commit b63cc313fd
2 changed files with 95 additions and 11 deletions

View File

@ -14,6 +14,7 @@ import (
"os/exec" "os/exec"
"os/user" "os/user"
"path" "path"
"regexp"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
@ -150,21 +151,79 @@ func BuildHistoryEntry(args []string) (*data.HistoryEntry, error) {
return &entry, nil return &entry, nil
} }
func buildRegexFromTimeFormat(timeFormat string) string {
expectedRegex := ""
lastCharWasPercent := false
for _, char := range timeFormat {
if lastCharWasPercent {
if char == '%' {
expectedRegex += regexp.QuoteMeta(string(char))
lastCharWasPercent = false
continue
} else if char == 't' {
expectedRegex += "\t"
} else if char == 'F' {
expectedRegex += buildRegexFromTimeFormat("%Y-%m-%d")
} else if char == 'Y' {
expectedRegex += "[0-9]{4}"
} else if char == 'G' {
expectedRegex += "[0-9]{4}"
} else if char == 'g' {
expectedRegex += "[0-9]{2}"
} else if char == 'C' {
expectedRegex += "[0-9]{2}"
} else if char == 'm' {
expectedRegex += "[0-9]{2}"
} else if char == 'd' {
expectedRegex += "[0-9]{2}"
} else if char == 'D' {
expectedRegex += buildRegexFromTimeFormat("%m/%d/%y")
} else if char == 'T' {
expectedRegex += buildRegexFromTimeFormat("%H:%M:%S")
} else if char == 'H' || char == 'I' {
expectedRegex += "[0-9]{2}"
} else if char == 'M' {
expectedRegex += "[0-9]{2}"
} else if char == 'j' {
expectedRegex += "[0-9]{3}"
} else if char == 'S' {
expectedRegex += "[0-9]{2}"
} else if char == 'c' {
// Note: Specific to the POSIX locale
expectedRegex += buildRegexFromTimeFormat("%a %b %e %H:%M:%S %Y")
} else if char == 'a' {
// Note: Specific to the POSIX locale
expectedRegex += "(Sun|Mon|Tue|Wed|Thu|Fri|Sat)"
} else if char == 'b' || char == 'h' {
// Note: Specific to the POSIX locale
expectedRegex += "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"
} else if char == 'e' {
expectedRegex += "[0-9 ]{2}"
} else {
// TODO: Add more of the options from https://man7.org/linux/man-pages/man3/strftime.3.html (currently going through j)
panic(fmt.Sprintf("buildRegexFromTimeFormat doesn't support %%%v, please open a bug against github.com/ddworken/hishtory", string(char)))
}
} else if char != '%' {
expectedRegex += regexp.QuoteMeta(string(char))
}
lastCharWasPercent = false
if char == '%' {
lastCharWasPercent = true
}
}
return expectedRegex
}
func maybeSkipBashHistTimePrefix(cmdLine string) string { func maybeSkipBashHistTimePrefix(cmdLine string) string {
format := os.Getenv("HISTTIMEFORMAT") format := os.Getenv("HISTTIMEFORMAT")
if format == "" { if format == "" {
return cmdLine return cmdLine
} }
if !strings.HasSuffix(format, " ") { re, err := regexp.Compile("^" + buildRegexFromTimeFormat(format))
GetLogger().Printf("bash has HISTTIMEFORMAT set, but it doesn't end in a space so we can't strip the timestamp") if err != nil {
return cmdLine panic("TODO: bubble up this error")
} }
// TODO: could we handle things like `export HISTTIMEFORMAT='%c:'`? return re.ReplaceAllLiteralString(cmdLine, "")
numSpaces := strings.Count(format, " ")
numC := strings.Count(format, "%c")
numSpaces += (4 * numC)
split := strings.SplitN(cmdLine, " ", numSpaces+1)
return split[len(split)-1]
} }
func parseCrossPlatformInt(data string) (int64, error) { func parseCrossPlatformInt(data string) (int64, error) {

View File

@ -191,6 +191,26 @@ func TestParseCrossPlatformInt(t *testing.T) {
} }
} }
func TestBuildRegexFromTimeFormat(t *testing.T) {
testcases := []struct {
formatString, regex string
}{
{"%Y ", "[0-9]{4} "},
{"%F %T ", "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} "},
{"%F%T", "[0-9]{4}-[0-9]{2}-[0-9]{2}[0-9]{2}:[0-9]{2}:[0-9]{2}"},
{"%%", "%"},
{"%%%%", "%%"},
{"%%%Y", "%[0-9]{4}"},
{"%%%F%T", "%[0-9]{4}-[0-9]{2}-[0-9]{2}[0-9]{2}:[0-9]{2}:[0-9]{2}"},
}
for _, tc := range testcases {
if regex := buildRegexFromTimeFormat(tc.formatString); regex != tc.regex {
t.Fatalf("building a regex for %#v returned %#v (expected=%#v)", tc.formatString, regex, tc.regex)
}
}
}
func TestMaybeSkipBashHistTimePrefix(t *testing.T) { func TestMaybeSkipBashHistTimePrefix(t *testing.T) {
defer shared.BackupAndRestoreEnv("HISTTIMEFORMAT")() defer shared.BackupAndRestoreEnv("HISTTIMEFORMAT")()
@ -205,6 +225,9 @@ func TestMaybeSkipBashHistTimePrefix(t *testing.T) {
{"%F %T ", "2019-07-12 13:02:31 ls -Slah", "ls -Slah"}, {"%F %T ", "2019-07-12 13:02:31 ls -Slah", "ls -Slah"},
{"%F ", "2019-07-12 ls -Slah", "ls -Slah"}, {"%F ", "2019-07-12 ls -Slah", "ls -Slah"},
{"%F ", "2019-07-12 ls -Slah", "ls -Slah"}, {"%F ", "2019-07-12 ls -Slah", "ls -Slah"},
{"%Y", "2019ls -Slah", "ls -Slah"},
{"%Y%Y", "20192020ls -Slah", "ls -Slah"},
{"%Y%Y", "20192020ls -Slah20192020", "ls -Slah20192020"},
{"", "ls -Slah", "ls -Slah"}, {"", "ls -Slah", "ls -Slah"},
{"[%F %T] ", "[2019-07-12 13:02:31] sudo apt update", "sudo apt update"}, {"[%F %T] ", "[2019-07-12 13:02:31] sudo apt update", "sudo apt update"},
{"[%F a %T] ", "[2019-07-12 a 13:02:31] sudo apt update", "sudo apt update"}, {"[%F a %T] ", "[2019-07-12 a 13:02:31] sudo apt update", "sudo apt update"},
@ -212,8 +235,10 @@ func TestMaybeSkipBashHistTimePrefix(t *testing.T) {
{"%c ", "Sun Aug 19 02:56:02 2012 sudo apt update", "sudo apt update"}, {"%c ", "Sun Aug 19 02:56:02 2012 sudo apt update", "sudo apt update"},
{"%c ", "Sun Aug 19 02:56:02 2012 ls", "ls"}, {"%c ", "Sun Aug 19 02:56:02 2012 ls", "ls"},
{"[%c] ", "[Sun Aug 19 02:56:02 2012] ls", "ls"}, {"[%c] ", "[Sun Aug 19 02:56:02 2012] ls", "ls"},
{"[%c %t] ", "[Sun Aug 19 02:56:02 2012 aaaa] ls", "ls"}, {"[%c %t] ", "[Sun Aug 19 02:56:02 2012 ] ls", "ls"},
{"[%c %t] ", "[Sun Aug 19 02:56:02 2012 aaaa] ls -Slah", "ls -Slah"}, {"[%c %t]", "[Sun Aug 19 02:56:02 2012 ]ls", "ls"},
{"[%c %t]", "[Sun Aug 19 02:56:02 2012 ]foo", "foo"},
{"[%c %t", "[Sun Aug 19 02:56:02 2012 foo", "foo"},
} }
for _, tc := range testcases { for _, tc := range testcases {