Support customizing HISHTORY_PATH for people who want to install hishtory in an alternate location to fix #54

This commit is contained in:
David Dworken
2022-12-16 22:22:57 -08:00
parent 53e97253e5
commit f8b51e49da
8 changed files with 80 additions and 52 deletions

View File

@ -351,7 +351,7 @@ func testBasicUserFlow(t *testing.T, tester shellTester, onlineStatus OnlineStat
if err != nil {
t.Fatalf("failed to get homedir: %v", err)
}
dat, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, "config.sh"))
dat, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), "config.sh"))
if err != nil {
t.Fatalf("failed to read config.sh: %v", err)
}
@ -952,7 +952,7 @@ echo other`)
if strings.Count(out, "\n") != 2 {
t.Fatalf("hishtory query has unexpected number of lines: out=%#v", out)
}
if !strings.Contains(out, "~/.hishtory") {
if !strings.Contains(out, "~/"+data.GetHishtoryPath()) {
t.Fatalf("hishtory query has an incorrect CWD: out=%#v", out)
}
out = hishtoryQuery(t, tester, "echo other")
@ -992,7 +992,7 @@ CGO_ENABLED=0 go build -o /tmp/client
if err != nil {
t.Fatalf("failed to get homedir: %v", err)
}
dat, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, "config.sh"))
dat, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), "config.sh"))
if err != nil {
t.Fatalf("failed to read config.sh: %v", err)
}
@ -1215,13 +1215,24 @@ echo other`)
}
}
func TestInstallViaPythonScriptWithCustomHishtoryPath(t *testing.T) {
defer testutils.BackupAndRestore(t)()
defer testutils.BackupAndRestoreEnv("HISHTORY_PATH")()
os.Setenv("HISHTORY_PATH", ".other-path")
testInstallViaPythonScriptChild(t, bashTester{})
}
func testInstallViaPythonScript(t *testing.T, tester shellTester) {
defer testutils.BackupAndRestore(t)()
testInstallViaPythonScriptChild(t, tester)
}
func testInstallViaPythonScriptChild(t *testing.T, tester shellTester) {
if !testutils.IsOnline() {
t.Skip("skipping because we're currently offline")
}
// Set up
defer testutils.BackupAndRestore(t)()
defer testutils.BackupAndRestoreEnv("HISHTORY_TEST")()
// Install via the python script
@ -1348,7 +1359,7 @@ func TestStripBashTimePrefix(t *testing.T) {
if err != nil {
t.Fatal(err)
}
f, err := os.OpenFile(path.Join(homedir, ".hishtory", "config.sh"),
f, err := os.OpenFile(path.Join(homedir, data.GetHishtoryPath(), "config.sh"),
os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
t.Fatal(err)
@ -1373,7 +1384,7 @@ func TestStripBashTimePrefix(t *testing.T) {
if err != nil {
t.Fatal(err)
}
f, err = os.OpenFile(path.Join(homedir, ".hishtory", "config.sh"),
f, err = os.OpenFile(path.Join(homedir, data.GetHishtoryPath(), "config.sh"),
os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
t.Fatal(err)
@ -1702,7 +1713,7 @@ func clearControlRSearchFromConfig(t *testing.T) {
configContents = []byte(strings.ReplaceAll(string(configContents), "enable_control_r_search", "something-else"))
homedir, err := os.UserHomeDir()
testutils.Check(t, err)
err = os.WriteFile(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH), configContents, 0o644)
err = os.WriteFile(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH), configContents, 0o644)
testutils.Check(t, err)
}

View File

@ -195,7 +195,7 @@ func handleUpgradedFeatures() error {
func installBinary(homedir string) (string, error) {
clientPath, err := exec.LookPath("hishtory")
if err != nil {
clientPath = path.Join(homedir, data.HISHTORY_PATH, "hishtory")
clientPath = path.Join(homedir, data.GetHishtoryPath(), "hishtory")
}
if _, err := os.Stat(clientPath); err == nil {
err = syscall.Unlink(clientPath)
@ -215,7 +215,7 @@ func installBinary(homedir string) (string, error) {
}
func getFishConfigPath(homedir string) string {
return path.Join(homedir, data.HISHTORY_PATH, "config.fish")
return path.Join(homedir, data.GetHishtoryPath(), "config.fish")
}
func configureFish(homedir, binaryPath string) error {
@ -254,7 +254,7 @@ func configureFish(homedir, binaryPath string) error {
}
func getFishConfigFragment(homedir string) string {
return "\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.HISHTORY_PATH) + "\"\nsource " + getFishConfigPath(homedir) + "\n"
return "\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.GetHishtoryPath()) + "\"\nsource " + getFishConfigPath(homedir) + "\n"
}
func isFishConfigured(homedir string) (bool, error) {
@ -266,11 +266,11 @@ func isFishConfigured(homedir string) (bool, error) {
if err != nil {
return false, fmt.Errorf("failed to read ~/.config/fish/config.fish: %v", err)
}
return strings.Contains(string(fishConfig), "# Hishtory Config:"), nil
return strings.Contains(string(fishConfig), getFishConfigFragment(homedir)), nil
}
func getZshConfigPath(homedir string) string {
return path.Join(homedir, data.HISHTORY_PATH, "config.zsh")
return path.Join(homedir, data.GetHishtoryPath(), "config.zsh")
}
func configureZshrc(homedir, binaryPath string) error {
@ -307,7 +307,7 @@ func getZshRcPath(homedir string) string {
}
func getZshConfigFragment(homedir string) string {
return "\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.HISHTORY_PATH) + "\"\nsource " + getZshConfigPath(homedir) + "\n"
return "\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.GetHishtoryPath()) + "\"\nsource " + getZshConfigPath(homedir) + "\n"
}
func isZshConfigured(homedir string) (bool, error) {
@ -319,11 +319,11 @@ func isZshConfigured(homedir string) (bool, error) {
if err != nil {
return false, fmt.Errorf("failed to read zshrc: %v", err)
}
return strings.Contains(string(bashrc), "# Hishtory Config:"), nil
return strings.Contains(string(bashrc), getZshConfigFragment(homedir)), nil
}
func getBashConfigPath(homedir string) string {
return path.Join(homedir, data.HISHTORY_PATH, "config.sh")
return path.Join(homedir, data.GetHishtoryPath(), "config.sh")
}
func configureBashrc(homedir, binaryPath string) error {
@ -379,7 +379,7 @@ func addToShellConfig(shellConfigPath, configFragment string) error {
}
func getBashConfigFragment(homedir string) string {
return "\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.HISHTORY_PATH) + "\"\nsource " + getBashConfigPath(homedir) + "\n"
return "\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.GetHishtoryPath()) + "\"\nsource " + getBashConfigPath(homedir) + "\n"
}
func isBashRcConfigured(homedir string) (bool, error) {
@ -391,7 +391,7 @@ func isBashRcConfigured(homedir string) (bool, error) {
if err != nil {
return false, fmt.Errorf("failed to read bashrc: %v", err)
}
return strings.Contains(string(bashrc), "# Hishtory Config:"), nil
return strings.Contains(string(bashrc), getBashConfigFragment(homedir)), nil
}
func isBashProfileConfigured(homedir string) (bool, error) {
@ -403,7 +403,7 @@ func isBashProfileConfigured(homedir string) (bool, error) {
if err != nil {
return false, fmt.Errorf("failed to read bash_profile: %v", err)
}
return strings.Contains(string(bashrc), "# Hishtory Config:"), nil
return strings.Contains(string(bashrc), getBashConfigFragment(homedir)), nil
}
func tweakConfigForTests(configContents string) (string, error) {
@ -472,7 +472,7 @@ func uninstall(ctx *context.Context) error {
if err != nil {
return err
}
err = os.RemoveAll(path.Join(homedir, ".hishtory"))
err = os.RemoveAll(path.Join(homedir, data.GetHishtoryPath()))
if err != nil {
return err
}

View File

@ -11,6 +11,7 @@ import (
"encoding/json"
"fmt"
"io"
"os"
"time"
"github.com/ddworken/hishtory/shared"
@ -21,10 +22,13 @@ const (
KdfUserID = "user_id"
KdfEncryptionKey = "encryption_key"
CONFIG_PATH = ".hishtory.config"
HISHTORY_PATH = ".hishtory"
DB_PATH = ".hishtory.db"
)
const (
defaultHishtoryPath = ".hishtory"
)
type HistoryEntry struct {
LocalUsername string `json:"local_username" gorm:"uniqueIndex:compositeindex"`
Hostname string `json:"hostname" gorm:"uniqueIndex:compositeindex"`
@ -163,3 +167,11 @@ func EntryEquals(entry1, entry2 HistoryEntry) bool {
entry1.StartTime.Format(time.RFC3339) == entry2.StartTime.Format(time.RFC3339) &&
entry1.EndTime.Format(time.RFC3339) == entry2.EndTime.Format(time.RFC3339)
}
func GetHishtoryPath() string {
hishtoryPath := os.Getenv("HISHTORY_PATH")
if hishtoryPath != "" {
return hishtoryPath
}
return defaultHishtoryPath
}

View File

@ -38,7 +38,7 @@ func GetLogger() *logrus.Logger {
}
lumberjackLogger := &lumberjack.Logger{
Filename: path.Join(homedir, data.HISHTORY_PATH, "hishtory.log"),
Filename: path.Join(homedir, data.GetHishtoryPath(), "hishtory.log"),
MaxSize: 1, // MB
MaxBackups: 10,
MaxAge: 30, // days
@ -61,9 +61,9 @@ func MakeHishtoryDir() error {
if err != nil {
return fmt.Errorf("failed to get user's home directory: %v", err)
}
err = os.MkdirAll(path.Join(homedir, data.HISHTORY_PATH), 0o744)
err = os.MkdirAll(path.Join(homedir, data.GetHishtoryPath()), 0o744)
if err != nil {
return fmt.Errorf("failed to create ~/.hishtory dir: %v", err)
return fmt.Errorf("failed to create ~/%s dir: %v", data.GetHishtoryPath(), err)
}
return nil
}
@ -86,7 +86,7 @@ func OpenLocalSqliteDb() (*gorm.DB, error) {
Colorful: false,
},
)
dbFilePath := path.Join(homedir, data.HISHTORY_PATH, data.DB_PATH)
dbFilePath := path.Join(homedir, data.GetHishtoryPath(), data.DB_PATH)
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 {
@ -189,9 +189,9 @@ func GetConfigContents() ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("failed to retrieve homedir: %v", err)
}
dat, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH))
dat, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH))
if err != nil {
files, err := os.ReadDir(path.Join(homedir, data.HISHTORY_PATH))
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)
}
@ -200,7 +200,7 @@ func GetConfigContents() ([]byte, error) {
filenames += file.Name()
filenames += ", "
}
return nil, fmt.Errorf("failed to read config file (files in ~/.hishtory/: %s): %v", filenames, err)
return nil, fmt.Errorf("failed to read config file (files in HISHTORY_PATH: %s): %v", filenames, err)
}
return dat, nil
}
@ -237,7 +237,7 @@ func SetConfig(config ClientConfig) error {
if err != nil {
return err
}
configPath := path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH)
configPath := path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)
stagedConfigPath := configPath + ".tmp-" + uuid.Must(uuid.NewRandom()).String()
err = os.WriteFile(stagedConfigPath, serializedConfig, 0o644)
if err != nil {
@ -255,7 +255,7 @@ func InitConfig() error {
if err != nil {
return err
}
_, err = os.Stat(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH))
_, err = os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH))
if errors.Is(err, os.ErrNotExist) {
return SetConfig(ClientConfig{})
}

View File

@ -692,9 +692,9 @@ func Update(ctx *context.Context) error {
// Unlink the existing binary so we can overwrite it even though it is still running
if runtime.GOOS == "linux" {
homedir := hctx.GetHome(ctx)
err = syscall.Unlink(path.Join(homedir, data.HISHTORY_PATH, "hishtory"))
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.HISHTORY_PATH, "hishtory"), err)
return fmt.Errorf("failed to unlink %s for update: %v", path.Join(homedir, data.GetHishtoryPath(), "hishtory"), err)
}
}

View File

@ -21,14 +21,14 @@ func TestSetup(t *testing.T) {
homedir, err := os.UserHomeDir()
testutils.Check(t, err)
if _, err := os.Stat(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH)); err == nil {
if _, err := os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)); err == nil {
t.Fatalf("hishtory secret file already exists!")
}
testutils.Check(t, Setup("", false))
if _, err := os.Stat(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH)); err != nil {
if _, err := os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)); err != nil {
t.Fatalf("hishtory secret file does not exist after Setup()!")
}
data, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH))
data, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH))
testutils.Check(t, err)
if len(data) < 10 {
t.Fatalf("hishtory secret has unexpected length: %d", len(data))
@ -45,14 +45,14 @@ func TestSetupOffline(t *testing.T) {
homedir, err := os.UserHomeDir()
testutils.Check(t, err)
if _, err := os.Stat(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH)); err == nil {
if _, err := os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)); err == nil {
t.Fatalf("hishtory secret file already exists!")
}
testutils.Check(t, Setup("", true))
if _, err := os.Stat(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH)); err != nil {
if _, err := os.Stat(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH)); err != nil {
t.Fatalf("hishtory secret file does not exist after Setup()!")
}
data, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH))
data, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH))
testutils.Check(t, err)
if len(data) < 10 {
t.Fatalf("hishtory secret has unexpected length: %d", len(data))