diff --git a/parser/parser.go b/parser/parser.go index 2f49b97..7a6ec97 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -63,30 +63,33 @@ func CLIOutput(ctx *types.Context, cliName string) (string, error) { return CLIVersion(ctx, baseName, string(output)), nil } +//nolint:funlen func CLIVersion(ctx *types.Context, cliName, output string) string { - floatRegex := `[\d.]*` + floatRegex := `\d+\.\d+` floatWithTrailingLetterRegex := `[\d.]*\w` intRegex := `\d*` + optimisticRegex := `[\d.]*` semverRegex := `\d+\.\d+\.\d+` vStringRegex := `v[\d.]*` vStringWithTrailingLetterRegex := `v[\d.]*\w` vStringWithTrailingGreedyRegex := `v[\d.]*[\w+-]*\w` regexen := map[string]string{ - "ansible": fmt.Sprintf(`ansible \[core (%s)\b`, floatRegex), - "bash": fmt.Sprintf(`version (%s)\b`, floatRegex), - "bat": fmt.Sprintf(`bat (%s)\b`, floatRegex), + "ansible": fmt.Sprintf(`ansible \[core (%s)\b`, semverRegex), + "bash": fmt.Sprintf(`version (%s)\b`, semverRegex), + "bat": fmt.Sprintf(`bat (%s)\b`, semverRegex), "csh": fmt.Sprintf(`(%s)`, semverRegex), - "curl": fmt.Sprintf(`curl (%s)\b`, floatRegex), - "docker": fmt.Sprintf(`version (%s),`, floatRegex), - "fpp": fmt.Sprintf(`version (%s)\b`, floatRegex), - "fzf": fmt.Sprintf(`(%s)\b`, floatRegex), - "gcc": fmt.Sprintf(`clang version (%s)\b`, floatRegex), - "git": fmt.Sprintf(`git version (%s)\s`, floatRegex), - "gh": fmt.Sprintf(`gh version (%s)\b`, floatRegex), - "go": fmt.Sprintf(`go version go(%s)\s`, floatRegex), + "curl": fmt.Sprintf(`curl (%s)\b`, semverRegex), + "docker": fmt.Sprintf(`version (%s),`, semverRegex), + "fpp": fmt.Sprintf(`version (%s)\b`, semverRegex), + "fzf": fmt.Sprintf(`(%s)\b`, semverRegex), + "gcc": fmt.Sprintf(`clang version (%s)\b`, semverRegex), + "git": fmt.Sprintf(`git version (%s)\s`, semverRegex), + "gh": fmt.Sprintf(`gh version (%s)\b`, semverRegex), + "go": fmt.Sprintf(`go version go(%s)\s`, semverRegex), + "grep": fmt.Sprintf(`(%s|%s)`, semverRegex, floatRegex), "jq": fmt.Sprintf(`jq-(%s)\b`, floatRegex), "less": fmt.Sprintf(`less (%s)\b`, intRegex), - "lua": fmt.Sprintf(`Lua (%s)\b`, floatRegex), + "lua": fmt.Sprintf(`Lua (%s)\b`, semverRegex), "md5sum": fmt.Sprintf(`md5sum \(GNU coreutils\) (%s)\b`, floatRegex), "nvim": fmt.Sprintf(`NVIM (%s)\b`, vStringWithTrailingGreedyRegex), "perl": fmt.Sprintf(`This is perl .* \((%s)\)\s`, vStringRegex), @@ -96,18 +99,18 @@ func CLIVersion(ctx *types.Context, cliName, output string) string { "perldoc": fmt.Sprintf(`(%s)\b`, vStringRegex), "pihole": fmt.Sprintf(`Pi-hole version is (%s)`, vStringRegex), "plenv": `plenv ([\d\w\-\.]*)\b`, - "python": fmt.Sprintf(`Python (%s)\b`, floatRegex), - "python3": fmt.Sprintf(`Python (%s)\b`, floatRegex), - "rg": fmt.Sprintf(`ripgrep (%s)\b`, floatRegex), + "python": fmt.Sprintf(`Python (%s)\b`, semverRegex), + "python3": fmt.Sprintf(`Python (%s)\b`, semverRegex), + "rg": fmt.Sprintf(`ripgrep (%s)\b`, semverRegex), "ruby": `ruby (\d+\.\d+\.[\d\w]+)\b`, "tcsh": fmt.Sprintf(`(%s)`, semverRegex), - "rustc": fmt.Sprintf(`rustc (%s)\b`, floatRegex), - "screen": fmt.Sprintf(`version (%s)\b`, floatRegex), - "sh": fmt.Sprintf(`version (%s)\b`, floatRegex), - "sqlite3": fmt.Sprintf(`(%s)\b`, floatRegex), + "rustc": fmt.Sprintf(`rustc (%s)\b`, semverRegex), + "screen": fmt.Sprintf(`version (%s)\b`, semverRegex), + "sh": fmt.Sprintf(`version (%s)\b`, semverRegex), + "sqlite3": fmt.Sprintf(`(%s)\b`, semverRegex), "ssh": `OpenSSH_([0-9a-z.]*)\b`, - "tar": fmt.Sprintf(`bsdtar (%s)\b`, floatRegex), - "typos": fmt.Sprintf(`typos-cli (%s)\b`, floatRegex), + "tar": fmt.Sprintf(`bsdtar (%s)\b`, semverRegex), + "typos": fmt.Sprintf(`typos-cli (%s)\b`, semverRegex), "tmux": fmt.Sprintf(`tmux (%s)\b`, floatWithTrailingLetterRegex), "tree": fmt.Sprintf(`tree (%s)\b`, vStringWithTrailingLetterRegex), "trurl": fmt.Sprintf(`trurl version (%s)\b`, floatRegex), @@ -122,9 +125,9 @@ func CLIVersion(ctx *types.Context, cliName, output string) string { } else if found := len(hasNewLines.FindAllStringIndex(output, -1)); found > 1 { // If --version returns more than one line, the actual version will // generally be the last thing on the first line - versionRegex = regexp.MustCompile(fmt.Sprintf(`(?:\s)(%s|%s|%s|%s)\s*\n`, - vStringWithTrailingLetterRegex, floatWithTrailingLetterRegex, - vStringRegex, floatRegex)) + versionRegex = regexp.MustCompile(fmt.Sprintf(`(?:\s)(%s|%s|%s|%s|%s|%s)\s*\n`, + semverRegex, vStringWithTrailingLetterRegex, floatWithTrailingLetterRegex, + vStringRegex, optimisticRegex, floatRegex)) } else { versionRegex = regexp.MustCompile(`(?i)` + cliName + `\s+(.*)\b`) } diff --git a/parser/parser_test.go b/parser/parser_test.go index bc71576..cd0f6b9 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -44,6 +44,15 @@ Features: alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefi {"fpp", "0.9.2", "fpp version 0.9.2"}, {"fzf", "0.53.0", "0.53.0 (c4a9ccd)"}, {"gcc", "14.0.3", "clang version 14.0.3 (clang-1403.0.22.14.1)"}, + {"grep", "3.4", `grep (GNU grep) 3.4 +Copyright (C) 2020 Free Software Foundation, Inc. +License GPLv3+: GNU GPL version 3 or later . +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +Written by Mike Haertel and others; see +.`}, + {"grep", "2.6.0", "grep (BSD grep, GNU compatible) 2.6.0-FreeBSD"}, {"gh", "2.30.0", "gh version 2.30.0 (2023-05-30)"}, {"go", "1.20.4", "go version go1.20.4 darwin/amd64"}, {"jq", "1.6", "jq-1.6"},