@@ -6,118 +6,41 @@ package autostart
66
77import (
88 "context"
9- _ "embed"
10- "errors"
11- "fmt"
12- "os"
13- "os/exec"
14- "path"
15- "path/filepath"
16- "strconv"
17- "strings"
9+ "runtime"
10+ "sync"
1811
19- "github.com/lima-vm/lima/v2/pkg/textutil "
12+ "github.com/lima-vm/lima/v2/pkg/limatype "
2013)
2114
22- 23- var systemdTemplate string
24-
25- //go:embed io.lima-vm.autostart.INSTANCE.plist
26- var launchdTemplate string
27-
28- // CreateStartAtLoginEntry respect host OS arch and create unit file.
29- func CreateStartAtLoginEntry (ctx context.Context , hostOS , instName , workDir string ) error {
30- unitPath := GetFilePath (hostOS , instName )
31- if _ , err := os .Stat (unitPath ); err != nil && ! errors .Is (err , os .ErrNotExist ) {
32- return err
33- }
34- tmpl , err := renderTemplate (hostOS , instName , workDir , os .Executable )
35- if err != nil {
36- return err
37- }
38- if err := os .MkdirAll (filepath .Dir (unitPath ), os .ModePerm ); err != nil {
39- return err
40- }
41- if err := os .WriteFile (unitPath , tmpl , 0o644 ); err != nil {
42- return err
43- }
44- return enableDisableService (ctx , "enable" , hostOS , GetFilePath (hostOS , instName ))
15+ // IsRegistered checks if the instance is registered to start at login.
16+ func IsRegistered (ctx context.Context , inst * limatype.Instance ) (bool , error ) {
17+ return manager ().IsRegistered (ctx , inst )
4518}
4619
47- // DeleteStartAtLoginEntry respect host OS arch and delete unit file.
48- // Return true, nil if unit file has been deleted.
49- func DeleteStartAtLoginEntry (ctx context.Context , hostOS , instName string ) (bool , error ) {
50- unitPath := GetFilePath (hostOS , instName )
51- if _ , err := os .Stat (unitPath ); err != nil {
52- return false , err
53- }
54- if err := enableDisableService (ctx , "disable" , hostOS , GetFilePath (hostOS , instName )); err != nil {
55- return false , err
56- }
57- if err := os .Remove (unitPath ); err != nil {
58- return false , err
59- }
60- return true , nil
20+ // RegisterToStartAtLogin creates a start-at-login entry for the instance.
21+ func RegisterToStartAtLogin (ctx context.Context , inst * limatype.Instance ) error {
22+ return manager ().RegisterToStartAtLogin (ctx , inst )
6123}
6224
63- // GetFilePath returns the path to autostart file with respect of host.
64- func GetFilePath (hostOS , instName string ) string {
65- var fileTmpl string
66- if hostOS == "darwin" { // launchd plist
67- fileTmpl = fmt .Sprintf ("%s/Library/LaunchAgents/io.lima-vm.autostart.%s.plist" , os .Getenv ("HOME" ), instName )
68- }
69- if hostOS == "linux" { // systemd service
70- // Use instance name as argument to systemd service
71- // Instance name available in unit file as %i
72- xdgConfigHome := os .Getenv ("XDG_CONFIG_HOME" )
73- if xdgConfigHome == "" {
74- xdgConfigHome = filepath .Join (os .Getenv ("HOME" ), ".config" )
75- }
76- fileTmpl = fmt .Sprintf ("%s/systemd/user/lima-vm@%s.service" , xdgConfigHome , instName )
77- }
78- return fileTmpl
25+ // UnregisterFromStartAtLogin deletes the start-at-login entry for the instance.
26+ func UnregisterFromStartAtLogin (ctx context.Context , inst * limatype.Instance ) error {
27+ return manager ().UnregisterFromStartAtLogin (ctx , inst )
7928}
8029
81- func enableDisableService (ctx context.Context , action , hostOS , serviceWithPath string ) error {
82- // Get filename without extension
83- filename := strings .TrimSuffix (path .Base (serviceWithPath ), filepath .Ext (path .Base (serviceWithPath )))
84-
85- var args []string
86- if hostOS == "darwin" {
87- // man launchctl
88- args = append (args , []string {
89- "launchctl" ,
90- action ,
91- fmt .Sprintf ("gui/%s/%s" , strconv .Itoa (os .Getuid ()), filename ),
92- }... )
93- } else {
94- args = append (args , []string {
95- "systemctl" ,
96- "--user" ,
97- action ,
98- filename ,
99- }... )
100- }
101- cmd := exec .CommandContext (ctx , args [0 ], args [1 :]... )
102- cmd .Stdout = os .Stdout
103- cmd .Stderr = os .Stderr
104- return cmd .Run ()
30+ type autoStartManager interface {
31+ // Registration
32+ IsRegistered (ctx context.Context , inst * limatype.Instance ) (bool , error )
33+ RegisterToStartAtLogin (ctx context.Context , inst * limatype.Instance ) error
34+ UnregisterFromStartAtLogin (ctx context.Context , inst * limatype.Instance ) error
10535}
10636
107- func renderTemplate ( hostOS , instName , workDir string , getExecutable func () ( string , error )) ([] byte , error ) {
108- selfExeAbs , err := getExecutable ()
109- if err != nil {
110- return nil , err
111- }
112- tmpToExecute := systemdTemplate
113- if hostOS == "darwin" {
114- tmpToExecute = launchdTemplate
37+ var manager = sync . OnceValue ( func () autoStartManager {
38+ switch runtime . GOOS {
39+ case "darwin" :
40+ return Launchd
41+ case "linux" :
42+ return Systemd
43+ default :
44+ return & notSupportedManager {}
11545 }
116- return textutil .ExecuteTemplate (
117- tmpToExecute ,
118- map [string ]string {
119- "Binary" : selfExeAbs ,
120- "Instance" : instName ,
121- "WorkDir" : workDir ,
122- })
123- }
46+ })
0 commit comments