-
Notifications
You must be signed in to change notification settings - Fork 1
/
upgrade.go
175 lines (153 loc) · 5.11 KB
/
upgrade.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
// Copyright (c) 2013-2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"io"
"os"
"path/filepath"
)
// dirEmpty returns whether or not the specified directory path is empty.
func dirEmpty(dirPath string) (bool, error) {
f, err := os.Open(dirPath)
if err != nil {
return false, err
}
defer f.Close()
// Read the names of a max of one entry from the directory. When the
// directory is empty, an io.EOF error will be returned, so allow it.
names, err := f.Readdirnames(1)
if err != nil && err != io.EOF {
return false, err
}
return len(names) == 0, nil
}
// oldBchdHomeDir returns the OS specific home directory bchd used prior to
// version 0.3.3. This has since been replaced with bchutil.AppDataDir, but
// this function is still provided for the automatic upgrade path.
func oldBchdHomeDir() string {
// Search for Windows APPDATA first. This won't exist on POSIX OSes.
appData := os.Getenv("APPDATA")
if appData != "" {
return filepath.Join(appData, "bchd")
}
// Fall back to standard HOME directory that works for most POSIX OSes.
home := os.Getenv("HOME")
if home != "" {
return filepath.Join(home, ".bchd")
}
// In the worst case, use the current directory.
return "."
}
// upgradeDBPathNet moves the database for a specific network from its
// location prior to bchd version 0.2.0 and uses heuristics to ascertain the old
// database type to rename to the new format.
func upgradeDBPathNet(oldDbPath, netName string) error {
// Prior to version 0.2.0, the database was named the same thing for
// both sqlite and leveldb. Use heuristics to figure out the type
// of the database and move it to the new path and name introduced with
// version 0.2.0 accordingly.
fi, err := os.Stat(oldDbPath)
if err == nil {
oldDbType := "sqlite"
if fi.IsDir() {
oldDbType = "leveldb"
}
// The new database name is based on the database type and
// resides in a directory named after the network type.
newDbRoot := filepath.Join(filepath.Dir(cfg.DataDir), netName)
newDbName := blockDbNamePrefix + "_" + oldDbType
if oldDbType == "sqlite" {
newDbName = newDbName + ".db"
}
newDbPath := filepath.Join(newDbRoot, newDbName)
// Create the new path if needed.
err = os.MkdirAll(newDbRoot, 0700)
if err != nil {
return err
}
// Move and rename the old database.
err := os.Rename(oldDbPath, newDbPath)
if err != nil {
return err
}
}
return nil
}
// upgradeDBPaths moves the databases from their locations prior to bchd
// version 0.2.0 to their new locations.
func upgradeDBPaths() error {
// Prior to version 0.2.0, the databases were in the "db" directory and
// their names were suffixed by "testnet" and "regtest" for their
// respective networks. Check for the old database and update it to the
// new path introduced with version 0.2.0 accordingly.
oldDbRoot := filepath.Join(oldBchdHomeDir(), "db")
upgradeDBPathNet(filepath.Join(oldDbRoot, "bchd.db"), "mainnet")
upgradeDBPathNet(filepath.Join(oldDbRoot, "bchd_testnet.db"), "testnet")
upgradeDBPathNet(filepath.Join(oldDbRoot, "bchd_regtest.db"), "regtest")
// Remove the old db directory.
return os.RemoveAll(oldDbRoot)
}
// upgradeDataPaths moves the application data from its location prior to bchd
// version 0.3.3 to its new location.
func upgradeDataPaths() error {
// No need to migrate if the old and new home paths are the same.
oldHomePath := oldBchdHomeDir()
newHomePath := defaultHomeDir
if oldHomePath == newHomePath {
return nil
}
// Only migrate if the old path exists and the new one doesn't.
if fileExists(oldHomePath) && !fileExists(newHomePath) {
// Create the new path.
bchdLog.Infof("Migrating application home path from '%s' to '%s'",
oldHomePath, newHomePath)
err := os.MkdirAll(newHomePath, 0700)
if err != nil {
return err
}
// Move old bchd.conf into new location if needed.
oldConfPath := filepath.Join(oldHomePath, defaultConfigFilename)
newConfPath := filepath.Join(newHomePath, defaultConfigFilename)
if fileExists(oldConfPath) && !fileExists(newConfPath) {
err := os.Rename(oldConfPath, newConfPath)
if err != nil {
return err
}
}
// Move old data directory into new location if needed.
oldDataPath := filepath.Join(oldHomePath, defaultDataDirname)
newDataPath := filepath.Join(newHomePath, defaultDataDirname)
if fileExists(oldDataPath) && !fileExists(newDataPath) {
err := os.Rename(oldDataPath, newDataPath)
if err != nil {
return err
}
}
// Remove the old home if it is empty or show a warning if not.
ohpEmpty, err := dirEmpty(oldHomePath)
if err != nil {
return err
}
if ohpEmpty {
err := os.Remove(oldHomePath)
if err != nil {
return err
}
} else {
bchdLog.Warnf("Not removing '%s' since it contains files "+
"not created by this application. You may "+
"want to manually move them or delete them.",
oldHomePath)
}
}
return nil
}
// doUpgrades performs upgrades to bchd as new versions require it.
func doUpgrades() error {
err := upgradeDBPaths()
if err != nil {
return err
}
return upgradeDataPaths()
}