@@ -130,11 +130,19 @@ func Install(exec executor.Executor, log *progress.Logger) error {
130130
131131 log .Debug ("launchd install: plist=%q log_dir=%q interval=%ds user_home=%q is_root=%v" , plistPath , logDir , intervalSeconds , userHome , exec .IsRoot ())
132132
133- // Load plist
134- _ , _ , exitCode , err := exec .Run (ctx , "launchctl" , "load" , plistPath )
135- log .Debug ("launchctl load %q: exit_code=%d err=%v" , plistPath , exitCode , err )
133+ // Bootstrap plist into its launchd domain. Apple actively recommends
134+ // `bootstrap`/`bootout` over the older `load`/`unload` verbs, which
135+ // are on the path to deprecation. Root daemons live in the `system`
136+ // domain; user LaunchAgents in `gui/<uid>`. Available since macOS
137+ // 10.11, so every machine we target supports it.
138+ domain := "system"
139+ if ! exec .IsRoot () {
140+ domain = fmt .Sprintf ("gui/%d" , os .Getuid ())
141+ }
142+ _ , _ , exitCode , err := exec .Run (ctx , "launchctl" , "bootstrap" , domain , plistPath )
143+ log .Debug ("launchctl bootstrap %q %q: exit_code=%d err=%v" , domain , plistPath , exitCode , err )
136144 if err != nil || exitCode != 0 {
137- return fmt .Errorf ("failed to load launchd configuration" )
145+ return fmt .Errorf ("failed to bootstrap launchd configuration" )
138146 }
139147
140148 log .Progress ("launchd configuration completed successfully" )
@@ -164,11 +172,18 @@ func doUninstall(ctx context.Context, exec executor.Executor, log *progress.Logg
164172 plistPath = agentPlistPath ()
165173 }
166174
167- // Unload
175+ // Bootout. `bootout` removes a service from its domain regardless of
176+ // how it was originally added, so it works on plists previously
177+ // `launchctl load`-ed by older agent versions during upgrade.
168178 stdout , _ , _ , _ := exec .Run (ctx , "launchctl" , "list" )
169179 if strings .Contains (stdout , label ) {
170- _ , _ , exitCode , err := exec .Run (ctx , "launchctl" , "unload" , plistPath )
171- log .Debug ("launchctl unload %q: exit_code=%d err=%v" , plistPath , exitCode , err )
180+ domain := "system"
181+ if ! exec .IsRoot () {
182+ domain = fmt .Sprintf ("gui/%d" , os .Getuid ())
183+ }
184+ target := domain + "/" + label
185+ _ , _ , exitCode , err := exec .Run (ctx , "launchctl" , "bootout" , target )
186+ log .Debug ("launchctl bootout %q: exit_code=%d err=%v" , target , exitCode , err )
172187 log .Progress ("Unloaded launchd agent" )
173188 }
174189
0 commit comments