Documentation
¶
Overview ¶
Package startup manages user-scoped autostart entries created by gitmap on the host OS:
- Linux/Unix: XDG `.desktop` files in `$XDG_CONFIG_HOME/autostart/` (or `$HOME/.config/autostart/`) carrying the `X-Gitmap-Managed=true` key.
- macOS: LaunchAgent `.plist` files in `~/Library/LaunchAgents/` carrying a top-level `<key>XGitmapManaged</key><true/>` marker.
On both OSes, List enumerates ONLY entries that satisfy BOTH the filename prefix gate AND the in-file marker; Remove deletes one named entry only after re-confirming it carries the marker. A request to remove a third-party entry becomes a refused no-op, never a deletion.
Windows is intentionally NOT covered by this package — Windows uses Registry `Run` keys / Startup folder shortcuts handled by separate code. The directory resolver returns an error on Windows so the CLI prints the "unsupported OS" message instead of touching a non-existent directory.
macOS LaunchAgent lifecycle (launchctl load/unload) is NOT triggered here — list/remove operate on the .plist file ONLY. A removed plist takes effect at the next login or after a manual `launchctl unload`. This is intentional: invoking launchctl requires a running user GUI session and would make automated uninstall scripts brittle on CI / SSH sessions.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AutostartDir ¶
AutostartDir returns the absolute path to the user's autostart directory for the current OS.
- Linux/Unix: honors $XDG_CONFIG_HOME, falls back to $HOME/.config/autostart per freedesktop.org base-dir spec.
- macOS: $HOME/Library/LaunchAgents (per Apple's LaunchAgents documentation; the user-domain location requires no sudo).
Returns an error on Windows so callers print the platform-specific "unsupported OS" message instead of touching a non-existent dir.
Types ¶
type AddOptions ¶
type AddOptions struct {
// Name is the entry's logical identifier. The on-disk filename
// becomes "gitmap-<Name>.desktop" (prefix added if missing) and
// the listed Name= field in the .desktop body is the same value.
Name string
// Exec is the absolute command line to launch at login. Callers
// MUST pre-quote any path containing spaces (the .desktop spec
// allows quoted strings inside Exec=); we do not parse it.
Exec string
// DisplayName, when non-empty, overrides the value written to
// the Name= field. Empty means "reuse Name verbatim".
DisplayName string
// Comment populates the Comment= field. Optional.
Comment string
// NoDisplay sets NoDisplay=true to hide the entry from desktop
// app menus while still autostarting it — useful for headless
// helpers users don't want cluttering their app drawer.
NoDisplay bool
// Force allows overwriting a previously gitmap-created entry
// with the same name. Has NO effect on third-party files; those
// always refuse.
Force bool
// WorkingDir, when non-empty, sets the process working directory
// for the autostart entry. Rendered as `Path=<dir>` in .desktop
// files (XDG spec field), `WorkingDirectory` in LaunchAgent
// plists, and stored as the `WorkingDir` value of the gitmap
// tracking subkey on Windows (HKCU\Software\Gitmap\Startup*\<name>).
// Callers MUST pass an absolute path; relative paths are accepted
// as-is and interpreted by the OS at login time. Empty means
// "inherit whatever the login session provides".
WorkingDir string
// Backend selects the Windows autostart target (Registry vs
// Startup-folder shortcut). Ignored on Linux/macOS, which each
// have one canonical backend. Zero value (BackendUnspecified)
// means "use the OS default" which is BackendRegistry on
// Windows.
Backend Backend
}
AddOptions captures every knob the runner exposes. Kept as a struct (not positional args) so future fields like Comment, Categories, OnlyShowIn don't keep growing the signature.
type AddResult ¶
AddResult mirrors RemoveResult. Path is the absolute target file for Created / Overwritten / Refused / Exists; empty for BadName.
func Add ¶
func Add(opts AddOptions) (AddResult, error)
Add is the public entry point. Returns (result, nil) for every "soft" outcome; only real I/O failures produce a non-nil error.
OS dispatch:
- linux/unix → writes a `.desktop` file with the X-Gitmap-Managed=true marker into AutostartDir().
- darwin → writes a LaunchAgent `.plist` with the XGitmapManaged <true/> marker into ~/Library/LaunchAgents/.
- windows → routes via opts.Backend (Registry by default, or Startup-folder .lnk shortcut). Both backends share the same managed-marker contract enforced by HKCU\Software\Gitmap tracking subkeys + a sibling marker value next to Run-key entries. See addWindows / winbackend.go for details.
Both OS paths share the same five-status outcome model (Created/Overwritten/Refused/BadName/Exists) and the same "managed-only, never escalate" guard — Force only lifts the "already exists AND is ours" check; a third-party file is NEVER overwritten.
type AddStatus ¶
type AddStatus int
AddStatus tags the four mutually-exclusive Add outcomes. Kept parallel to RemoveStatus so the CLI rendering layer can switch on either with the same shape.
const ( // AddCreated = file did not exist; was written fresh. AddCreated AddStatus = iota // AddOverwritten = previously gitmap-managed file was replaced // because Force was set. AddOverwritten // AddRefused = a non-gitmap-managed file with the same name // already exists; we did NOT touch it. AddRefused // AddBadName = name failed validation (empty / separator / NUL). AddBadName // AddExists = a gitmap-managed file with the same name already // exists and Force was NOT set; nothing was written. AddExists )
type Backend ¶
type Backend int
Backend enumerates the Windows-specific add targets. Linux/macOS have one canonical backend each (XDG .desktop / LaunchAgents .plist) so they ignore this value entirely. The zero value (BackendUnspecified) means "let the dispatcher pick the OS default" which is `BackendRegistry` on Windows.
const ( // BackendUnspecified is the zero value. The dispatcher // translates it to the per-OS default rather than failing — // keeps the public Add(opts) API ergonomic for non-Windows // callers that have no opinion on backend. BackendUnspecified Backend = iota // BackendRegistry writes the HKCU Run-key value + tracking // subkey (per-user; the long-standing default). BackendRegistry // BackendStartupFolder writes the .lnk + tracking subkey. BackendStartupFolder // BackendRegistryHKLM writes the HKLM Run-key value + // tracking subkey (machine-wide; requires admin). Same on- // disk shape as BackendRegistry, just rooted under // HKEY_LOCAL_MACHINE so every interactive user on the // machine triggers the autostart at login. BackendRegistryHKLM )
func ParseBackend ¶
ParseBackend translates the user-facing flag string into the Backend enum. Unknown / empty values from non-Windows callers flow through as BackendUnspecified (the per-OS default); empty values from Windows callers also default to Registry. ONLY a non-empty unrecognized value is an error — that means the user typed something we don't understand and silently defaulting would hide the typo.
type Entry ¶
Entry is one gitmap-managed autostart record. Path is the absolute file path; Name is the basename WITHOUT the platform-specific extension (the form users pass to `startup-remove`); Exec is the command line surfaced so `startup-list` shows what would actually run at login. On macOS, Exec is the space-joined ProgramArguments (or the Program string if ProgramArguments is absent).
func List ¶
List returns every gitmap-managed entry. A MISSING directory / registry key is treated as "zero entries", NOT an error — fresh accounts that have never had any autostart entry shouldn't see a scary error from `gitmap startup-list`. On Windows, enumerates BOTH the Registry Run-key and Startup-folder backends.
type RemoveOptions ¶
type RemoveOptions struct {
// DryRun runs the full classification (existence + marker check)
// but skips the actual os.Remove call. The returned RemoveResult
// has DryRun=true and the Status the live call would have
// produced — letting CLI renderers print "would delete X" with
// the same accuracy as a real run.
DryRun bool
// Backend scopes the removal to a specific Windows backend
// (registry or startup-folder). Zero value (BackendUnspecified)
// preserves legacy behavior: both backends are tried in order
// and the first non-NoOp result wins. Linux and macOS callers
// ignore this field — there's only one backend per OS.
Backend Backend
}
RemoveOptions carries optional knobs for Remove. Kept as a struct (not extra positional args) so future flags like Trash bool or BackupTo string can be added without breaking callers.
type RemoveResult ¶
type RemoveResult struct {
Status RemoveStatus
Path string
DryRun bool
}
RemoveResult tags every Remove outcome so callers can render the right user-facing message without inspecting error text. The path is empty for NotOurs / NoOp / BadName so callers don't accidentally print a path the user can't act on. DryRun reports whether the outcome was simulated (no filesystem mutation) — set when the caller passed RemoveOptions.DryRun=true and the status would otherwise have been RemoveDeleted.
func Remove ¶
func Remove(name string) (RemoveResult, error)
Remove deletes the named gitmap-managed autostart entry. `name` is the basename WITHOUT the platform extension (the same form `List` returns); a trailing platform extension is tolerated so users who copy/paste from `ls` get the same behavior. The extension is `.desktop` on Linux/Unix and `.plist` on macOS.
This is the legacy entry point — equivalent to RemoveWithOptions(name, RemoveOptions{}). New callers that need dry-run semantics should call RemoveWithOptions directly.
func RemoveWithOptions ¶
func RemoveWithOptions(name string, opts RemoveOptions) (RemoveResult, error)
RemoveWithOptions is the full-featured entry point. The dry-run branch reuses every classification check the live branch runs so `--dry-run` cannot disagree with the real command — only the final os.Remove is suppressed.
type RemoveStatus ¶
type RemoveStatus int
RemoveStatus enumerates the four mutually-exclusive outcomes.
const ( // RemoveDeleted = file existed, was gitmap-managed, was unlinked // (or, under DryRun, would have been unlinked). RemoveDeleted RemoveStatus = iota // RemoveNoOp = no file by that name in the autostart dir. RemoveNoOp // RemoveRefused = file exists but is not gitmap-managed. RemoveRefused // RemoveBadName = input failed validation (empty / separator). RemoveBadName )