feat: add alias file generation and management for shell hooks
Release / release (push) Successful in 49s
Release / release (push) Successful in 49s
- **Aliases**: Generate shell alias files (`aliases.sh` for bash/zsh, `netssh.fish` for fish) from cached hosts. Regenerate on each shell startup and cache refresh to keep aliases updated. - **Hooks**: Extend shell hook functionality to include alias file support. Install and uninstall commands updated for bash, zsh, and fish. - **Tests**: Add unit tests to verify alias file generation, path resolution, and idempotent hook installation. - **Docs**: Update README with instructions for alias file usage, installation, and relation to hooks.
This commit is contained in:
+32
-5
@@ -8,10 +8,15 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// Marker is the unique string used to detect an existing hook installation.
|
||||
// Marker is the unique string used to detect an existing hook line.
|
||||
Marker = "netssh shell-init"
|
||||
// Line is the full line written into the shell profile.
|
||||
Line = "netssh shell-init # netssh cache auto-refresh"
|
||||
|
||||
// AliasesMarker is the unique string used to detect the aliases source line.
|
||||
AliasesMarker = "netssh/aliases.sh"
|
||||
// AliasesSourceLine is the bash/zsh line that sources the generated aliases file.
|
||||
AliasesSourceLine = "source ~/.cache/netssh/aliases.sh 2>/dev/null # netssh aliases"
|
||||
)
|
||||
|
||||
// ProfilePath returns the canonical shell profile path for the given shell name.
|
||||
@@ -68,8 +73,30 @@ func Install(profilePath string) (installed bool, err error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Uninstall removes the hook line from the profile.
|
||||
// Returns (true, nil) when removed, (false, nil) when the hook was not found.
|
||||
// InstallAliasesSource appends the aliases source line to a bash/zsh profile.
|
||||
// This is a no-op for fish (which uses conf.d auto-sourcing instead).
|
||||
// Returns (true, nil) when newly added, (false, nil) when already present.
|
||||
func InstallAliasesSource(profilePath string) (installed bool, err error) {
|
||||
data, err := os.ReadFile(profilePath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return false, fmt.Errorf("reading profile: %w", err)
|
||||
}
|
||||
if strings.Contains(string(data), AliasesMarker) {
|
||||
return false, nil
|
||||
}
|
||||
f, err := os.OpenFile(profilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("opening profile: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := fmt.Fprintf(f, "%s\n", AliasesSourceLine); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Uninstall removes the hook line and the aliases source line from the profile.
|
||||
// Returns (true, nil) when something was removed, (false, nil) when nothing was found.
|
||||
// Returns (false, nil) — not an error — when the file does not exist.
|
||||
func Uninstall(profilePath string) (removed bool, err error) {
|
||||
data, err := os.ReadFile(profilePath)
|
||||
@@ -80,13 +107,13 @@ func Uninstall(profilePath string) (removed bool, err error) {
|
||||
return false, fmt.Errorf("reading profile: %w", err)
|
||||
}
|
||||
content := string(data)
|
||||
if !strings.Contains(content, Marker) {
|
||||
if !strings.Contains(content, Marker) && !strings.Contains(content, AliasesMarker) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var kept []string
|
||||
for _, line := range strings.Split(content, "\n") {
|
||||
if strings.Contains(line, Marker) {
|
||||
if strings.Contains(line, Marker) || strings.Contains(line, AliasesMarker) {
|
||||
continue
|
||||
}
|
||||
kept = append(kept, line)
|
||||
|
||||
Reference in New Issue
Block a user