forked from jhuckaby/Cronicle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
install.js
executable file
·255 lines (217 loc) · 7.58 KB
/
install.js
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// Cronicle Auto Installer
// Copyright (c) 2015 - 2019 Joseph Huckaby, MIT License.
// https://github.com/jhuckaby/Cronicle
// To install, issue this command as root:
// curl -s "https://raw.githubusercontent.com/jhuckaby/Cronicle/master/bin/install.js" | node
var path = require('path');
var fs = require('fs');
var util = require('util');
var os = require('os');
var cp = require('child_process');
var installer_version = '1.3';
var base_dir = '/opt/cronicle';
var log_dir = base_dir + '/logs';
var log_file = '';
var gh_repo_url = 'http://github.com/jhuckaby/Cronicle';
var gh_releases_url = 'https://api.github.com/repos/jhuckaby/Cronicle/releases';
var gh_head_tarball_url = 'https://github.com/jhuckaby/Cronicle/archive/master.tar.gz';
// don't allow npm to delete these (ugh)
var packages_to_check = ['couchbase', 'aws-sdk', 'redis'];
var packages_to_rescue = {};
var restore_packages = function() {
// restore packages that npm killed during upgrade
var cmd = "npm install";
for (var pkg in packages_to_rescue) {
cmd += ' ' + pkg + '@' + packages_to_rescue[pkg];
}
if (log_file) {
fs.appendFileSync(log_file, "\nExecuting npm command to restore lost packages: " + cmd + "\n");
cmd += ' >>' + log_file + ' 2>&1';
}
cp.execSync(cmd);
};
var print = function(msg) {
process.stdout.write(msg);
if (log_file) fs.appendFileSync(log_file, msg);
};
var warn = function(msg) {
process.stderr.write(msg);
if (log_file) fs.appendFileSync(log_file, msg);
};
var die = function(msg) {
warn( "\nERROR: " + msg.trim() + "\n\n" );
process.exit(1);
};
var logonly = function(msg) {
if (log_file) fs.appendFileSync(log_file, msg);
};
if (process.getuid() != 0) {
die( "The Cronicle auto-installer must be run as root." );
}
// create base and log directories
try { cp.execSync( "mkdir -p " + base_dir + " && chmod 775 " + base_dir ); }
catch (err) { die("Failed to create base directory: " + base_dir + ": " + err); }
try { cp.execSync( "mkdir -p " + log_dir + " && chmod 777 " + log_dir ); }
catch (err) { die("Failed to create log directory: " + log_dir + ": " + err); }
// start logging from this point onward
log_file = log_dir + '/install.log';
logonly( "\nStarting install run: " + (new Date()).toString() + "\n" );
print(
"\nCronicle Installer v" + installer_version + "\n" +
"Copyright (c) 2015 - 2018 PixlCore.com. MIT Licensed.\n" +
"Log File: " + log_file + "\n\n"
);
process.chdir( base_dir );
var is_preinstalled = false;
var cur_version = '';
var new_version = process.argv[2] || '';
try {
var stats = fs.statSync( base_dir + '/package.json' );
var json = require( base_dir + '/package.json' );
if (json && json.version) {
cur_version = json.version;
is_preinstalled = true;
}
}
catch (err) {;}
var is_running = false;
if (is_preinstalled) {
var pid_file = log_dir + '/cronicled.pid';
try {
var pid = fs.readFileSync(pid_file, { encoding: 'utf8' });
is_running = process.kill( pid, 0 );
}
catch (err) {;}
}
print( "Fetching release list...\n");
logonly( "Releases URL: " + gh_releases_url + "\n" );
cp.exec('curl -s ' + gh_releases_url, function (err, stdout, stderr) {
if (err) {
print( stdout.toString() );
warn( stderr.toString() );
die("Failed to fetch release list: " + gh_releases_url + ": " + err);
}
var releases = null;
try { releases = JSON.parse( stdout.toString() ); }
catch (err) {
die("Failed to parse JSON from GitHub: " + gh_releases_url + ": " + err);
}
// util.isArray is DEPRECATED??? Nooooooooode!
var isArray = Array.isArray || util.isArray;
if (!isArray(releases)) die("Unexpected response from GitHub Releases API: " + gh_releases_url + ": Not an array");
var release = null;
for (var idx = 0, len = releases.length; idx < len; idx++) {
var rel = releases[idx];
var ver = rel.tag_name.replace(/^\D+/, '');
rel.version = ver;
if (!new_version || (ver == new_version)) {
release = rel;
new_version = ver;
idx = len;
}
} // foreach release
if (!release) {
// no release found -- use HEAD rev?
if (!new_version || new_version.match(/HEAD/i)) {
release = {
version: 'HEAD',
tarball_url: gh_head_tarball_url
};
}
else {
die("Release not found: " + new_version);
}
}
// sanity check
if (is_preinstalled && (cur_version == new_version)) {
if (process.argv[2]) print( "\nVersion " + cur_version + " is already installed.\n\n" );
else print( "\nVersion " + cur_version + " is already installed, and is the latest.\n\n" );
process.exit(0);
}
// proceed with installation
if (is_preinstalled) print("Upgrading Cronicle from v"+cur_version+" to v"+new_version+"...\n");
else print("Installing Cronicle v"+new_version+"...\n");
if (is_running) {
print("\n");
try { cp.execSync( base_dir + "/bin/control.sh stop", { stdio: 'inherit' } ); }
catch (err) { die("Failed to stop Cronicle: " + err); }
print("\n");
}
// download tarball and expand into current directory
var tarball_url = release.tarball_url;
logonly( "Tarball URL: " + tarball_url + "\n" );
cp.exec('curl -L ' + tarball_url + ' | tar zxf - --strip-components 1', function (err, stdout, stderr) {
if (err) {
print( stdout.toString() );
warn( stderr.toString() );
die("Failed to download release: " + tarball_url + ": " + err);
}
else {
logonly( stdout.toString() + stderr.toString() );
}
try {
var stats = fs.statSync( base_dir + '/package.json' );
var json = require( base_dir + '/package.json' );
}
catch (err) {
die("Failed to download package: " + tarball_url + ": " + err);
}
print( is_preinstalled ? "Updating dependencies...\n" : "Installing dependencies...\n");
var npm_cmd = is_preinstalled ? "npm update --unsafe-perm" : "npm install --unsafe-perm";
logonly( "Executing command: " + npm_cmd + "\n" );
// temporarily stash add-on modules that were installed separately (thanks npm)
if (is_preinstalled) packages_to_check.forEach( function(pkg) {
if (fs.existsSync('node_modules/' + pkg)) {
packages_to_rescue[pkg] = JSON.parse( fs.readFileSync('node_modules/' + pkg + '/package.json', 'utf8') ).version;
}
});
// install dependencies via npm
cp.exec(npm_cmd, function (err, stdout, stderr) {
if (err) {
print( stdout.toString() );
warn( stderr.toString() );
if (is_preinstalled) restore_packages();
die("Failed to install dependencies: " + err);
}
else {
logonly( stdout.toString() + stderr.toString() );
}
print("Running post-install script...\n");
logonly( "Executing command: node bin/build.js dist\n" );
// finally, run postinstall script
cp.exec('node bin/build.js dist', function (err, stdout, stderr) {
if (is_preinstalled) {
// for upgrades only print output on error
if (err) {
print( stdout.toString() );
warn( stderr.toString() );
if (is_preinstalled) restore_packages();
die("Failed to run post-install: " + err);
}
else {
if (is_preinstalled) restore_packages();
print("Upgrade complete.\n\n");
if (is_running) {
try { cp.execSync( base_dir + "/bin/control.sh start", { stdio: 'inherit' } ); }
catch (err) { die("Failed to start Cronicle: " + err); }
print("\n");
}
}
} // upgrade
else {
// first time install, always print output
print( stdout.toString() );
warn( stderr.toString() );
if (err) {
die("Failed to run post-install: " + err);
}
else {
print("Installation complete.\n\n");
}
} // first install
logonly( "Completed install run: " + (new Date()).toString() + "\n" );
process.exit(0);
} ); // build.js
} ); // npm
} ); // download
} ); // releases api