/
main.js
175 lines (159 loc) · 4.58 KB
/
main.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
#!/usr/bin/env node
var argv = require('optimist')
.usage("execute command with node version acceptable to engine package.json property\nusage: $0")
.demand('c')
.describe('c', 'Shell command')
.demand('f')
.describe('f', 'Path to package.json')
.argv
exec = require('child_process').exec,
fs = require('fs'),
semver = require('semver'),
spawn = require('child_process').spawn;
function findNave() {
// First try under ./node_modules
var path = "/node_modules/nave/nave.sh";
var res;
try {
res = "." + path;
fs.statSync(res);
return res;
} catch(e) {
// Not found - now try relative to this file's location
res = __dirname + path;
fs.statSync(res);
return res
}
}
// Check what version of node is already in system $PATH
function getSystemNodeVers(cb) {
exec('node -v', function(err, stdout) {
if (err) {
return cb(err, null);
}
cb(null, stdout.slice(1).replace('\n',''));
});
}
function readPackage(path) {
try {
return(fs.readFileSync(path));
} catch(e) {
console.log(e.toString());
process.exit(1);
}
}
function parsePackage(contents) {
try {
return(JSON.parse(contents));
} catch(e) {
console.log("Error: Could not parse package.json:", e);
process.exit(1);
}
}
function getEngine(pkgData) {
var engine;
if (pkgData.engines && pkgData.engines.node) {
engine = pkgData.engines.node;
} else {
engine = "*";
}
return engine;
}
// Look in ~/.nave/installed to list currently installed Node.JS versions
// @param cb function(err, [versions])
function getLocalNodeVers(cb) {
var nave_path = process.env.HOME + "/.nave/installed/";
fs.readdir(nave_path, cb);
}
// Use `nave ls-remote` to build a list of available node.js versions
// @param cb function([versions])
function getRemoteNodeVers(cb) {
var cmd = nave_path + " ls-remote";
exec(cmd, function(err, stdout, stderr) {
if (err) {
console.log(err);
process.exit(1);
}
// Filter out 'remote:'
stdout = stdout.replace('remote:', '');
var versions = stdout.split(/\s+/);
var res = [];
// Filter empty strings
for (var i=0; i < versions.length; i++) {
if (versions[i].length > 0) {
res.push(versions[i]);
}
}
cb(res);
});
}
function run(cmd, cb, hide_dl) {
cmd = cmd.split(/\s+/);
var child = spawn(cmd[0], cmd.slice(1));
var done = false;
child.stdout.on('data', function(data) {
process.stdout.write(data.toString());
});
child.stderr.on('data', function(data) {
process.stderr.write(data.toString());
});
child.on('exit', function(code) {
if (code != 0) {
console.log("Error executing command %s - exit code: %s", cmd, code);
process.exit(1);
}
cb();
});
}
var nave_path = findNave();
var json = readPackage(argv.f);
var data = parsePackage(json);
var engine = getEngine(data);
// Check for matching system (non-Nave) Node.JS version
getSystemNodeVers(function(err, version) {
if (!err) {
if (semver.satisfies(version, engine)) {
console.log("System non-Nave Node.JS version %s satisfies range %s", version, engine);
return run(argv.c, function() {
process.exit(0);
});
}
}
console.log("System non-Nave Node.JS version %s does not satisfy range %s", version, engine);
getLocalNodeVers(function(err, versions) {
if (err) {
versions = [];
}
console.log("local versions: %j", versions);
// Check whether an already-installed-via-Nave node version satisfies the engine
var found = false;
for (var i=0; i<versions.length; i++) {
if (semver.satisfies(versions[i], engine)) {
found = versions[i];
break;
}
}
var cmd = nave_path + " -o -Lfs use " + found + " " + argv.c;
if (found) {
console.log("Local version %s satisfies range %s", found, engine);
run(cmd, function() {
process.exit(0);
}, true);
} else {
// No locally-installed version satisfies, find the latest remote version
// install that, then run the command with that version.
getRemoteNodeVers(function(versions) {
var remote_version = semver.maxSatisfying(versions, engine);
if (!remote_version) {
console.log("Error: No remote version can satisfy range %s!", engine);
process.exit(1);
}
console.log("Remote version %s satisfies range %s", remote_version, engine);
var cmd = nave_path + " -o -Lfs use " + remote_version + " " + argv.c;
run(cmd, function() {
process.exit(0);
}, true);
});
}
});
});