forked from keybase/go-updater
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathupdater.go
136 lines (114 loc) · 3.52 KB
/
updater.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
// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.
package updater
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/keys-pub/updater/util"
"github.com/pkg/errors"
)
// Version is the updater version
const Version = "0.2.3"
// Updater knows how to find and apply updates
type Updater struct {
source UpdateSource
}
// UpdateSource defines where the updater can find updates
type UpdateSource interface {
// Description is a short description about the update source
Description() string
// FindUpdate finds an update given options
FindUpdate(options UpdateOptions) (*Update, error)
}
// NewUpdater constructs an Updater
func NewUpdater(source UpdateSource) *Updater {
return &Updater{
source: source,
}
}
// Download an update.
// If downloaded update.Asset.LocalPath is set to downloaded path.
func (u *Updater) Download(update *Update, options UpdateOptions) error {
// Linux updates don't have assets so it's ok to prompt for update above before
// we check for nil asset.
if update.Asset == nil || update.Asset.URL == "" {
logger.Infof("No update asset to apply")
return nil
}
tmpDir := tempDir(options.AppName)
if err := u.downloadAsset(update.Asset, tmpDir, options); err != nil {
return err
}
return nil
}
// downloadAsset will download the update to a temporary path (if not cached),
// check the digest, and set the LocalPath property on the asset.
func (u *Updater) downloadAsset(asset *Asset, tmpDir string, options UpdateOptions) error {
if asset == nil {
return fmt.Errorf("No asset to download")
}
var digestType util.DigestType
switch asset.DigestType {
case "", "sha256":
digestType = util.SHA256
case "sha512":
digestType = util.SHA512
default:
return errors.Errorf("Unsupported digest type: %s", asset.DigestType)
}
downloadOptions := util.DownloadURLOptions{
Digest: asset.Digest,
DigestType: digestType,
UseETag: true,
}
downloadPath := filepath.Join(tmpDir, asset.Name)
// If asset had a file extension, lets add it back on
if err := util.DownloadURL(asset.URL, downloadPath, downloadOptions); err != nil {
return err
}
asset.LocalPath = downloadPath
return nil
}
// CheckForUpdate checks a update source for an update.
func (u *Updater) CheckForUpdate(options UpdateOptions) (*Update, error) {
logger.Infof("Checking for update, current version is %s", options.Version)
logger.Infof("Using updater source: %s", u.source.Description())
logger.Debugf("Using options: %#v", options)
update, findErr := u.source.FindUpdate(options)
if findErr != nil {
return nil, findErr
}
if update == nil {
return nil, nil
}
return update, nil
}
func tempDir(appName string) string {
return filepath.Join(os.TempDir(), "updater", appName)
}
// Cleanup files, except for a path (presumably the update).
// You can do this after you download an update, so that if the update already
// exists it doesn't have to be re-downloaded, which removes all other files
// except the current update.
func Cleanup(appName string, except string) {
dir := tempDir(appName)
files, err := ioutil.ReadDir(dir)
if err != nil {
logger.Errorf("Error listing temp dir: %v", err)
return
}
exceptBase := filepath.Base(except)
logger.Infof("Cleanup files (except=%s)...", exceptBase)
for _, file := range files {
name := file.Name()
if name != exceptBase {
logger.Infof("Cleanup, removing %s", name)
if err := os.RemoveAll(name); err != nil {
logger.Errorf("Error removing %s: %v", file, err)
return
}
}
}
}