feat: add -l (list) and -u (unmount) flags
Update PKGBUILD version / update-pkgver (push) Successful in 5s
Update PKGBUILD version / update-pkgver (push) Successful in 5s
A second sshfsc <alias> call only printed "Already mounted"; tearing down a mount required ls + fusermount by hand. -l lists active mounts verified via mountinfo.Mounted, -u <Host> unmounts and removes the empty mountpoint dir. Flags are mutually exclusive.
This commit is contained in:
@@ -1,5 +1,48 @@
|
||||
# Decisions
|
||||
|
||||
## 2026-05-04 – Add `-l` (list) and `-u` (unmount) flags
|
||||
- **Who**: Dom, ClaudeCode
|
||||
- **Why**: Mounts under `$XDG_RUNTIME_DIR/sshfs/<alias>` had to be listed and
|
||||
torn down with `ls` and `fusermount -u` by hand. A second `sshfsc <alias>`
|
||||
call only prints `!!! Already mounted` and exits, so the tool gave no first-
|
||||
class way to undo what it set up. `-l` and `-u` close that gap without
|
||||
changing the default mount flow.
|
||||
- **Tradeoffs**:
|
||||
- Flag-based UX over subcommands keeps the existing `-e`/`-v`/`-r` style.
|
||||
`-l` and `-u` are mutually exclusive (exit 2 when both passed). `-u` reuses
|
||||
the positional `<Host>` argument; no separate value flag needed.
|
||||
- `-l` only lists *real* mounts (verified via `mountinfo.Mounted`). Stale
|
||||
empty dirs left behind by failed mounts are silently filtered, not
|
||||
surfaced — keeps the output a true list of teardownable targets. Cleanup
|
||||
of stale dirs is not implemented; tmpfs reclaims them on logout.
|
||||
- `-u` shells out to `fusermount -u` and best-effort `os.Remove`s the empty
|
||||
mount dir afterwards. A failed `Remove` warns but does not fail the
|
||||
command — the unmount itself already succeeded.
|
||||
- `mount_base(create bool)` returns `fs.ErrNotExist` when `create=false` and
|
||||
the base is missing. `list_mounts` swallows that into "no mounts";
|
||||
`unmount_sshfs` translates it into `not mounted: <alias>` so the caller
|
||||
sees a single coherent error regardless of whether the alias-dir, the
|
||||
base, or `XDG_RUNTIME_DIR` was missing.
|
||||
- **How**:
|
||||
- `verify_mount_dir` split into `mount_base(create bool)` (XDG resolve +
|
||||
optional mkdir + EvalSymlinks) and `mount_path(base, name)` (join +
|
||||
traversal + symlink guard, no mkdir). The original `verify_mount_dir`
|
||||
becomes a thin wrapper that composes both and creates the mountpoint —
|
||||
only the mount path needs that mkdir.
|
||||
- `list_mounts(io.Writer)` reads the base dir, runs `mountinfo.Mounted` per
|
||||
entry, prints alias names that pass. Takes a writer so tests can capture
|
||||
output without stdout redirection.
|
||||
- `unmount_sshfs(alias)` validates against `rxHostUser`, resolves the
|
||||
mountpoint, checks `mountinfo.Mounted`, then `exec.Command("fusermount",
|
||||
"-u", mount).Run()` and `os.Remove(mount)`.
|
||||
- `main()` flow: after `flag.Parse()`, branch on `*lFlag` / `*uFlag` before
|
||||
the existing mount path. Mutex check up front. Exit codes 8 (list) and 9
|
||||
(unmount) extend the existing 2..7 range.
|
||||
- Tests: `TestListMountsMissingBase`, `TestListMountsFiltersUnmounted`,
|
||||
`TestUnmountRejectsBadAlias`, `TestUnmountNotMountedMissingBase`,
|
||||
`TestUnmountNotMountedExistingDir`. The real `fusermount` path is not
|
||||
exercised in unit tests — the not-mounted check returns before the exec.
|
||||
|
||||
## 2026-04-28 – Move mount base from `~/Servers/` to `$XDG_RUNTIME_DIR/sshfs/`
|
||||
- **Who**: Dom, ClaudeCode
|
||||
- **Why**: `~/Servers/` is non-standard. XDG Base Directory spec defines
|
||||
|
||||
Reference in New Issue
Block a user