-
Notifications
You must be signed in to change notification settings - Fork 0
/
install_linux.go
221 lines (195 loc) · 7.32 KB
/
install_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
package main
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"github.com/urfave/cli/v2"
)
const (
binPath = ".local/share/telltail"
startupPath = ".config/systemd/user"
)
func installSync(params installSyncParams) error {
////// Check basic necessities exist
// check if system is x11, https://github.com/atotto/clipboard has ways to indentify it
env := os.Getenv("XDG_SESSION_TYPE")
if env != "x11" {
return cli.Exit("Sync cannot be installed on a non-X11 Linux", exitUnsupportedOsVariant)
}
{
if !cmdExists("systemctl") {
return cli.Exit("We use systemctl/systemd to run services on boot. We cannot proceed if that is not available.", exitMissingDependency)
}
// it'll fail if the systemd config is not present, which is fine as well, no need to panic
// doing this + the fact writing a file overrides the existing one will make the `install` idempotent
cmd := exec.Command("systemctl", "--user", "disable", "telltail-sync", "--now")
cmd.Output()
}
if !cmdExists("xsel") && !cmdExists("xclip") {
return cli.Exit("Please install `xsel` from your package manager first", exitMissingDependency)
} else {
if !cmdExists("xsel") {
fmt.Println("Although you have `xclip` installed, we'd recommend you to install `xsel` from your package manager" +
" (because we've found that reading clipboard's content from `xclip` fails spontaneously).")
}
}
homeDir, err := os.UserHomeDir()
if err != nil {
return cli.Exit("Cannot determine your home folder", exitCannotDetermineUserHomeDir)
}
baseBinLoc := filepath.Join(homeDir, binPath)
////// Download and store clipnotify
{
loc := filepath.Join(baseBinLoc, "clipnotify")
exitCode, err := downloadFile(
"https://github.com/ajitid/clipnotify-for-desktop-os/releases/download/"+version+"/clipnotify-linux-x11-"+runtime.GOARCH,
loc)
if err != nil {
return cli.Exit(err, exitCode)
}
markFileAsExecutableOnUnix(loc)
}
////// Download and store the telltail-sync
// fmt.Println("Downloading files...")
{
loc := filepath.Join(baseBinLoc, "telltail-sync")
exitCode, err := downloadFile(
"https://github.com/ajitid/telltail-sync/releases/download/"+version+"/telltail-sync-linux-"+runtime.GOARCH,
loc)
if err != nil {
return cli.Exit(err, exitCode)
}
markFileAsExecutableOnUnix(loc)
}
////// Put bootup configuration
// fmt.Println("Configuring for it load on boot...")
{
dir := filepath.Join(homeDir, startupPath)
err = os.MkdirAll(dir, os.ModePerm)
if err != nil {
log.Println("Unable to create folder", dir)
return cli.Exit(err, exitDirNotModifiable)
}
tmpl := getSyncSystemdCfgLinuxX11()
f, err := os.Create(filepath.Join(dir, "telltail-sync.service"))
if err != nil {
return cli.Exit("Cannot create service file for systemd", exitFileNotModifiable)
}
defer f.Close()
err = tmpl.Execute(f, syncSystemdCfgLinuxX11Attrs{
Tailnet: params.tailnet,
Device: params.device,
BinDirectory: baseBinLoc,
})
if err != nil {
return cli.Exit("Cannot write to service file for systemd", exitFileNotModifiable)
}
}
////// Start the service
{
cmd := exec.Command("systemctl", "--user", "daemon-reload")
cmd.Output()
cmd = exec.Command("systemctl", "--user", "enable", "telltail-sync", "--now")
cmd.Output()
}
// TODO handle failures:
// systemctl status will give status code 3 if:
// - service is stopped
// - start the service fails
// **Do note that** status code is 3 by telltail-center, not by telltail-sync (as I tested w/ telltail-center). It could be different for Sync.
// so yeah, that ain't a way to distinguish. It also prints logs from journalctl, which we can use though:
// On normal stop:
// Mar 16 14:47:24 sd systemd[2235]: Stopped telltail.service - Telltail server.
// Mar 16 14:47:24 sd systemd[2235]: telltail.service: Consumed 3min 39.217s CPU time.
// On failure stop:
// Mar 16 14:47:31 sd systemd[2235]: telltail.service: Main process exited, code=exited, status=203/EXEC
// Mar 16 14:47:31 sd systemd[2235]: telltail.service: Failed with result 'exit-code'.
//
// We probably could also be able to pass flags and get the active statuses:
// Active: inactive (dead) // normal stop
// Active: failed (Result: exit-code) since Thu 2023-03-16 14:47:31 IST; 4s ago // failure stop
////// Success message
fmt.Println("All done! You can read about the changes we've made on here: https://guide-on.gitbook.io/telltail/changes-done-by-install")
return nil
}
func installCenter(authKey string) error {
{
if !cmdExists("systemctl") {
return cli.Exit("We use systemctl/systemd to run services on boot. We cannot proceed if that is not available.", exitMissingDependency)
}
// it'll fail if the systemd config is not present, which is fine as well, no need to panic
// doing this + the fact writing a file overrides the existing one will make the `install` idempotent
cmd := exec.Command("systemctl", "--user", "disable", "telltail-center", "--now")
cmd.Output()
}
homeDir, err := os.UserHomeDir()
if err != nil {
return cli.Exit("Cannot determine your home folder", exitCannotDetermineUserHomeDir)
}
baseBinLoc := filepath.Join(homeDir, binPath)
{
loc := filepath.Join(baseBinLoc, "telltail-center")
exitCode, err := downloadFile(
"https://github.com/ajitid/telltail-center/releases/download/"+version+"/telltail-center-linux-"+runtime.GOARCH,
loc)
if err != nil {
return cli.Exit(err, exitCode)
}
markFileAsExecutableOnUnix(loc)
}
{
dir := filepath.Join(homeDir, startupPath)
err = os.MkdirAll(dir, os.ModePerm)
if err != nil {
log.Println("Unable to create folder", dir)
return cli.Exit(err, exitDirNotModifiable)
}
tmpl := getCenterSystemdCfgLinux()
f, err := os.Create(filepath.Join(dir, "telltail-center.service"))
if err != nil {
return cli.Exit("Cannot create service file for systemd", exitFileNotModifiable)
}
defer f.Close()
err = tmpl.Execute(f, centerSystemdCfgLinuxAttrs{
BinDirectory: baseBinLoc,
})
if err != nil {
return cli.Exit("Cannot write to service file for systemd", exitFileNotModifiable)
}
}
{
dir := filepath.Join(homeDir, startupPath, "telltail-center.service.d")
err = os.MkdirAll(dir, os.ModePerm)
if err != nil {
log.Println("Unable to create folder", dir)
return cli.Exit(err, exitDirNotModifiable)
}
tmpl := getCenterSystemdOverrideCfgLinux()
f, err := os.Create(filepath.Join(dir, "override.conf"))
if err != nil {
return cli.Exit("Cannot create service override file for systemd", exitFileNotModifiable)
}
defer f.Close()
err = tmpl.Execute(f, centerSystemdOverrideCfgLinuxAttrs{
AuthKey: authKey,
})
if err != nil {
return cli.Exit("Cannot write to service override file for systemd", exitFileNotModifiable)
}
}
{
cmd := exec.Command("systemctl", "--user", "daemon-reload")
cmd.Run()
cmd = exec.Command("systemctl", "--user", "enable", "telltail-center", "--now")
cmd.Run()
}
// write to local override file and tell user to open it and manually enter key there to avoid
// and because they'll have the familiarity, they'll be able to update it as well. Revocation and expiration of key is quite common to happen
// tell them what they can use to change auth key if they need to
////// Success message
fmt.Println("All done! You can read about the changes we've made on here: https://guide-on.gitbook.io/telltail/changes-done-by-install")
return nil
}