-
Notifications
You must be signed in to change notification settings - Fork 2
/
update.go
160 lines (134 loc) · 3.48 KB
/
update.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
package main
import (
"os"
"io"
"io/ioutil"
"http"
"fmt"
"strings"
"path"
"exec"
)
/*
Various URLs used for automatically updating.
*/
const (
currentVersionUrl = "http://github.com/hgp/Go2Lunch/raw/master/VERSION"
downloadUrl = "http://github.com/downloads/hgp/Go2Lunch/lunch_"
updateScriptUrl = "http://github.com/hgp/Go2Lunch/raw/master/update_client.sh"
)
func getCurrentVersion() (string, os.Error) {
res, _, err := http.Get(currentVersionUrl)
if err != nil {
return "", err
}
fmt.Println("1")
if res.StatusCode != 200 {
return "", os.NewError(fmt.Sprint("Could not check current version. Status code from server: ", res.StatusCode))
}
fmt.Println("2")
buf, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", err
}
fmt.Println("3")
res.Body.Close()
fmt.Println("4")
return strings.TrimSpace(fmt.Sprintf("%s", buf)), nil
}
func needsUpdate() (result bool, currentVersion string, err os.Error) {
currentVersion, err = getCurrentVersion()
if err != nil {
return
}
result = currentVersion != clientVersion
return
}
func findLunch() (result string) {
argPath := os.Args[0]
result, _ = exec.LookPath(argPath)
if !path.IsAbs(result) {
// LookPath didn't find it, and the path isn't absolute, so put it relative to the current directory
pwd, _ := os.Getwd()
result = path.Join(pwd, path.Clean(argPath))
}
return
}
func downloadTempFile(url string, prefix string) (path string, err os.Error) {
res, _, err := http.Get(url)
if err != nil {
return
}
defer res.Body.Close()
if res.StatusCode != 200 {
return "", os.NewError("Could not download file. Status code from server: " + string(res.StatusCode))
}
dest, err := ioutil.TempFile("", prefix)
if err != nil {
return
}
defer dest.Close()
_, err = io.Copy(dest, res.Body)
if err != nil {
return
}
return dest.Name(), nil
}
func downloadUpdateScript() (path string, err os.Error) {
fmt.Println("downloadUpdateScript()")
path, err = downloadTempFile(updateScriptUrl, "update_lunch")
if err != nil {
return
}
err = os.Chmod(path, 0700)
return
}
func downloadNewVersion(version string) (path string, err os.Error) {
return downloadTempFile(downloadUrl+version, "lunch")
}
func runUpdateScript(scriptPath, oldPath, newPath string) (err os.Error) {
_, err = os.ForkExec(scriptPath, []string{scriptPath, oldPath, newPath}, os.Envs, "", []*os.File{os.Stdin, os.Stdout, os.Stderr})
return
}
func CheckForUpdates() (errChan chan os.Error) {
errChan = make(chan os.Error)
go checkForUpdates(errChan)
return errChan
}
func checkForUpdates(errChan chan os.Error) {
update, version, err := needsUpdate()
if err != nil {
errChan <- err
}
if update {
fmt.Println("An update is available. Would you like to download it? [Y/n] ")
var result string
fmt.Scanln(&result)
fmt.Println()
switch strings.ToLower(result) {
case "", "y":
fmt.Println("Downloading update script...")
scriptPath, err := downloadUpdateScript()
if err != nil {
errChan <- err
}
fmt.Println("Update script downloaded to", scriptPath)
fmt.Println()
fmt.Println("Downloading new version...")
newPath, err := downloadNewVersion(version)
if err != nil {
errChan <- err
}
fmt.Println("New version downloaded to", newPath)
fmt.Println()
fmt.Println("Running update script...")
err = runUpdateScript(scriptPath, findLunch(), newPath)
if err != nil {
errChan <- err
}
// We should have forked the updater by now. We can exit.
os.Exit(0)
}
}
errChan <- nil
}