Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/pkg/autostart/managers.go
2609 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
// Package autostart manage start at login unit files for darwin/linux
5
package autostart
6
7
import (
8
"context"
9
"errors"
10
"fmt"
11
"os"
12
"path/filepath"
13
"runtime"
14
15
"github.com/lima-vm/lima/v2/pkg/limatype"
16
"github.com/lima-vm/lima/v2/pkg/textutil"
17
)
18
19
type notSupportedManager struct{}
20
21
var _ autoStartManager = (*notSupportedManager)(nil)
22
23
var ErrNotSupported = fmt.Errorf("autostart is not supported on %s", runtime.GOOS)
24
25
func (*notSupportedManager) IsRegistered(_ context.Context, _ *limatype.Instance) (bool, error) {
26
return false, ErrNotSupported
27
}
28
29
func (*notSupportedManager) RegisterToStartAtLogin(_ context.Context, _ *limatype.Instance) error {
30
return ErrNotSupported
31
}
32
33
func (*notSupportedManager) UnregisterFromStartAtLogin(_ context.Context, _ *limatype.Instance) error {
34
return ErrNotSupported
35
}
36
37
func (*notSupportedManager) AutoStartedIdentifier() string {
38
return ""
39
}
40
41
func (*notSupportedManager) RequestStart(_ context.Context, _ *limatype.Instance) error {
42
return ErrNotSupported
43
}
44
45
func (*notSupportedManager) RequestStop(_ context.Context, _ *limatype.Instance) (bool, error) {
46
return false, ErrNotSupported
47
}
48
49
// TemplateFileBasedManager is an autostart manager that uses a template file to create the autostart entry.
50
type TemplateFileBasedManager struct {
51
enabler func(ctx context.Context, enable bool, instName string) error
52
filePath func(instName string) string
53
template string
54
autoStartedIdentifier func() string
55
requestStart func(ctx context.Context, inst *limatype.Instance) error
56
requestStop func(ctx context.Context, inst *limatype.Instance) (bool, error)
57
}
58
59
var _ autoStartManager = (*TemplateFileBasedManager)(nil)
60
61
func (t *TemplateFileBasedManager) IsRegistered(_ context.Context, inst *limatype.Instance) (bool, error) {
62
if t.filePath == nil {
63
return false, errors.New("no filePath function available")
64
}
65
autostartFilePath := t.filePath(inst.Name)
66
if _, err := os.Stat(autostartFilePath); err != nil {
67
if os.IsNotExist(err) {
68
return false, nil
69
}
70
return false, err
71
}
72
return true, nil
73
}
74
75
func (t *TemplateFileBasedManager) RegisterToStartAtLogin(ctx context.Context, inst *limatype.Instance) error {
76
if _, err := t.IsRegistered(ctx, inst); err != nil {
77
return fmt.Errorf("failed to check if the autostart entry for instance %q is registered: %w", inst.Name, err)
78
}
79
content, err := t.renderTemplate(inst.Name, inst.Dir, os.Executable)
80
if err != nil {
81
return fmt.Errorf("failed to render the autostart entry for instance %q: %w", inst.Name, err)
82
}
83
entryFilePath := t.filePath(inst.Name)
84
if err := os.MkdirAll(filepath.Dir(entryFilePath), os.ModePerm); err != nil {
85
return fmt.Errorf("failed to create the directory for the autostart entry for instance %q: %w", inst.Name, err)
86
}
87
if err := os.WriteFile(entryFilePath, content, 0o644); err != nil {
88
return fmt.Errorf("failed to write the autostart entry for instance %q: %w", inst.Name, err)
89
}
90
if t.enabler != nil {
91
return t.enabler(ctx, true, inst.Name)
92
}
93
return nil
94
}
95
96
func (t *TemplateFileBasedManager) UnregisterFromStartAtLogin(ctx context.Context, inst *limatype.Instance) error {
97
if registered, err := t.IsRegistered(ctx, inst); err != nil {
98
return fmt.Errorf("failed to check if the autostart entry for instance %q is registered: %w", inst.Name, err)
99
} else if !registered {
100
return nil
101
}
102
if t.enabler != nil {
103
if err := t.enabler(ctx, false, inst.Name); err != nil {
104
return fmt.Errorf("failed to disable the autostart entry for instance %q: %w", inst.Name, err)
105
}
106
}
107
if err := os.Remove(t.filePath(inst.Name)); err != nil {
108
return fmt.Errorf("failed to remove the autostart entry for instance %q: %w", inst.Name, err)
109
}
110
return nil
111
}
112
113
func (t *TemplateFileBasedManager) renderTemplate(instName, workDir string, getExecutable func() (string, error)) ([]byte, error) {
114
if t.template == "" {
115
return nil, errors.New("no template available")
116
}
117
selfExeAbs, err := getExecutable()
118
if err != nil {
119
return nil, err
120
}
121
return textutil.ExecuteTemplate(
122
t.template,
123
map[string]string{
124
"Binary": selfExeAbs,
125
"Instance": instName,
126
"WorkDir": workDir,
127
})
128
}
129
130
func (t *TemplateFileBasedManager) AutoStartedIdentifier() string {
131
if t.autoStartedIdentifier != nil {
132
return t.autoStartedIdentifier()
133
}
134
return ""
135
}
136
137
func (t *TemplateFileBasedManager) RequestStart(ctx context.Context, inst *limatype.Instance) error {
138
if t.requestStart == nil {
139
return errors.New("no RequestStart function available")
140
}
141
return t.requestStart(ctx, inst)
142
}
143
144
func (t *TemplateFileBasedManager) RequestStop(ctx context.Context, inst *limatype.Instance) (bool, error) {
145
if t.requestStop == nil {
146
return false, errors.New("no RequestStop function available")
147
}
148
return t.requestStop(ctx, inst)
149
}
150
151