wrap errors with %w instead of using %v

This commit is contained in:
Sergio Moura 2023-09-05 15:08:55 -04:00
parent efa9ddd6df
commit 83ad8c7b1f
10 changed files with 119 additions and 119 deletions

View File

@ -196,7 +196,7 @@ func apiSubmitHandler(ctx context.Context, w http.ResponseWriter, r *http.Reques
return nil
})
if err != nil {
panic(fmt.Errorf("failed to execute transaction to add entries to DB: %v", err))
panic(fmt.Errorf("failed to execute transaction to add entries to DB: %w", err))
}
if GLOBAL_STATSD != nil {
GLOBAL_STATSD.Count("hishtory.submit", int64(len(devices)), []string{}, 1.0)
@ -312,7 +312,7 @@ func apiGetPendingDumpRequestsHandler(ctx context.Context, w http.ResponseWriter
checkGormResult(GLOBAL_DB.WithContext(ctx).Where("user_id = ? AND requesting_device_id != ?", userId, deviceId).Find(&dumpRequests))
respBody, err := json.Marshal(dumpRequests)
if err != nil {
panic(fmt.Errorf("failed to JSON marshall the dump requests: %v", err))
panic(fmt.Errorf("failed to JSON marshall the dump requests: %w", err))
}
w.Write(respBody)
}
@ -342,7 +342,7 @@ func apiSubmitDumpHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
return nil
})
if err != nil {
panic(fmt.Errorf("failed to execute transaction to add dumped DB: %v", err))
panic(fmt.Errorf("failed to execute transaction to add dumped DB: %w", err))
}
checkGormResult(GLOBAL_DB.WithContext(ctx).Delete(&shared.DumpRequest{}, "user_id = ? AND requesting_device_id = ?", userId, requestingDeviceId))
updateUsageData(ctx, r, userId, srcDeviceId, len(entries), false)
@ -372,7 +372,7 @@ func getDeletionRequestsHandler(ctx context.Context, w http.ResponseWriter, r *h
checkGormResult(GLOBAL_DB.WithContext(ctx).Where("user_id = ? AND destination_device_id = ?", userId, deviceId).Find(&deletionRequests))
respBody, err := json.Marshal(deletionRequests)
if err != nil {
panic(fmt.Errorf("failed to JSON marshall the dump requests: %v", err))
panic(fmt.Errorf("failed to JSON marshall the dump requests: %w", err))
}
w.Write(respBody)
}
@ -491,11 +491,11 @@ func OpenDB() (*gorm.DB, error) {
if isTestEnvironment() {
db, err := gorm.Open(sqlite.Open("file::memory:?_journal_mode=WAL&cache=shared"), &gorm.Config{})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
}
underlyingDb, err := db.DB()
if err != nil {
return nil, fmt.Errorf("failed to access underlying DB: %v", err)
return nil, fmt.Errorf("failed to access underlying DB: %w", err)
}
underlyingDb.SetMaxOpenConns(1)
db.Exec("PRAGMA journal_mode = WAL")
@ -521,7 +521,7 @@ func OpenDB() (*gorm.DB, error) {
var err error
db, err = gorm.Open(sqlite.Open(sqliteDb), &gorm.Config{Logger: customLogger})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
}
} else {
postgresDb := fmt.Sprintf(PostgresDb, os.Getenv("POSTGRESQL_PASSWORD"))
@ -535,7 +535,7 @@ func OpenDB() (*gorm.DB, error) {
}
db, err = gormtrace.Open(postgres.New(postgres.Config{Conn: sqlDb}), &gorm.Config{Logger: customLogger})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
}
}
AddDatabaseTables(db)
@ -602,12 +602,12 @@ type releaseInfo struct {
func updateReleaseVersion() error {
resp, err := http.Get("https://api.github.com/repos/ddworken/hishtory/releases/latest")
if err != nil {
return fmt.Errorf("failed to get latest release version: %v", err)
return fmt.Errorf("failed to get latest release version: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read github API response body: %v", err)
return fmt.Errorf("failed to read github API response body: %w", err)
}
if resp.StatusCode == 403 && strings.Contains(string(respBody), "API rate limit exceeded for ") {
return nil
@ -618,7 +618,7 @@ func updateReleaseVersion() error {
var info releaseInfo
err = json.Unmarshal(respBody, &info)
if err != nil {
return fmt.Errorf("failed to parse github API response: %v", err)
return fmt.Errorf("failed to parse github API response: %w", err)
}
latestVersionTag := info.Name
ReleaseVersion = decrementVersionIfInvalid(latestVersionTag)
@ -654,7 +654,7 @@ func assertValidUpdate(updateInfo shared.UpdateInfo) error {
for _, url := range urls {
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("failed to retrieve URL %#v: %v", url, err)
return fmt.Errorf("failed to retrieve URL %#v: %w", url, err)
}
defer resp.Body.Close()
if resp.StatusCode == 404 {
@ -878,7 +878,7 @@ func deepCleanDatabase(ctx context.Context) {
return nil
})
if err != nil {
panic(fmt.Errorf("failed to deep clean DB: %v", err))
panic(fmt.Errorf("failed to deep clean DB: %w", err))
}
}

View File

@ -75,7 +75,7 @@ func (b bashTester) RunInteractiveShellRelaxed(t testing.TB, script string) (str
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return "", fmt.Errorf("unexpected error when running commands, out=%#v, err=%#v: %v", stdout.String(), stderr.String(), err)
return "", fmt.Errorf("unexpected error when running commands, out=%#v, err=%#v: %w", stdout.String(), stderr.String(), err)
}
outStr := stdout.String()
require.NotContains(t, outStr, "hishtory fatal error", "Ran command, but hishtory had a fatal error!")
@ -105,7 +105,7 @@ func (z zshTester) RunInteractiveShellRelaxed(t testing.TB, script string) (stri
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return stdout.String(), fmt.Errorf("unexpected error when running command=%#v, out=%#v, err=%#v: %v", script, stdout.String(), stderr.String(), err)
return stdout.String(), fmt.Errorf("unexpected error when running command=%#v, out=%#v, err=%#v: %w", script, stdout.String(), stderr.String(), err)
}
outStr := stdout.String()
require.NotContains(t, outStr, "hishtory fatal error")

View File

@ -129,7 +129,7 @@ func warnIfUnsupportedBashVersion() error {
cmd := exec.Command("bash", "--version")
bashVersion, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to check bash version: %v", err)
return fmt.Errorf("failed to check bash version: %w", err)
}
if strings.Contains(string(bashVersion), "version 3.") {
fmt.Printf("Warning: Your current bash version does not support overriding control-r. Please upgrade to at least bash 5 to enable the control-r integration.\n")
@ -140,7 +140,7 @@ func warnIfUnsupportedBashVersion() error {
func install(secretKey string, offline bool) error {
homedir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to get user's home directory: %v", err)
return fmt.Errorf("failed to get user's home directory: %w", err)
}
err = hctx.MakeHishtoryDir()
if err != nil {
@ -201,16 +201,16 @@ func installBinary(homedir string) (string, error) {
if _, err := os.Stat(clientPath); err == nil {
err = syscall.Unlink(clientPath)
if err != nil {
return "", fmt.Errorf("failed to unlink %s for install: %v", clientPath, err)
return "", fmt.Errorf("failed to unlink %s for install: %w", clientPath, err)
}
}
err = copyFile(os.Args[0], clientPath)
if err != nil {
return "", fmt.Errorf("failed to copy hishtory binary to $PATH: %v", err)
return "", fmt.Errorf("failed to copy hishtory binary to $PATH: %w", err)
}
err = os.Chmod(clientPath, 0o700)
if err != nil {
return "", fmt.Errorf("failed to set permissions on hishtory binary: %v", err)
return "", fmt.Errorf("failed to set permissions on hishtory binary: %w", err)
}
return clientPath, nil
}
@ -236,12 +236,12 @@ func configureFish(homedir, binaryPath string) error {
}
err = os.WriteFile(getFishConfigPath(homedir), []byte(configContents), 0o644)
if err != nil {
return fmt.Errorf("failed to write config.zsh file: %v", err)
return fmt.Errorf("failed to write config.zsh file: %w", err)
}
// Check if we need to configure the fishrc
fishIsConfigured, err := isFishConfigured(homedir)
if err != nil {
return fmt.Errorf("failed to check ~/.config/fish/config.fish: %v", err)
return fmt.Errorf("failed to check ~/.config/fish/config.fish: %w", err)
}
if fishIsConfigured {
return nil
@ -249,7 +249,7 @@ func configureFish(homedir, binaryPath string) error {
// Add to fishrc
err = os.MkdirAll(path.Join(homedir, ".config/fish"), 0o744)
if err != nil {
return fmt.Errorf("failed to create fish config directory: %v", err)
return fmt.Errorf("failed to create fish config directory: %w", err)
}
return addToShellConfig(path.Join(homedir, ".config/fish/config.fish"), getFishConfigFragment(homedir))
}
@ -265,7 +265,7 @@ func isFishConfigured(homedir string) (bool, error) {
}
fishConfig, err := os.ReadFile(path.Join(homedir, ".config/fish/config.fish"))
if err != nil {
return false, fmt.Errorf("failed to read ~/.config/fish/config.fish: %v", err)
return false, fmt.Errorf("failed to read ~/.config/fish/config.fish: %w", err)
}
return strings.Contains(string(fishConfig), getFishConfigFragment(homedir)), nil
}
@ -286,12 +286,12 @@ func configureZshrc(homedir, binaryPath string) error {
}
err := os.WriteFile(getZshConfigPath(homedir), []byte(configContents), 0o644)
if err != nil {
return fmt.Errorf("failed to write config.zsh file: %v", err)
return fmt.Errorf("failed to write config.zsh file: %w", err)
}
// Check if we need to configure the zshrc
zshIsConfigured, err := isZshConfigured(homedir)
if err != nil {
return fmt.Errorf("failed to check .zshrc: %v", err)
return fmt.Errorf("failed to check .zshrc: %w", err)
}
if zshIsConfigured {
return nil
@ -318,7 +318,7 @@ func isZshConfigured(homedir string) (bool, error) {
}
bashrc, err := os.ReadFile(getZshRcPath(homedir))
if err != nil {
return false, fmt.Errorf("failed to read zshrc: %v", err)
return false, fmt.Errorf("failed to read zshrc: %w", err)
}
return strings.Contains(string(bashrc), getZshConfigFragment(homedir)), nil
}
@ -339,12 +339,12 @@ func configureBashrc(homedir, binaryPath string) error {
}
err := os.WriteFile(getBashConfigPath(homedir), []byte(configContents), 0o644)
if err != nil {
return fmt.Errorf("failed to write config.sh file: %v", err)
return fmt.Errorf("failed to write config.sh file: %w", err)
}
// Check if we need to configure the bashrc and configure it if so
bashRcIsConfigured, err := isBashRcConfigured(homedir)
if err != nil {
return fmt.Errorf("failed to check ~/.bashrc: %v", err)
return fmt.Errorf("failed to check ~/.bashrc: %w", err)
}
if !bashRcIsConfigured {
err = addToShellConfig(path.Join(homedir, ".bashrc"), getBashConfigFragment(homedir))
@ -356,7 +356,7 @@ func configureBashrc(homedir, binaryPath string) error {
if doesBashProfileNeedConfig(homedir) {
bashProfileIsConfigured, err := isBashProfileConfigured(homedir)
if err != nil {
return fmt.Errorf("failed to check ~/.bash_profile: %v", err)
return fmt.Errorf("failed to check ~/.bash_profile: %w", err)
}
if !bashProfileIsConfigured {
err = addToShellConfig(path.Join(homedir, ".bash_profile"), getBashConfigFragment(homedir))
@ -371,12 +371,12 @@ func configureBashrc(homedir, binaryPath string) error {
func addToShellConfig(shellConfigPath, configFragment string) error {
f, err := os.OpenFile(shellConfigPath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644)
if err != nil {
return fmt.Errorf("failed to append to %s: %v", shellConfigPath, err)
return fmt.Errorf("failed to append to %s: %w", shellConfigPath, err)
}
defer f.Close()
_, err = f.WriteString(configFragment)
if err != nil {
return fmt.Errorf("failed to append to %s: %v", shellConfigPath, err)
return fmt.Errorf("failed to append to %s: %w", shellConfigPath, err)
}
return nil
}
@ -392,7 +392,7 @@ func isBashRcConfigured(homedir string) (bool, error) {
}
bashrc, err := os.ReadFile(path.Join(homedir, ".bashrc"))
if err != nil {
return false, fmt.Errorf("failed to read bashrc: %v", err)
return false, fmt.Errorf("failed to read bashrc: %w", err)
}
return strings.Contains(string(bashrc), getBashConfigFragment(homedir)), nil
}
@ -418,7 +418,7 @@ func isBashProfileConfigured(homedir string) (bool, error) {
}
bashrc, err := os.ReadFile(path.Join(homedir, ".bash_profile"))
if err != nil {
return false, fmt.Errorf("failed to read bash_profile: %v", err)
return false, fmt.Errorf("failed to read bash_profile: %w", err)
}
return strings.Contains(string(bashrc), getBashConfigFragment(homedir)), nil
}

View File

@ -50,7 +50,7 @@ func redact(ctx *context.Context, query string, force bool) error {
reader := bufio.NewReader(os.Stdin)
resp, err := reader.ReadString('\n')
if err != nil {
return fmt.Errorf("failed to read response: %v", err)
return fmt.Errorf("failed to read response: %w", err)
}
if strings.TrimSpace(resp) != "y" {
fmt.Printf("Aborting delete per user response of %#v\n", strings.TrimSpace(resp))

View File

@ -58,7 +58,7 @@ func maybeUploadSkippedHistoryEntries(ctx *context.Context) error {
query := fmt.Sprintf("after:%s", time.Unix(config.MissedUploadTimestamp, 0).Format("2006-01-02"))
entries, err := lib.Search(ctx, db, query, 0)
if err != nil {
return fmt.Errorf("failed to retrieve history entries that haven't been uploaded yet: %v", err)
return fmt.Errorf("failed to retrieve history entries that haven't been uploaded yet: %w", err)
}
hctx.GetLogger().Infof("Uploading %d history entries that previously failed to upload (query=%#v)\n", len(entries), query)
jsonValue, err := lib.EncryptAndMarshal(config, entries)
@ -76,7 +76,7 @@ func maybeUploadSkippedHistoryEntries(ctx *context.Context) error {
config.MissedUploadTimestamp = 0
err = hctx.SetConfig(config)
if err != nil {
return fmt.Errorf("failed to mark a history entry as uploaded: %v", err)
return fmt.Errorf("failed to mark a history entry as uploaded: %w", err)
}
return nil
}
@ -140,11 +140,11 @@ func saveHistoryEntry(ctx *context.Context) {
if config.BetaMode {
tx, err := lib.MakeWhereQueryFromSearch(ctx, db, "cwd:"+entry.CurrentWorkingDirectory+" start_time:"+strconv.FormatInt(entry.StartTime.Unix(), 10))
if err != nil {
lib.CheckFatalError(fmt.Errorf("failed to query for pre-saved history entries: %s", err))
lib.CheckFatalError(fmt.Errorf("failed to query for pre-saved history entries: %w", err))
}
res := tx.Delete(&data.HistoryEntry{})
if res.Error != nil {
lib.CheckFatalError(fmt.Errorf("failed to delete pre-saved history entries: %s", res.Error))
lib.CheckFatalError(fmt.Errorf("failed to delete pre-saved history entries: %w", res.Error))
}
if res.RowsAffected > 1 {
lib.CheckFatalError(fmt.Errorf("attempted to delete pre-saved entry, but something went wrong since we deleted %d rows", res.RowsAffected))
@ -224,14 +224,14 @@ func buildPreArgsHistoryEntry(ctx *context.Context) (*data.HistoryEntry, error)
// user
user, err := user.Current()
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
entry.LocalUsername = user.Username
// cwd and homedir
cwd, homedir, err := getCwd(ctx)
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
entry.CurrentWorkingDirectory = cwd
entry.HomeDirectory = homedir
@ -239,7 +239,7 @@ func buildPreArgsHistoryEntry(ctx *context.Context) (*data.HistoryEntry, error)
// hostname
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
entry.Hostname = hostname
@ -272,14 +272,14 @@ func buildHistoryEntry(ctx *context.Context, args []string) (*data.HistoryEntry,
// exitCode
exitCode, err := strconv.Atoi(args[3])
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
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: %v", args[5], err)
return nil, fmt.Errorf("failed to parse start time %s as int: %w", args[5], err)
}
entry.StartTime = time.Unix(seconds, 0)
@ -290,11 +290,11 @@ func buildHistoryEntry(ctx *context.Context, args []string) (*data.HistoryEntry,
if shell == "bash" {
cmd, err := getLastCommand(args[4])
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
shouldBeSkipped, err := shouldSkipHiddenCommand(ctx, args[4])
if err != nil {
return nil, fmt.Errorf("failed to check if command was hidden: %v", err)
return nil, fmt.Errorf("failed to check if command was hidden: %w", err)
}
if shouldBeSkipped || strings.HasPrefix(cmd, " ") {
// Don't save commands that start with a space
@ -443,7 +443,7 @@ func maybeSkipBashHistTimePrefix(cmdLine string) (string, error) {
}
re, err := regexp.Compile("^" + buildRegexFromTimeFormat(format))
if err != nil {
return "", fmt.Errorf("failed to parse regex for HISTTIMEFORMAT variable: %v", err)
return "", fmt.Errorf("failed to parse regex for HISTTIMEFORMAT variable: %w", err)
}
return re.ReplaceAllLiteralString(cmdLine, ""), nil
}
@ -481,7 +481,7 @@ func shouldSkipHiddenCommand(ctx *context.Context, historyLine string) (bool, er
func getCwd(ctx *context.Context) (string, string, error) {
cwd, err := getCwdWithoutSubstitution()
if err != nil {
return "", "", fmt.Errorf("failed to get cwd for last command: %v", err)
return "", "", fmt.Errorf("failed to get cwd for last command: %w", err)
}
homedir := hctx.GetHome(ctx)
if cwd == homedir {

View File

@ -96,16 +96,16 @@ func makeAead(userSecret string) (cipher.AEAD, error) {
func Encrypt(userSecret string, data, additionalData []byte) ([]byte, []byte, error) {
aead, err := makeAead(userSecret)
if err != nil {
return []byte{}, []byte{}, fmt.Errorf("failed to make AEAD: %v", err)
return []byte{}, []byte{}, fmt.Errorf("failed to make AEAD: %w", err)
}
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return []byte{}, []byte{}, fmt.Errorf("failed to read a nonce: %v", err)
return []byte{}, []byte{}, fmt.Errorf("failed to read a nonce: %w", err)
}
ciphertext := aead.Seal(nil, nonce, data, additionalData)
_, err = aead.Open(nil, nonce, ciphertext, additionalData)
if err != nil {
return []byte{}, []byte{}, fmt.Errorf("failed to open AEAD: %v", err)
return []byte{}, []byte{}, fmt.Errorf("failed to open AEAD: %w", err)
}
return ciphertext, nonce, nil
}
@ -113,11 +113,11 @@ func Encrypt(userSecret string, data, additionalData []byte) ([]byte, []byte, er
func Decrypt(userSecret string, data, additionalData, nonce []byte) ([]byte, error) {
aead, err := makeAead(userSecret)
if err != nil {
return []byte{}, fmt.Errorf("failed to make AEAD: %v", err)
return []byte{}, fmt.Errorf("failed to make AEAD: %w", err)
}
plaintext, err := aead.Open(nil, nonce, data, additionalData)
if err != nil {
return []byte{}, fmt.Errorf("failed to decrypt: %v", err)
return []byte{}, fmt.Errorf("failed to decrypt: %w", err)
}
return plaintext, nil
}

View File

@ -30,7 +30,7 @@ func GetLogger() *logrus.Logger {
getLoggerOnce.Do(func() {
homedir, err := os.UserHomeDir()
if err != nil {
panic(fmt.Errorf("failed to get user's home directory: %v", err))
panic(fmt.Errorf("failed to get user's home directory: %w", err))
}
err = MakeHishtoryDir()
if err != nil {
@ -59,11 +59,11 @@ func GetLogger() *logrus.Logger {
func MakeHishtoryDir() error {
homedir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to get user's home directory: %v", err)
return fmt.Errorf("failed to get user's home directory: %w", err)
}
err = os.MkdirAll(path.Join(homedir, data.GetHishtoryPath()), 0o744)
if err != nil {
return fmt.Errorf("failed to create ~/%s dir: %v", data.GetHishtoryPath(), err)
return fmt.Errorf("failed to create ~/%s dir: %w", data.GetHishtoryPath(), err)
}
return nil
}
@ -71,7 +71,7 @@ func MakeHishtoryDir() error {
func OpenLocalSqliteDb() (*gorm.DB, error) {
homedir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("failed to get user's home directory: %v", err)
return nil, fmt.Errorf("failed to get user's home directory: %w", err)
}
err = MakeHishtoryDir()
if err != nil {
@ -90,7 +90,7 @@ func OpenLocalSqliteDb() (*gorm.DB, error) {
dsn := fmt.Sprintf("file:%s?mode=rwc&_journal_mode=WAL", dbFilePath)
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{SkipDefaultTransaction: true, Logger: newLogger})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
}
tx, err := db.DB()
if err != nil {
@ -112,17 +112,17 @@ func MakeContext() *context.Context {
ctx := context.Background()
config, err := GetConfig()
if err != nil {
panic(fmt.Errorf("failed to retrieve config: %v", err))
panic(fmt.Errorf("failed to retrieve config: %w", err))
}
ctx = context.WithValue(ctx, hishtoryContextKey("config"), config)
db, err := OpenLocalSqliteDb()
if err != nil {
panic(fmt.Errorf("failed to open local DB: %v", err))
panic(fmt.Errorf("failed to open local DB: %w", err))
}
ctx = context.WithValue(ctx, hishtoryContextKey("db"), db)
homedir, err := os.UserHomeDir()
if err != nil {
panic(fmt.Errorf("failed to get homedir: %v", err))
panic(fmt.Errorf("failed to get homedir: %w", err))
}
ctx = context.WithValue(ctx, hishtoryContextKey("homedir"), homedir)
return &ctx
@ -191,20 +191,20 @@ type CustomColumnDefinition struct {
func GetConfigContents() ([]byte, error) {
homedir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("failed to retrieve homedir: %v", err)
return nil, fmt.Errorf("failed to retrieve homedir: %w", err)
}
dat, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH))
if err != nil {
files, err := os.ReadDir(path.Join(homedir, data.GetHishtoryPath()))
if err != nil {
return nil, fmt.Errorf("failed to read config file (and failed to list too): %v", err)
return nil, fmt.Errorf("failed to read config file (and failed to list too): %w", err)
}
filenames := ""
for _, file := range files {
filenames += file.Name()
filenames += ", "
}
return nil, fmt.Errorf("failed to read config file (files in HISHTORY_PATH: %s): %v", filenames, err)
return nil, fmt.Errorf("failed to read config file (files in HISHTORY_PATH: %s): %w", filenames, err)
}
return dat, nil
}
@ -217,7 +217,7 @@ func GetConfig() (ClientConfig, error) {
var config ClientConfig
err = json.Unmarshal(data, &config)
if err != nil {
return ClientConfig{}, fmt.Errorf("failed to parse config file: %v", err)
return ClientConfig{}, fmt.Errorf("failed to parse config file: %w", err)
}
if config.DisplayedColumns == nil || len(config.DisplayedColumns) == 0 {
config.DisplayedColumns = []string{"Hostname", "CWD", "Timestamp", "Runtime", "Exit Code", "Command"}
@ -231,11 +231,11 @@ func GetConfig() (ClientConfig, error) {
func SetConfig(config ClientConfig) error {
serializedConfig, err := json.Marshal(config)
if err != nil {
return fmt.Errorf("failed to serialize config: %v", err)
return fmt.Errorf("failed to serialize config: %w", err)
}
homedir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to retrieve homedir: %v", err)
return fmt.Errorf("failed to retrieve homedir: %w", err)
}
err = MakeHishtoryDir()
if err != nil {
@ -245,11 +245,11 @@ func SetConfig(config ClientConfig) error {
stagedConfigPath := configPath + ".tmp-" + uuid.Must(uuid.NewRandom()).String()
err = os.WriteFile(stagedConfigPath, serializedConfig, 0o644)
if err != nil {
return fmt.Errorf("failed to write config: %v", err)
return fmt.Errorf("failed to write config: %w", err)
}
err = os.Rename(stagedConfigPath, configPath)
if err != nil {
return fmt.Errorf("failed to replace config file with the updated version: %v", err)
return fmt.Errorf("failed to replace config file with the updated version: %w", err)
}
return nil
}

View File

@ -66,7 +66,7 @@ func Setup(userSecret string, isOffline bool) error {
config.IsOffline = isOffline
err := hctx.SetConfig(config)
if err != nil {
return fmt.Errorf("failed to persist config to disk: %v", err)
return fmt.Errorf("failed to persist config to disk: %w", err)
}
// Drop all existing data
@ -82,22 +82,22 @@ func Setup(userSecret string, isOffline bool) error {
}
_, err = ApiGet("/api/v1/register?user_id=" + data.UserId(userSecret) + "&device_id=" + config.DeviceId)
if err != nil {
return fmt.Errorf("failed to register device with backend: %v", err)
return fmt.Errorf("failed to register device with backend: %w", err)
}
respBody, err := ApiGet("/api/v1/bootstrap?user_id=" + data.UserId(userSecret) + "&device_id=" + config.DeviceId)
if err != nil {
return fmt.Errorf("failed to bootstrap device from the backend: %v", err)
return fmt.Errorf("failed to bootstrap device from the backend: %w", err)
}
var retrievedEntries []*shared.EncHistoryEntry
err = json.Unmarshal(respBody, &retrievedEntries)
if err != nil {
return fmt.Errorf("failed to load JSON response: %v", err)
return fmt.Errorf("failed to load JSON response: %w", err)
}
for _, entry := range retrievedEntries {
decEntry, err := data.DecryptHistoryEntry(userSecret, *entry)
if err != nil {
return fmt.Errorf("failed to decrypt history entry from server: %v", err)
return fmt.Errorf("failed to decrypt history entry from server: %w", err)
}
AddToDbIfNew(db, decEntry)
}
@ -252,30 +252,30 @@ func ImportHistory(ctx *context.Context, shouldReadStdin, force bool) (int, erro
bashHistPath := filepath.Join(homedir, ".bash_history")
historyEntries, err := readFileToArray(bashHistPath)
if err != nil {
return 0, fmt.Errorf("failed to parse bash history: %v", err)
return 0, fmt.Errorf("failed to parse bash history: %w", err)
}
zshHistPath := filepath.Join(homedir, ".zsh_history")
extraEntries, err := readFileToArray(zshHistPath)
if err != nil {
return 0, fmt.Errorf("failed to parse zsh history: %v", err)
return 0, fmt.Errorf("failed to parse zsh history: %w", err)
}
historyEntries = append(historyEntries, extraEntries...)
extraEntries, err = parseFishHistory(homedir)
if err != nil {
return 0, fmt.Errorf("failed to parse fish history: %v", err)
return 0, fmt.Errorf("failed to parse fish history: %w", err)
}
historyEntries = append(historyEntries, extraEntries...)
if histfile := os.Getenv("HISTFILE"); histfile != "" && histfile != zshHistPath && histfile != bashHistPath {
extraEntries, err := readFileToArray(histfile)
if err != nil {
return 0, fmt.Errorf("failed to parse histfile: %v", err)
return 0, fmt.Errorf("failed to parse histfile: %w", err)
}
historyEntries = append(historyEntries, extraEntries...)
}
if shouldReadStdin {
extraEntries, err = readStdin()
if err != nil {
return 0, fmt.Errorf("failed to read stdin: %v", err)
return 0, fmt.Errorf("failed to read stdin: %w", err)
}
historyEntries = append(historyEntries, extraEntries...)
}
@ -307,17 +307,17 @@ func ImportHistory(ctx *context.Context, shouldReadStdin, force bool) (int, erro
}
err = ReliableDbCreate(db, entry)
if err != nil {
return 0, fmt.Errorf("failed to insert imported history entry: %v", err)
return 0, fmt.Errorf("failed to insert imported history entry: %w", err)
}
}
err = Reupload(ctx)
if err != nil {
return 0, fmt.Errorf("failed to upload hishtory import: %v", err)
return 0, fmt.Errorf("failed to upload hishtory import: %w", err)
}
config.HaveCompletedInitialImport = true
err = hctx.SetConfig(config)
if err != nil {
return 0, fmt.Errorf("failed to mark initial import as completed, this may lead to duplicate history entries: %v", err)
return 0, fmt.Errorf("failed to mark initial import as completed, this may lead to duplicate history entries: %w", err)
}
// Trigger a checkpoint so that these bulk entries are added from the WAL to the main DB
db.Exec("PRAGMA wal_checkpoint")
@ -386,12 +386,12 @@ func readFileToArray(path string) ([]string, error) {
func GetDownloadData() (shared.UpdateInfo, error) {
respBody, err := ApiGet("/api/v1/download")
if err != nil {
return shared.UpdateInfo{}, fmt.Errorf("failed to download update info: %v", err)
return shared.UpdateInfo{}, fmt.Errorf("failed to download update info: %w", err)
}
var downloadData shared.UpdateInfo
err = json.Unmarshal(respBody, &downloadData)
if err != nil {
return shared.UpdateInfo{}, fmt.Errorf("failed to parse update info: %v", err)
return shared.UpdateInfo{}, fmt.Errorf("failed to parse update info: %w", err)
}
return downloadData, nil
}
@ -438,7 +438,7 @@ func Update(ctx *context.Context) error {
homedir := hctx.GetHome(ctx)
err = syscall.Unlink(path.Join(homedir, data.GetHishtoryPath(), "hishtory"))
if err != nil {
return fmt.Errorf("failed to unlink %s for update: %v", path.Join(homedir, data.GetHishtoryPath(), "hishtory"), err)
return fmt.Errorf("failed to unlink %s for update: %w", path.Join(homedir, data.GetHishtoryPath(), "hishtory"), err)
}
}
@ -450,7 +450,7 @@ func Update(ctx *context.Context) error {
cmd.Stderr = &stderr
err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to chmod +x the update (stdout=%#v, stderr=%#v): %v", stdout.String(), stderr.String(), err)
return fmt.Errorf("failed to chmod +x the update (stdout=%#v, stderr=%#v): %w", stdout.String(), stderr.String(), err)
}
cmd = exec.Command(getTmpClientPath(), "install")
cmd.Stdout = os.Stdout
@ -458,7 +458,7 @@ func Update(ctx *context.Context) error {
cmd.Stdin = os.Stdin
err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to install update (stderr=%#v), is %s in a noexec directory? (if so, set the TMPDIR environment variable): %v", stderr.String(), getTmpClientPath(), err)
return fmt.Errorf("failed to install update (stderr=%#v), is %s in a noexec directory? (if so, set the TMPDIR environment variable): %w", stderr.String(), getTmpClientPath(), err)
}
fmt.Printf("Successfully updated hishtory from v0.%s to %s\n", Version, downloadData.Version)
return nil
@ -550,7 +550,7 @@ func stripCodeSignature(inPath, outPath string) error {
cmd.Stderr = &stderr
err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to use codesign_allocate to strip signatures on binary=%v (stdout=%#v, stderr%#v): %v", inPath, stdout.String(), stderr.String(), err)
return fmt.Errorf("failed to use codesign_allocate to strip signatures on binary=%v (stdout=%#v, stderr%#v): %w", inPath, stdout.String(), stderr.String(), err)
}
return nil
}
@ -591,7 +591,7 @@ func downloadFile(filename, url string) error {
// Download the data
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("failed to download file at %s to %s: %v", url, filename, err)
return fmt.Errorf("failed to download file at %s to %s: %w", url, filename, err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
@ -609,7 +609,7 @@ func downloadFile(filename, url string) error {
// Create the file
out, err := os.Create(filename)
if err != nil {
return fmt.Errorf("failed to save file to %s: %v", filename, err)
return fmt.Errorf("failed to save file to %s: %w", filename, err)
}
defer out.Close()
@ -636,12 +636,12 @@ func ApiGet(path string) ([]byte, error) {
start := time.Now()
req, err := http.NewRequest("GET", getServerHostname()+path, nil)
if err != nil {
return nil, fmt.Errorf("failed to create GET: %v", err)
return nil, fmt.Errorf("failed to create GET: %w", err)
}
req.Header.Set("X-Hishtory-Version", "v0."+Version)
resp, err := httpClient().Do(req)
if err != nil {
return nil, fmt.Errorf("failed to GET %s%s: %v", getServerHostname(), path, err)
return nil, fmt.Errorf("failed to GET %s%s: %w", getServerHostname(), path, err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
@ -649,7 +649,7 @@ func ApiGet(path string) ([]byte, error) {
}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body from GET %s%s: %v", getServerHostname(), path, err)
return nil, fmt.Errorf("failed to read response body from GET %s%s: %w", getServerHostname(), path, err)
}
duration := time.Since(start)
hctx.GetLogger().Infof("ApiGet(%#v): %s\n", path, duration.String())
@ -663,13 +663,13 @@ func ApiPost(path, contentType string, data []byte) ([]byte, error) {
start := time.Now()
req, err := http.NewRequest("POST", getServerHostname()+path, bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("failed to create POST: %v", err)
return nil, fmt.Errorf("failed to create POST: %w", err)
}
req.Header.Set("Content-Type", contentType)
req.Header.Set("X-Hishtory-Version", "v0."+Version)
resp, err := httpClient().Do(req)
if err != nil {
return nil, fmt.Errorf("failed to POST %s: %v", path, err)
return nil, fmt.Errorf("failed to POST %s: %w", path, err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
@ -677,7 +677,7 @@ func ApiPost(path, contentType string, data []byte) ([]byte, error) {
}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body from POST %s: %v", path, err)
return nil, fmt.Errorf("failed to read response body from POST %s: %w", path, err)
}
duration := time.Since(start)
hctx.GetLogger().Infof("ApiPost(%#v): %s\n", path, duration.String())
@ -721,13 +721,13 @@ func ReliableDbCreate(db *gorm.DB, entry interface{}) error {
return nil
}
}
return fmt.Errorf("unrecoverable sqlite error: %v", err)
return fmt.Errorf("unrecoverable sqlite error: %w", err)
}
if err != nil && err.Error() != "database is locked (5) (SQLITE_BUSY)" {
return fmt.Errorf("unrecoverable sqlite error: %v", err)
return fmt.Errorf("unrecoverable sqlite error: %w", err)
}
}
return fmt.Errorf("failed to create DB entry even with %d retries: %v", i, err)
return fmt.Errorf("failed to create DB entry even with %d retries: %w", i, err)
}
func EncryptAndMarshal(config hctx.ClientConfig, entries []*data.HistoryEntry) ([]byte, error) {
@ -742,7 +742,7 @@ func EncryptAndMarshal(config hctx.ClientConfig, entries []*data.HistoryEntry) (
}
jsonValue, err := json.Marshal(encEntries)
if err != nil {
return jsonValue, fmt.Errorf("failed to marshal encrypted history entry: %v", err)
return jsonValue, fmt.Errorf("failed to marshal encrypted history entry: %w", err)
}
return jsonValue, nil
}
@ -754,16 +754,16 @@ func Reupload(ctx *context.Context) error {
}
entries, err := Search(ctx, hctx.GetDb(ctx), "", 0)
if err != nil {
return fmt.Errorf("failed to reupload due to failed search: %v", err)
return fmt.Errorf("failed to reupload due to failed search: %w", err)
}
for _, chunk := range shared.Chunks(entries, 100) {
jsonValue, err := EncryptAndMarshal(config, chunk)
if err != nil {
return fmt.Errorf("failed to reupload due to failed encryption: %v", err)
return fmt.Errorf("failed to reupload due to failed encryption: %w", err)
}
_, err = ApiPost("/api/v1/submit?source_device_id="+config.DeviceId, "application/json", jsonValue)
if err != nil {
return fmt.Errorf("failed to reupload due to failed POST: %v", err)
return fmt.Errorf("failed to reupload due to failed POST: %w", err)
}
}
return nil
@ -785,12 +785,12 @@ func RetrieveAdditionalEntriesFromRemote(ctx *context.Context) error {
var retrievedEntries []*shared.EncHistoryEntry
err = json.Unmarshal(respBody, &retrievedEntries)
if err != nil {
return fmt.Errorf("failed to load JSON response: %v", err)
return fmt.Errorf("failed to load JSON response: %w", err)
}
for _, entry := range retrievedEntries {
decEntry, err := data.DecryptHistoryEntry(config.UserSecret, *entry)
if err != nil {
return fmt.Errorf("failed to decrypt history entry from server: %v", err)
return fmt.Errorf("failed to decrypt history entry from server: %w", err)
}
AddToDbIfNew(db, decEntry)
}
@ -819,7 +819,7 @@ func ProcessDeletionRequests(ctx *context.Context) error {
for _, entry := range request.Messages.Ids {
res := db.Where("device_id = ? AND end_time = ?", entry.DeviceId, entry.Date).Delete(&data.HistoryEntry{})
if res.Error != nil {
return fmt.Errorf("DB error: %v", res.Error)
return fmt.Errorf("DB error: %w", res.Error)
}
}
}
@ -843,7 +843,7 @@ func parseTimeGenerously(input string) (time.Time, error) {
func MakeWhereQueryFromSearch(ctx *context.Context, db *gorm.DB, query string) (*gorm.DB, error) {
tokens, err := tokenize(query)
if err != nil {
return nil, fmt.Errorf("failed to tokenize query: %v", err)
return nil, fmt.Errorf("failed to tokenize query: %w", err)
}
tx := db.Model(&data.HistoryEntry{}).Where("true")
for _, token := range tokens {
@ -903,7 +903,7 @@ func Search(ctx *context.Context, db *gorm.DB, query string, limit int) ([]*data
var historyEntries []*data.HistoryEntry
result := tx.Find(&historyEntries)
if result.Error != nil {
return nil, fmt.Errorf("DB query error: %v", result.Error)
return nil, fmt.Errorf("DB query error: %w", result.Error)
}
return historyEntries, nil
}
@ -931,13 +931,13 @@ func parseAtomizedToken(ctx *context.Context, token string) (string, interface{}
case "before":
t, err := parseTimeGenerously(val)
if err != nil {
return "", nil, nil, fmt.Errorf("failed to parse before:%s as a timestamp: %v", val, err)
return "", nil, nil, fmt.Errorf("failed to parse before:%s as a timestamp: %w", val, err)
}
return "(CAST(strftime(\"%s\",start_time) AS INTEGER) < ?)", t.Unix(), nil, nil
case "after":
t, err := parseTimeGenerously(val)
if err != nil {
return "", nil, nil, fmt.Errorf("failed to parse after:%s as a timestamp: %v", val, err)
return "", nil, nil, fmt.Errorf("failed to parse after:%s as a timestamp: %w", val, err)
}
return "(CAST(strftime(\"%s\",start_time) AS INTEGER) > ?)", t.Unix(), nil, nil
case "start_time":
@ -945,7 +945,7 @@ func parseAtomizedToken(ctx *context.Context, token string) (string, interface{}
// internally for pre-saving history entries.
t, err := parseTimeGenerously(val)
if err != nil {
return "", nil, nil, fmt.Errorf("failed to parse after:%s as a timestamp: %v", val, err)
return "", nil, nil, fmt.Errorf("failed to parse after:%s as a timestamp: %w", val, err)
}
return "(CAST(strftime(\"%s\",start_time) AS INTEGER) = ?)", t.Unix(), nil, nil
case "command":
@ -960,7 +960,7 @@ func parseAtomizedToken(ctx *context.Context, token string) (string, interface{}
// Also get all ones that are in the DB
names, err := getAllCustomColumnNames(ctx)
if err != nil {
return "", nil, nil, fmt.Errorf("failed to get custom column names from the DB: %v", err)
return "", nil, nil, fmt.Errorf("failed to get custom column names from the DB: %w", err)
}
knownCustomColumns = append(knownCustomColumns, names...)
// Check if the atom is for a custom column that exists and if it isn't, return an error
@ -1079,7 +1079,7 @@ func SendDeletionRequest(deletionRequest shared.DeletionRequest) error {
}
_, err = ApiPost("/api/v1/add-deletion-request", "application/json", data)
if err != nil {
return fmt.Errorf("failed to send deletion request to backend service, this may cause commands to not get deleted on other instances of hishtory: %v", err)
return fmt.Errorf("failed to send deletion request to backend service, this may cause commands to not get deleted on other instances of hishtory: %w", err)
}
return nil
}

View File

@ -61,7 +61,7 @@ func verifyBinary(ctx *context.Context, binaryPath, attestationPath, versionTag
attestation, err := os.ReadFile(attestationPath)
if err != nil {
return fmt.Errorf("failed to read attestation file: %v", err)
return fmt.Errorf("failed to read attestation file: %w", err)
}
hash, err := getFileHash(binaryPath)
@ -75,13 +75,13 @@ func verifyBinary(ctx *context.Context, binaryPath, attestationPath, versionTag
func getFileHash(binaryPath string) (string, error) {
binaryFile, err := os.Open(binaryPath)
if err != nil {
return "", fmt.Errorf("failed to read binary for verification purposes: %v", err)
return "", fmt.Errorf("failed to read binary for verification purposes: %w", err)
}
defer binaryFile.Close()
hasher := sha256.New()
if _, err := io.Copy(hasher, binaryFile); err != nil {
return "", fmt.Errorf("failed to hash binary: %v", err)
return "", fmt.Errorf("failed to hash binary: %w", err)
}
hash := hex.EncodeToString(hasher.Sum(nil))
return hash, nil
@ -95,5 +95,5 @@ func handleSlsaFailure(srcErr error) error {
fmt.Println("Proceeding with update...")
return nil
}
return fmt.Errorf("failed to verify SLSA provenance of the updated binary, aborting update (to bypass, set `export HISHTORY_DISABLE_SLSA_ATTESTATION=true`): %v", srcErr)
return fmt.Errorf("failed to verify SLSA provenance of the updated binary, aborting update (to bypass, set `export HISHTORY_DISABLE_SLSA_ATTESTATION=true`): %w", srcErr)
}

View File

@ -381,7 +381,7 @@ func getRows(ctx *context.Context, columnNames []string, query string, numEntrie
entry.Command = strings.ReplaceAll(entry.Command, "\n", "\\n")
row, err := buildTableRow(ctx, columnNames, *entry)
if err != nil {
return nil, nil, fmt.Errorf("failed to build row for entry=%#v: %v", entry, err)
return nil, nil, fmt.Errorf("failed to build row for entry=%#v: %w", entry, err)
}
rows = append(rows, row)
filteredData = append(filteredData, entry)
@ -449,7 +449,7 @@ func makeTableColumns(ctx *context.Context, columnNames []string, rows []table.R
// Get the actual terminal width. If we're below this, opportunistically add some padding aiming for the maximum column widths
terminalWidth, _, err := getTerminalSize()
if err != nil {
return nil, fmt.Errorf("failed to get terminal size: %v", err)
return nil, fmt.Errorf("failed to get terminal size: %w", err)
}
for totalWidth < (terminalWidth - len(columnNames)) {
prevTotalWidth := totalWidth