UNPKG

13 kBJavaScriptView Raw
1#!/usr/bin/env node
2var path = require('path');
3var fs = require('fs');
4var program = require('commander');
5var npm = require('npm');
6var ini = require('ini');
7var echo = require('node-echo');
8var extend = require('extend');
9var open = require('open');
10var async = require('async');
11var request = require('request');
12var only = require('only');
13
14var registries = require('./registries.json');
15var PKG = require('./package.json');
16var NRMRC = path.join(process.env.HOME, '.nrmrc');
17
18var REGISTRY_ATTRS = [];
19var FIELD_IS_CURRENT = 'is-current';
20var FIELD_REPOSITORY = 'repository';
21var IGNORED_ATTRS = [FIELD_IS_CURRENT, FIELD_REPOSITORY];
22
23
24program
25 .version(PKG.version);
26
27program
28 .command('ls')
29 .description('List all the registries')
30 .action(onList);
31
32program
33 .command('current')
34 .description('Show current registry name')
35 .action(showCurrent);
36
37program
38 .command('use <registry>')
39 .description('Change registry to registry')
40 .action(onUse);
41
42program
43 .command('add <registry> <url> [home]')
44 .description('Add one custom registry')
45 .action(onAdd);
46
47program
48 .command('set-auth <registry> <value> [always]')
49 .description('Set authorize information for a custom registry')
50 .action(onSetAuth);
51
52program
53 .command('set-email <registry> <value>')
54 .description('Set email for a custom registry')
55 .action(onSetEmail);
56
57program
58 .command('set-hosted-repo <registry> <value>')
59 .description('Set hosted npm repository for a custom registry to publish packages')
60 .action(onSetRepository);
61
62program
63 .command('del <registry>')
64 .description('Delete one custom registry')
65 .action(onDel);
66
67program
68 .command('home <registry> [browser]')
69 .description('Open the homepage of registry with optional browser')
70 .action(onHome);
71
72program
73 .command('publish [<tarball>|<folder>]')
74 .option('-t, --tag [tag]', 'Add tag')
75 .option('-a, --access <public|restricted>', 'Set access')
76 .option('-o, --otp [otpcode]', 'Set otpcode')
77 .option('-dr, --dry-run', 'Set is dry run')
78 .description('Publish package to current registry if current registry is a custom registry.\n if you\'re not using custom registry, this command will run npm publish directly')
79 .action(onPublish);
80
81program
82 .command('test [registry]')
83 .description('Show response time for specific or all registries')
84 .action(onTest);
85
86program
87 .command('help', { isDefault: true })
88 .description('Print this help')
89 .action(function () {
90 program.outputHelp();
91 });
92
93program
94 .parse(process.argv);
95
96
97if (process.argv.length === 2) {
98 program.outputHelp();
99}
100
101/*//////////////// cmd methods /////////////////*/
102
103function onList() {
104 getCurrentRegistry(function(cur) {
105 var info = [''];
106 var allRegistries = getAllRegistry();
107
108 Object.keys(allRegistries).forEach(function(key) {
109 var item = allRegistries[key];
110 var prefix = item.registry === cur ? '* ' : ' ';
111 info.push(prefix + key + line(key, 8) + item.registry);
112 });
113
114 info.push('');
115 printMsg(info);
116 });
117}
118
119function showCurrent() {
120 getCurrentRegistry(function(cur) {
121 var allRegistries = getAllRegistry();
122 Object.keys(allRegistries).forEach(function(key) {
123 var item = allRegistries[key];
124 if (item.registry === cur) {
125 printMsg([key]);
126 return;
127 }
128 });
129 });
130}
131function config(attrArray, registry, index = 0) {
132 return new Promise((resolve, reject) => {
133 const attr = attrArray[index];
134 const command = registry.hasOwnProperty(attr) ? ['set', attr, String(registry[attr])] : ['delete', attr];
135 npm.commands.config(command, function (err, data) {
136 return err ? reject(err) : resolve(index + 1);
137 });
138 }).then(next => {
139 if (next < attrArray.length) {
140 return config(attrArray, registry, next);
141 } else {
142 return Promise.resolve();
143 }
144 });
145}
146
147function onUse(name) {
148 var allRegistries = getAllRegistry();
149 if (allRegistries.hasOwnProperty(name)) {
150 var registry = allRegistries[name];
151 npm.load(function (err) {
152 if (err) return exit(err);
153 const attrs = [].concat(REGISTRY_ATTRS);
154 for (let attr in registry) {
155 if (!REGISTRY_ATTRS.includes(attr) && !IGNORED_ATTRS.includes(attr)) {
156 attrs.push(attr);
157 }
158 }
159 config(attrs, registry).then(() => {
160 console.log(' ');
161 var newR = npm.config.get('registry');
162 var customRegistries = getCustomRegistry();
163 Object.keys(customRegistries).forEach(key => {
164 delete customRegistries[key][FIELD_IS_CURRENT];
165 });
166 if (customRegistries.hasOwnProperty(name) && customRegistries[name].registry === registry.registry) {
167 registry[FIELD_IS_CURRENT] = true;
168 customRegistries[name] = registry;
169 }
170 setCustomRegistry(customRegistries);
171 printMsg([
172 '', ' Registry has been set to: ' + newR, ''
173 ]);
174 }).catch(err => {
175 exit(err);
176 });
177 });
178 } else {
179 printMsg([
180 '', ' Not find registry: ' + name, ''
181 ]);
182 }
183}
184
185function onDel(name) {
186 var customRegistries = getCustomRegistry();
187 if (!customRegistries.hasOwnProperty(name)) return;
188 getCurrentRegistry(function(cur) {
189 if (cur === customRegistries[name].registry) {
190 onUse('npm');
191 }
192 delete customRegistries[name];
193 setCustomRegistry(customRegistries, function(err) {
194 if (err) return exit(err);
195 printMsg([
196 '', ' delete registry ' + name + ' success', ''
197 ]);
198 });
199 });
200}
201
202function onAdd(name, url, home) {
203 var customRegistries = getCustomRegistry();
204 if (customRegistries.hasOwnProperty(name)) return;
205 var config = customRegistries[name] = {};
206 if (url[url.length - 1] !== '/') url += '/'; // ensure url end with /
207 config.registry = url;
208 if (home) {
209 config.home = home;
210 }
211 setCustomRegistry(customRegistries, function(err) {
212 if (err) return exit(err);
213 printMsg([
214 '', ' add registry ' + name + ' success', ''
215 ]);
216 });
217}
218
219function onSetAuth(registry, value, always) {
220 var customRegistries = getCustomRegistry();
221 if (!customRegistries.hasOwnProperty(registry)) return;
222 var config = customRegistries[registry];
223 config._auth = value;
224 if (always) {
225 config['always-auth'] = always;
226 }
227 setCustomRegistry(customRegistries, function(err) {
228 if (err) return exit(err);
229 printMsg(['', ' set authorize info to registry ' + registry + ' success', '']);
230 });
231}
232
233function onSetEmail(registry, value) {
234 var customRegistries = getCustomRegistry();
235 if (!customRegistries.hasOwnProperty(registry)) return;
236 var config = customRegistries[registry];
237 config.email = value;
238 setCustomRegistry(customRegistries, function(err) {
239 if (err) return exit(err);
240 printMsg(['', ' set email to registry ' + registry + ' success', '']);
241 });
242}
243
244function onSetRepository(registry, value) {
245 var customRegistries = getCustomRegistry();
246 if (!customRegistries.hasOwnProperty(registry)) return;
247 var config = customRegistries[registry];
248 config[FIELD_REPOSITORY] = value;
249 setCustomRegistry(customRegistries, function(err) {
250 if (err) return exit(err);
251 printMsg(['', ` set ${FIELD_REPOSITORY} to registry [${registry}] success`, '']);
252 });
253}
254
255function onHome(name, browser) {
256 var allRegistries = getAllRegistry();
257 var home = allRegistries[name] && allRegistries[name].home;
258 if (home) {
259 var args = [home];
260 if (browser) args.push(browser);
261 open.apply(null, args);
262 }
263}
264
265function onPublish(tarballOrFolder, cmd) {
266 getCurrentRegistry(registry => {
267 var customRegistries = getCustomRegistry();
268 var currentRegistry;
269 Object.keys(customRegistries).forEach(function(key) {
270 var item = customRegistries[key];
271 if (item.registry === registry && item['is-current']) {
272 currentRegistry = item;
273 currentRegistry.name = key;
274 return;
275 }
276 });
277 if (currentRegistry) {
278 if (currentRegistry[FIELD_REPOSITORY]) {
279 const optionData = {
280 registry: currentRegistry[FIELD_REPOSITORY]
281 };
282 const attrs = ['registry'];
283 let command = `npm publish --registry ${currentRegistry[FIELD_REPOSITORY]}`;
284 cmd.options.forEach(option => {
285 const opt = option.long.substring(2);
286 const optionValue = cmd[opt];
287 if (optionValue) {
288 command += ` ${option.long} ${optionValue}`;
289 optionData[opt] = cmd[opt];
290 attrs.push(opt);
291 }
292 });
293 console.info(command);
294 new Promise((resolve, reject) => {
295 attrs.length ? resolve(config(attrs, optionData)) : resolve();
296 }).then(() => {
297 const callback = (err) => {
298 new Promise(resolve => {
299 attrs.length ? resolve(config(attrs, currentRegistry)) : resolve();
300 }).then(() => {
301 if (err) {
302 exit(err);
303 }
304 printMsg([ '',
305 ` published to registry ${currentRegistry[FIELD_REPOSITORY]} successfully.`,
306 '']);
307 }).catch(err => {
308 exit(err);
309 });
310 };
311 try {
312 tarballOrFolder ? npm.publish(tarballOrFolder, callback) : npm.publish(callback);
313 } catch (e) {
314 callback(err);
315 }
316 });
317 } else {
318 printMsg([ '',
319 ` current using registry [${currentRegistry.name}] has no ${FIELD_REPOSITORY} field, can't execute publish.`,
320 '']);
321 }
322 } else {
323 printMsg([ '',
324 ` current using registry is not a custom registry, will run npm publish directly.`,
325 '']);
326 tarballOrFolder ? npm.publish(tarballOrFolder) : npm.publish();
327 }
328 });
329}
330
331function onTest(registry) {
332 var allRegistries = getAllRegistry();
333
334 var toTest;
335
336 if (registry) {
337 if (!allRegistries.hasOwnProperty(registry)) {
338 return;
339 }
340 toTest = only(allRegistries, registry);
341 } else {
342 toTest = allRegistries;
343 }
344
345 async.map(Object.keys(toTest), function(name, cbk) {
346 var registry = toTest[name];
347 var start = +new Date();
348 request(registry.registry + 'pedding', function(error) {
349 cbk(null, {
350 name: name,
351 registry: registry.registry,
352 time: (+new Date() - start),
353 error: error ? true : false
354 });
355 });
356 }, function(err, results) {
357 getCurrentRegistry(function(cur) {
358 var msg = [''];
359 results.forEach(function(result) {
360 var prefix = result.registry === cur ? '* ' : ' ';
361 var suffix = result.error ? 'Fetch Error' : result.time + 'ms';
362 msg.push(prefix + result.name + line(result.name, 8) + suffix);
363 });
364 msg.push('');
365 printMsg(msg);
366 });
367 });
368}
369
370
371
372/*//////////////// helper methods /////////////////*/
373
374/*
375 * get current registry
376 */
377function getCurrentRegistry(cbk) {
378 npm.load(function(err, conf) {
379 if (err) return exit(err);
380 cbk(npm.config.get('registry'));
381 });
382}
383
384function getCustomRegistry() {
385 return fs.existsSync(NRMRC) ? ini.parse(fs.readFileSync(NRMRC, 'utf-8')) : {};
386}
387
388function setCustomRegistry(config, cbk) {
389 echo(ini.stringify(config), '>', NRMRC, cbk);
390}
391
392function getAllRegistry() {
393 return extend({}, registries, getCustomRegistry());
394}
395
396function printErr(err) {
397 console.error('an error occured: ' + err);
398}
399
400function printMsg(infos) {
401 infos.forEach(function(info) {
402 console.log(info);
403 });
404}
405
406/*
407 * print message & exit
408 */
409function exit(err) {
410 printErr(err);
411 process.exit(1);
412}
413
414function line(str, len) {
415 var line = new Array(Math.max(1, len - str.length)).join('-');
416 return ' ' + line + ' ';
417}