nvm-vanilla 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/package.json +16 -0
- package/src/bin.js +115 -0
- package/src/index.js +408 -0
- package/src/init.js +28 -0
- package/src/nvm-vanilla +3 -0
- package/src/nvm.ps1 +10 -0
- package/src/nvm.sh +35 -0
- package/src/template/node +6 -0
- package/src/template/npm +9 -0
- package/src/template/npx +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# NVM
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
nvm current
|
|
7
|
+
nvm (which|where) <version>
|
|
8
|
+
nvm (list|ls)
|
|
9
|
+
nvm alias <name>
|
|
10
|
+
|
|
11
|
+
nvm install <version>
|
|
12
|
+
nvm uninstall <version>
|
|
13
|
+
nvm use <version>
|
|
14
|
+
|
|
15
|
+
nvm run <version> <args>
|
|
16
|
+
nvm exec <version> <command>
|
|
17
|
+
|
|
18
|
+
nvm alias <name> <version>
|
|
19
|
+
nvm unalias <name>
|
|
20
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nvm-vanilla",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"nvm-vanilla": "src/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"postinstall": "node src/init.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC"
|
|
16
|
+
}
|
package/src/bin.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { promisify } = require('util');
|
|
7
|
+
const { spawnSync, execFileSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
const { init: install, use, list, detect, uninstall, alias, which } = require('./index');
|
|
10
|
+
|
|
11
|
+
const init = require('./init');
|
|
12
|
+
|
|
13
|
+
const evalCommandSet = new Set(['use', 'autoload', 'env']);
|
|
14
|
+
|
|
15
|
+
const main = async () => {
|
|
16
|
+
// process.stderr.write(JSON.stringify(process.argv) + '\n'); // debug
|
|
17
|
+
|
|
18
|
+
const homeDir = os.homedir();
|
|
19
|
+
|
|
20
|
+
const baseDir = path.join(homeDir, '.nvm2');
|
|
21
|
+
|
|
22
|
+
const args = process.argv.slice(2);
|
|
23
|
+
|
|
24
|
+
let evalMode = false;
|
|
25
|
+
if (args[0] === '--eval') {
|
|
26
|
+
evalMode = true;
|
|
27
|
+
args.shift();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const command = args[0];
|
|
31
|
+
const version = args[1];
|
|
32
|
+
|
|
33
|
+
if (evalMode ^ evalCommandSet.has(command)) return;
|
|
34
|
+
|
|
35
|
+
const checkVersion = () => {
|
|
36
|
+
if (version) return true;
|
|
37
|
+
throw 'no specific node version';
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
switch (command) {
|
|
41
|
+
case 'env': {
|
|
42
|
+
const content = await promisify(fs.readFile)(path.resolve(
|
|
43
|
+
__dirname,
|
|
44
|
+
process.platform == 'win32' ? 'nvm.ps1' : 'nvm.sh'
|
|
45
|
+
), 'utf-8');
|
|
46
|
+
process.stdin.write(content);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case 'use': {
|
|
50
|
+
await use(baseDir, version);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case 'autoload': {
|
|
54
|
+
const targetVersion = await detect(baseDir);
|
|
55
|
+
if (targetVersion) {
|
|
56
|
+
await use(baseDir, targetVersion);
|
|
57
|
+
} else {
|
|
58
|
+
console.log(':');
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'which':
|
|
63
|
+
case 'where': {
|
|
64
|
+
if (!checkVersion()) return;
|
|
65
|
+
const dir = await which(baseDir, version);
|
|
66
|
+
console.log(dir);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case 'alias': {
|
|
70
|
+
await alias(baseDir, args[1], args[2]);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case 'install': {
|
|
74
|
+
await install(baseDir, version);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'unalias':
|
|
78
|
+
case 'uninstall': {
|
|
79
|
+
if (!checkVersion()) return;
|
|
80
|
+
await uninstall(baseDir, version);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
case 'ls':
|
|
84
|
+
case 'list': {
|
|
85
|
+
await list(baseDir);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case 'exec':
|
|
89
|
+
case 'run': {
|
|
90
|
+
if (!checkVersion()) return;
|
|
91
|
+
const env = await use(baseDir, version, false);
|
|
92
|
+
Object.assign(process.env, env);
|
|
93
|
+
const childArgs = args.slice(2);
|
|
94
|
+
const childCommand = command === 'run' ? 'node' : childArgs.shift();
|
|
95
|
+
spawnSync(childCommand, childArgs, { stdio: 'inherit' });
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case 'current': {
|
|
99
|
+
spawnSync('node', ['--version'], { stdio: 'inherit' });
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'init': {
|
|
103
|
+
await init();
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
default:
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
main()
|
|
111
|
+
.catch((error) => {
|
|
112
|
+
const message = (error || {}).stack || error;
|
|
113
|
+
process.stderr.write(message + '\n');
|
|
114
|
+
process.exit(-1);
|
|
115
|
+
});
|
package/src/index.js
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const http = require('http');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
const { spawn, execFile } = require('child_process');
|
|
7
|
+
const { promisify } = require('util');
|
|
8
|
+
|
|
9
|
+
const getNpmCommand = () => {
|
|
10
|
+
return process.platform == 'win32' ? 'npm.cmd' : 'npm';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const npmCommand = getNpmCommand();
|
|
14
|
+
|
|
15
|
+
// https://github.com/aredridel/node-bin-setup/blob/514d4aa42b58b10971845c420d34330c2414eef9/index.js#L10-L17
|
|
16
|
+
|
|
17
|
+
process.env.npm_config_global = 'false';
|
|
18
|
+
process.env.npm_config_repository = '';
|
|
19
|
+
|
|
20
|
+
const getNodePackageName = () => {
|
|
21
|
+
const platform = process.platform == 'win32' ? 'win' : process.platform;
|
|
22
|
+
const arch = platform == 'win' && process.arch == 'ia32' ? 'x86' : process.arch;
|
|
23
|
+
const prefix = (process.platform == 'darwin' && process.arch == 'arm64') ? 'node-bin' : 'node';
|
|
24
|
+
return [prefix, platform, arch].join('-');
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const nodePackageName = getNodePackageName();
|
|
28
|
+
|
|
29
|
+
const readJsonFile = (filePath) => (
|
|
30
|
+
promisify(fs.readFile)(filePath, 'utf8').then(JSON.parse)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const promisifySpawn = (command, args, options) => {
|
|
34
|
+
const child = spawn(command, args, {
|
|
35
|
+
stdio: 'inherit',
|
|
36
|
+
...options,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
child.on('exit', code => {
|
|
41
|
+
if (code === 0) resolve();
|
|
42
|
+
else reject(code);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const getNodeVersion = async (semanticVersion) => {
|
|
48
|
+
const npmViewOutput = await promisify(execFile)('npm', [
|
|
49
|
+
'view',
|
|
50
|
+
nodePackageName + '@' + semanticVersion,
|
|
51
|
+
'version',
|
|
52
|
+
'--json',
|
|
53
|
+
])
|
|
54
|
+
.catch(() => { });
|
|
55
|
+
|
|
56
|
+
let nodeVersion;
|
|
57
|
+
try {
|
|
58
|
+
nodeVersion = JSON.parse(npmViewOutput.stdout).pop();
|
|
59
|
+
} catch (_) { }
|
|
60
|
+
|
|
61
|
+
return nodeVersion;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const fetchJsonFile = async (fileUrl) => {
|
|
65
|
+
const response = await new Promise((resolve, reject) => {
|
|
66
|
+
const { get } = /^http:\/\//.test(fileUrl) ? http : https;
|
|
67
|
+
get(fileUrl)
|
|
68
|
+
.on('response', resolve)
|
|
69
|
+
.on('error', reject);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const chunkList = [];
|
|
73
|
+
|
|
74
|
+
await new Promise((resolve, reject) => {
|
|
75
|
+
response
|
|
76
|
+
.on('error', reject)
|
|
77
|
+
.on('end', resolve)
|
|
78
|
+
.on('data', (chunk) => {
|
|
79
|
+
chunkList.push(chunk);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return JSON.parse(Buffer.concat(chunkList));
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const getNpmVersion = async (nodeVersion) => {
|
|
87
|
+
const list = await Promise.race([
|
|
88
|
+
fetchJsonFile('https://cdn.npmmirror.com/binaries/node/index.json'),
|
|
89
|
+
fetchJsonFile('https://nodejs.org/dist/index.json'),
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
const target = list.find(item =>
|
|
93
|
+
item.version === nodeVersion ||
|
|
94
|
+
item.version === 'v' + nodeVersion
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
if (!target) throw 'npm version not found';
|
|
98
|
+
|
|
99
|
+
return target.npm;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const install = async (cwd, nodeVersion) => {
|
|
103
|
+
// await promisifySpawn(npmCommand, ['install', '--no-save', nodePackageName + '@' + version], {
|
|
104
|
+
// stdio: 'inherit',
|
|
105
|
+
// // shell: true,
|
|
106
|
+
// cwd,
|
|
107
|
+
// });
|
|
108
|
+
|
|
109
|
+
// const packageFile = path.join(cwd, 'node_modules', nodePackageName, 'package.json');
|
|
110
|
+
// const { version: nodeVersion } = await readJsonFile(packageFile);
|
|
111
|
+
|
|
112
|
+
const npmVersion = await getNpmVersion(nodeVersion);
|
|
113
|
+
|
|
114
|
+
await promisifySpawn(npmCommand, [
|
|
115
|
+
'install',
|
|
116
|
+
'--no-save',
|
|
117
|
+
'--ignore-engines',
|
|
118
|
+
nodePackageName + '@' + nodeVersion,
|
|
119
|
+
'npm' + '@' + npmVersion,
|
|
120
|
+
], {
|
|
121
|
+
stdio: 'inherit',
|
|
122
|
+
// shell: true,
|
|
123
|
+
cwd,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return nodeVersion;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
const override = async (workDir) => {
|
|
131
|
+
const npmDir = path.join(workDir, 'node_modules', 'npm');
|
|
132
|
+
const { bin } = await readJsonFile(path.join(npmDir, 'package.json'));
|
|
133
|
+
|
|
134
|
+
const fileList = [];
|
|
135
|
+
|
|
136
|
+
if (typeof bin === 'string') {
|
|
137
|
+
fileList.push(bin);
|
|
138
|
+
} else if (bin && typeof bin === 'object') {
|
|
139
|
+
for (const key in bin) {
|
|
140
|
+
fileList.push(bin[key]);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const promiseList = fileList.map(async relativeFilePath => {
|
|
145
|
+
relativeFilePath = relativeFilePath.replace(/^\//, '');
|
|
146
|
+
const relativeLibPath = path.posix.relative(
|
|
147
|
+
path.join(npmDir, relativeFilePath),
|
|
148
|
+
workDir,
|
|
149
|
+
);
|
|
150
|
+
const prefix = `
|
|
151
|
+
process.env.NPM_CONFIG_PREFIX = process.env.NPM_CONFIG_PREFIX
|
|
152
|
+
|| require("path").resolve(__filename, ${JSON.stringify(relativeLibPath)}, "prefix");
|
|
153
|
+
process.env.NPM_CONFIG_CACHE = process.env.NPM_CONFIG_CACHE
|
|
154
|
+
|| require("path").resolve(__filename, ${JSON.stringify(relativeLibPath)}, "cache");
|
|
155
|
+
`
|
|
156
|
+
.trim();
|
|
157
|
+
const filePath = path.join(npmDir, relativeFilePath);
|
|
158
|
+
let content = await promisify(fs.readFile)(filePath, 'utf-8');
|
|
159
|
+
content = content.replace(/\n/, '\n' + prefix + '\n'); // #!/usr/bin/env node 第一行要保留
|
|
160
|
+
await promisify(fs.writeFile)(filePath, content, 'utf-8');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return Promise.all(promiseList);
|
|
164
|
+
};
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
const detect = async (baseDir) => {
|
|
168
|
+
const [
|
|
169
|
+
nodeVersion,
|
|
170
|
+
nvmrc,
|
|
171
|
+
defaultVersion,
|
|
172
|
+
] = await Promise.all(
|
|
173
|
+
[
|
|
174
|
+
'.node-version',
|
|
175
|
+
'.nvmrc',
|
|
176
|
+
]
|
|
177
|
+
.map(name => promisify(fs.readFile)(name, 'utf-8').catch(() => { }))
|
|
178
|
+
.concat([
|
|
179
|
+
baseDir && getLocalNodeVersion(baseDir, 'default').catch(() => { }),
|
|
180
|
+
])
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
return String(nodeVersion || nvmrc || defaultVersion || '').trim();
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const corrent = async (version) => {
|
|
187
|
+
if (!version) version = await detect();
|
|
188
|
+
if (!version) {
|
|
189
|
+
throw 'cannot detect node version';
|
|
190
|
+
}
|
|
191
|
+
return version.replace(/^v/i, '');
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const clear = async (dir) => {
|
|
195
|
+
if (process.platform == 'win32') {
|
|
196
|
+
await promisify(execFile)('rd', ['/s', '/q', dir]);
|
|
197
|
+
} else {
|
|
198
|
+
await promisify(execFile)('rm', ['-rf', dir]);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const getLocalNodeVersion = async (baseDir, name) => {
|
|
203
|
+
const packageFile = path.join(baseDir, name, 'node_modules', nodePackageName, 'package.json');
|
|
204
|
+
try {
|
|
205
|
+
const { version } = await readJsonFile(packageFile);
|
|
206
|
+
return version;
|
|
207
|
+
} catch (_) {
|
|
208
|
+
throw `no local node version "${name}"`;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const alias = async (baseDir, version, targetVersion) => {
|
|
213
|
+
if (version === 'system') {
|
|
214
|
+
throw 'cannot alias system node version';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const linkDir = path.join(baseDir, version);
|
|
218
|
+
|
|
219
|
+
const resetFlag = targetVersion === 'none' && false;
|
|
220
|
+
|
|
221
|
+
if (!targetVersion) {
|
|
222
|
+
const nodeVersion = await getLocalNodeVersion(baseDir, version);
|
|
223
|
+
console.log(nodeVersion);
|
|
224
|
+
return;
|
|
225
|
+
} else if (!resetFlag) {
|
|
226
|
+
await getLocalNodeVersion(baseDir, targetVersion); // check
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const sourceDir = path.join(baseDir, targetVersion);
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
await promisify(fs.unlink)(linkDir);
|
|
233
|
+
} catch (_) { }
|
|
234
|
+
|
|
235
|
+
if (!resetFlag) await promisify(fs.symlink)(sourceDir, linkDir, 'dir');
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const init = async (baseDir, version) => {
|
|
239
|
+
version = await corrent(version);
|
|
240
|
+
if (!version) return;
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
await promisify(fs.mkdir)(baseDir);
|
|
244
|
+
} catch (_) { }
|
|
245
|
+
|
|
246
|
+
const nodeVersion = await getNodeVersion(version);
|
|
247
|
+
|
|
248
|
+
if (!nodeVersion) {
|
|
249
|
+
throw `no satisified node version "${version}"`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const workDir = path.join(baseDir, nodeVersion);
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
await promisify(fs.mkdir)(workDir);
|
|
256
|
+
} catch (_) {
|
|
257
|
+
throw `node version "${nodeVersion}" already installed`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const binDir = path.join(workDir, 'bin');
|
|
261
|
+
const templateDir = path.join(__dirname, 'template');
|
|
262
|
+
|
|
263
|
+
const mkdirPromise = Promise.all([
|
|
264
|
+
// 'bin',
|
|
265
|
+
'cache',
|
|
266
|
+
'prefix',
|
|
267
|
+
].map(
|
|
268
|
+
name => promisify(fs.mkdir)(path.join(workDir, name))
|
|
269
|
+
))
|
|
270
|
+
.then(() => (
|
|
271
|
+
promisify(fs.mkdir)(path.join(workDir, 'prefix', 'lib'))
|
|
272
|
+
));
|
|
273
|
+
|
|
274
|
+
const [
|
|
275
|
+
// nameList,
|
|
276
|
+
] = await Promise.all([
|
|
277
|
+
// promisify(fs.readdir)(templateDir),
|
|
278
|
+
install(workDir, nodeVersion),
|
|
279
|
+
mkdirPromise,
|
|
280
|
+
]);
|
|
281
|
+
|
|
282
|
+
// await override(workDir);
|
|
283
|
+
|
|
284
|
+
/*
|
|
285
|
+
const binNameList = await promisify(fs.readdir)(path.join(workDir, 'node_modules', '.bin'));
|
|
286
|
+
|
|
287
|
+
const commandNameSet = new Set(binNameList.map(_ => _.split('.')[0]));
|
|
288
|
+
|
|
289
|
+
await Promise.all(nameList.map(async name => {
|
|
290
|
+
const commandName = name.split('.')[0];
|
|
291
|
+
if (!commandNameSet.has(commandName)) return;
|
|
292
|
+
const targetPath = path.join(binDir, name);
|
|
293
|
+
await promisify(fs.copyFile)(
|
|
294
|
+
path.join(templateDir, name),
|
|
295
|
+
targetPath,
|
|
296
|
+
);
|
|
297
|
+
await promisify(fs.chmod)(targetPath, 0o755);
|
|
298
|
+
}));
|
|
299
|
+
*/
|
|
300
|
+
|
|
301
|
+
if (version !== nodeVersion) {
|
|
302
|
+
await alias(baseDir, version, nodeVersion);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const uninstall = async (baseDir, version) => {
|
|
307
|
+
const workDir = path.join(baseDir, version);
|
|
308
|
+
|
|
309
|
+
try {
|
|
310
|
+
await clear(workDir);
|
|
311
|
+
} catch (_) { }
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const which = async (baseDir, name) => {
|
|
315
|
+
const version = await getLocalNodeVersion(baseDir, name);
|
|
316
|
+
const workDir = path.join(baseDir, version, 'node_modules', '.bin');
|
|
317
|
+
return workDir;
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const use = async (baseDir, version, evalFlag = true) => {
|
|
321
|
+
if (version !== 'system') {
|
|
322
|
+
version = await corrent(version);
|
|
323
|
+
version = await getLocalNodeVersion(baseDir, version);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// const workDir = path.join(baseDir, version, 'bin');
|
|
327
|
+
|
|
328
|
+
const workDir = path.join(baseDir, version, 'node_modules', '.bin');
|
|
329
|
+
const prefixDir = path.join(baseDir, version, 'prefix');
|
|
330
|
+
const cacheDir = path.join(baseDir, version, 'cache');
|
|
331
|
+
|
|
332
|
+
const resetFlag = version === 'system';
|
|
333
|
+
|
|
334
|
+
// let checkFlag = false;
|
|
335
|
+
// try {
|
|
336
|
+
// const stat = await promisify(fs.stat)(workDir);
|
|
337
|
+
// checkFlag = stat.isDirectory();
|
|
338
|
+
// } catch (_) { }
|
|
339
|
+
|
|
340
|
+
// if (!checkFlag && !resetFlag) {
|
|
341
|
+
// throw `node version "${version}" not installed`;
|
|
342
|
+
// }
|
|
343
|
+
|
|
344
|
+
let list = process.env.PATH.split(path.delimiter);
|
|
345
|
+
|
|
346
|
+
list = list.filter(item => item.indexOf(baseDir) === -1);
|
|
347
|
+
|
|
348
|
+
if (!resetFlag) list.unshift(workDir, prefixDir);
|
|
349
|
+
|
|
350
|
+
const env = {};
|
|
351
|
+
|
|
352
|
+
env.PATH = list.join(path.delimiter);
|
|
353
|
+
|
|
354
|
+
env.NPM_CONFIG_PREFIX = prefixDir;
|
|
355
|
+
env.NPM_CONFIG_CACHE = cacheDir;
|
|
356
|
+
|
|
357
|
+
// process.stderr.write('Now using node v' + version + '\n');
|
|
358
|
+
|
|
359
|
+
if (evalFlag) {
|
|
360
|
+
for (const key in env) {
|
|
361
|
+
const value = env[key];
|
|
362
|
+
let command = (key === 'PATH' || true)
|
|
363
|
+
? `export ${key}=${value}`
|
|
364
|
+
: `export ${key}=\${${key}:-${value}}`;
|
|
365
|
+
|
|
366
|
+
if (process.platform === 'win32') {
|
|
367
|
+
command = (key === 'PATH' || true)
|
|
368
|
+
? `set ${key}=${value}`
|
|
369
|
+
: `if not defined ${key} set ${key}=${value}`;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
process.stdout.write(
|
|
373
|
+
command + '\n'
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
// process.stderr.write(
|
|
377
|
+
// command + '\n'
|
|
378
|
+
// );
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return env;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const list = async (baseDir) => {
|
|
386
|
+
const nameList = await promisify(fs.readdir)(baseDir);
|
|
387
|
+
|
|
388
|
+
let versionList = await Promise.all(nameList.map(async name => {
|
|
389
|
+
const packageFile = path.join(baseDir, name, 'node_modules', nodePackageName, 'package.json');
|
|
390
|
+
const { version } = await readJsonFile(packageFile).catch(() => ({}));
|
|
391
|
+
if (!version) return;
|
|
392
|
+
return 'node@' + name + ' (' + version + ')';
|
|
393
|
+
}));
|
|
394
|
+
|
|
395
|
+
versionList = versionList.filter(Boolean);
|
|
396
|
+
|
|
397
|
+
if (versionList.length) console.log(versionList.join('\n'));
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
module.exports = {
|
|
401
|
+
init,
|
|
402
|
+
uninstall,
|
|
403
|
+
use,
|
|
404
|
+
list,
|
|
405
|
+
detect,
|
|
406
|
+
alias,
|
|
407
|
+
which,
|
|
408
|
+
};
|
package/src/init.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const os = require('os');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { promisify } = require('util');
|
|
5
|
+
|
|
6
|
+
const init = async () => {
|
|
7
|
+
if (process.platform === 'win32') {
|
|
8
|
+
await promisify(fs.appendFile)(
|
|
9
|
+
path.resolve(os.homedir(), 'Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1'),
|
|
10
|
+
'\nnvm-vanilla env --eval | Out-String | Invoke-Expression',
|
|
11
|
+
)
|
|
12
|
+
} else {
|
|
13
|
+
await promisify(fs.appendFile)(
|
|
14
|
+
path.resolve(os.homedir(), '.bashrc'),
|
|
15
|
+
'\neval "$(nvm-vanilla env --eval)"',
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
module.exports = init;
|
|
21
|
+
|
|
22
|
+
// ${ZDOTDIR:-$HOME}/.zshrc
|
|
23
|
+
// $HOME/.profile
|
|
24
|
+
// $HOME/.bashrc
|
|
25
|
+
|
|
26
|
+
if (require.main === module) {
|
|
27
|
+
init();
|
|
28
|
+
}
|
package/src/nvm-vanilla
ADDED
package/src/nvm.ps1
ADDED
package/src/nvm.sh
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
nvm() {
|
|
2
|
+
local cmd="$(command nvm-vanilla --eval "$@")"
|
|
3
|
+
if [ -n "$cmd" ]; then
|
|
4
|
+
eval $cmd
|
|
5
|
+
else
|
|
6
|
+
command nvm-vanilla "$@"
|
|
7
|
+
fi
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
nvm_autoload_dir=""
|
|
11
|
+
|
|
12
|
+
_nvm_autoload_hook() {
|
|
13
|
+
local current_dir="$PWD"
|
|
14
|
+
|
|
15
|
+
if [ "$current_dir" = "$nvm_autoload_dir" ]; then
|
|
16
|
+
return
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
nvm autoload
|
|
20
|
+
|
|
21
|
+
nvm_autoload_dir="$current_dir"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# 根据不同 shell 设置钩子
|
|
25
|
+
case "$SHELL" in
|
|
26
|
+
*bash*)
|
|
27
|
+
# bash: 使用 PROMPT_COMMAND
|
|
28
|
+
PROMPT_COMMAND="_nvm_autoload_hook; $PROMPT_COMMAND"
|
|
29
|
+
;;
|
|
30
|
+
*zsh*)
|
|
31
|
+
# zsh: 使用 chpwd 或 precmd 钩子
|
|
32
|
+
autoload -U add-zsh-hook
|
|
33
|
+
add-zsh-hook chpwd _nvm_autoload_hook
|
|
34
|
+
;;
|
|
35
|
+
esac
|
package/src/template/npm
ADDED
package/src/template/npx
ADDED