service

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 9, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package service installs and removes the flue login service: a launchd agent on darwin, a systemd user unit on linux. It is self-contained — cmd/flue consumes it and nothing else does — and every interaction with a real service manager goes through the Runner seam so tests never touch one.

Index

Constants

View Source
const LaunchdLabel = "sh.flue.daemon"

LaunchdLabel is the launchd service label and the plist's basename.

Variables

View Source
var ErrNoUserManager = errors.New("service: systemd user services are not available here (no user manager — common on WSL)")

ErrNoUserManager reports that systemctl --user has nobody to talk to — the common WSL shape. The CLI turns this into a one-line pointer at `flue serve`; it is never a stack trace.

View Source
var ErrUnsupported = errors.New("service: no login-service support on this platform")

ErrUnsupported reports a platform with no login-service support. flue ships darwin and linux; WSL is linux with, usually, no user manager — which is ErrNoUserManager at Enable time, not this.

Functions

func LaunchdPlist

func LaunchdPlist(exe string) []byte

LaunchdPlist renders the launchd agent plist that runs `exe serve` at login. exe is the path os.Executable reports, symlinks left intact — for a brew cask install that is the stable /opt/homebrew/bin/flue symlink, not the version-pinned Caskroom target that `brew upgrade` deletes.

func SystemdUnit

func SystemdUnit(exe string) []byte

SystemdUnit renders the systemd user unit that runs `exe serve` at login. The path is double-quoted for systemd's ExecStart lexer, and % is doubled because ExecStart expands specifiers.

Types

type ExecRunner

type ExecRunner struct{}

ExecRunner is the production Runner.

func (ExecRunner) Run

func (ExecRunner) Run(name string, args ...string) ([]byte, error)

type Launchd

type Launchd struct {
	// contains filtered or unexported fields
}

Launchd manages the login service through launchctl on darwin.

func NewLaunchd

func NewLaunchd(exe, home string, uid int, r Runner) *Launchd

func (*Launchd) Disable

func (l *Launchd) Disable() error

Disable boots the agent out and removes the plist. Both halves tolerate absence: a bootout of an unloaded label and a remove of a missing file are what "already disabled" looks like, and that is a success.

func (*Launchd) Enable

func (l *Launchd) Enable() error

Enable writes the plist and bootstraps it — the modern spelling, not `launchctl load`. When the label is already bootstrapped, bootstrap refuses; whether that is convergence depends on whether the plist just changed. launchd reads a plist only at bootstrap, so a loaded job keeps its old definition no matter what Enable writes to disk: when the render differs from what was there (a new binary path after an upgrade), Enable must bootout the stale job and bootstrap the fresh plist — restarting the daemon on purpose, because the old job would exec a path that may no longer exist. When the plist is byte-identical, the loaded job already matches, so Enable only verifies the label is loaded (print) and kickstarts it in case it is dead. kickstart without -k never restarts a running service, which is what keeps a no-op re-run of flue enable from killing live sessions.

func (*Launchd) Status

func (l *Launchd) Status() (Status, error)

type Manager

type Manager interface {
	Enable() error
	Disable() error
	Status() (Status, error)
}

Manager installs, removes, and inspects the flue login service.

  • Enable converges: it rewrites the unit if it drifted, loads it if it is not loaded, and starts it if it is dead — without restarting a healthy daemon, whose sessions must survive a re-run of flue enable.
  • Disable is idempotent: disabling what is not enabled is nil.

func ForPlatform

func ForPlatform(goos, exe, home string, uid int, r Runner) (Manager, error)

ForPlatform picks the implementation for goos. It takes goos as a parameter rather than reading runtime.GOOS so both arms are testable on any host.

type Runner

type Runner interface {
	Run(name string, args ...string) ([]byte, error)
}

Runner executes one service-manager command and returns its combined output. It exists so the command flows are testable against a fake and so CI never touches a real launchd or systemd.

type Status

type Status struct {
	Installed bool // the unit file is on disk
	Running   bool // the service manager reports it alive
}

Status reports the login service's two independent facts.

type Systemd

type Systemd struct {
	// contains filtered or unexported fields
}

Systemd manages the login service through systemctl --user on linux.

func NewSystemd

func NewSystemd(exe, home string, r Runner) *Systemd

func (*Systemd) Disable

func (s *Systemd) Disable() error

Disable stops and disables the unit, removes the file, and reloads. Every systemctl failure is tolerated: on a machine with no user manager the file removal is the whole operation, and "already disabled" is a success.

Lingering is deliberately left as Enable set it. It is a per-user fact, not a per-service one — the user may linger for reasons that have nothing to do with flue — and disable-linger here would stop their other user services at logout. Removing the unit already means flue no longer runs.

func (*Systemd) Enable

func (s *Systemd) Enable() error

Enable writes the unit, reloads, and runs the spec's exact command: `systemctl --user enable --now flue`. Rewriting the unit unconditionally is what converges drift; enable --now starts the service only when it is not already active, so a healthy daemon is never restarted.

func (*Systemd) Status

func (s *Systemd) Status() (Status, error)

func (*Systemd) Warnings

func (s *Systemd) Warnings() []string

Warnings reports the advisories from the most recent Enable.

type Warner

type Warner interface {
	Warnings() []string
}

Warner is optionally implemented by a Manager whose Enable can succeed while still owing the user a fact. Warnings reports advisories from the most recent Enable — true and unfortunate but not failures, like loginctl enable-linger being refused in a container, where the service works while logged in and dies at the last logout. Launchd never warns, so it does not implement this; the CLI upgrades with a type assertion.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL