-
Notifications
You must be signed in to change notification settings - Fork 3
/
install_linux.go
147 lines (136 loc) · 4.41 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
// +build linux
package linux_installer
import (
"errors"
"io/ioutil"
"log"
"os"
"os/exec"
"os/user"
"path/filepath"
"syscall"
"golang.org/x/sys/unix"
)
const (
desktopFileUserDir = ".local/share/applications"
desktopFileSystemDir = "/usr/share/applications"
desktopFilenameTemplate = `{{if .organization_short}}{{.organization_short | lower | replace " " ""}}-{{end}}{{.product | lower | replace " " ""}}.desktop`
desktopFileTemplate = `[Desktop Entry]
Name={{.product}}
Version={{.version}}
Type=Application
Icon={{.installDir}}/{{.icon_file}}
Exec={{.installDir}}/{{.start_command}}
Comment={{.tagline}}
Terminal={{.show_terminal_during_app_run}}
`
)
// osFileWriteAccess returns whether a given path has write access for the current user.
func osFileWriteAccess(path string) bool {
return unix.Access(path, unix.W_OK) == nil
}
// osDiskSpace returns the amount of bytes available to the current user on the
// partition that the given path resides on.
func osDiskSpace(path string) int64 {
fs := unix.Statfs_t{}
if err := unix.Statfs(path, &fs); err != nil {
return -1
}
return int64(fs.Bavail) * fs.Bsize
}
// osCreateLauncherEntry creates an application menu entry for the application being
// installed.
//
// On linux this creates a .desktop file in the users application dir, or—if
// installing as root—in the system-wide application dir.
func osCreateLauncherEntry(variables VariableMap) (desktopFilepath string, err error) {
content := ExpandVariables(desktopFileTemplate, variables)
desktopFilename := ExpandVariables(desktopFilenameTemplate, variables)
usr, err := user.Current()
if err != nil {
return
}
var applicationsDir string
if usr.Uid == "0" {
applicationsDir = desktopFileSystemDir
} else {
applicationsDir = desktopFileUserDir
}
err = os.MkdirAll(filepath.Join(usr.HomeDir, applicationsDir), 0755)
if err != nil {
return
}
desktopFilepath = filepath.Join(usr.HomeDir, applicationsDir, desktopFilename)
err = ioutil.WriteFile(desktopFilepath, []byte(content), 0755)
return
}
// osCreateUninstaller expands the uninstaller template with installed files that were
// installed, and writes the result into a file that removes the installed application
// when executed.
//
// The uninstaller script template(s) are located in the resources/uninstaller/
// directory.
//
// On Linux, this is a simple .sh script with a list of files and directories to be fed
// to rm and rmdir respectively.
func osCreateUninstaller(installedFiles []string, variables VariableMap) error {
uninstallScriptFilepath := filepath.Join(
variables["installDir"], variables["uninstaller_name"]+".sh",
)
uninstallScriptTemplate, err := GetResource("uninstaller/uninstall.sh.template")
if err != nil {
return err
}
installedFiles = append(installedFiles, uninstallScriptFilepath)
content := ExpandAllVariables(
uninstallScriptTemplate,
variables,
UntypedVariableMap{"installedFiles": installedFiles},
)
return ioutil.WriteFile(uninstallScriptFilepath, []byte(content), 0755)
}
// osRunHookIfExists runs a script given its base name (no extension), if that script
// does exist. The hook scripts are located in the resources/hooks/ directory.
// installPath is the installation directory, and the script can expect it as its first
// commandline argument.
//
// On Linux it loads the hook files that end in ".sh".
func osRunHookIfExists(scriptFile string, installPath string) error {
if _, err := os.Stat(scriptFile + ".sh"); os.IsNotExist(err) {
return nil
}
err := os.Chmod(scriptFile+".sh", 0755)
out, err := exec.Command("/bin/sh", scriptFile+".sh", installPath).CombinedOutput()
log.Println("hook output:\n", string(out[:]))
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
return errors.New(string(exitErr.Stderr))
} else {
return err
}
}
return err
}
// osShowRawErrorDialog tries to show a graphical error dialog in case the main GUI
// fails to load. If that fails too, an error is returned.
//
// On Linux it tries to run a Zenity command.
func osShowRawErrorDialog(message string) (err error) {
_, err = exec.Command(
"zenity",
"--error",
"--title", "error",
"--no-wrap",
"--text", message,
).CombinedOutput()
return
}
// osExecVE runs cmd with the given args, replaces the current process and never
// returns.
func osExecVE(cmd string, args []string) {
err := syscall.Exec(cmd, args, os.Environ())
if err != nil {
log.Println("execve error:", err.Error())
os.Exit(1)
}
}