1 | #!/usr/bin/env node
|
2 | var path = require('path');
|
3 | var fs = require('fs');
|
4 | var program = require('commander');
|
5 | var npm = require('npm');
|
6 | var ini = require('ini');
|
7 | var echo = require('node-echo');
|
8 | var extend = require('extend');
|
9 | var open = require('open');
|
10 | var async = require('async');
|
11 | var request = require('request');
|
12 | var only = require('only');
|
13 |
|
14 | var registries = require('./registries.json');
|
15 | var PKG = require('./package.json');
|
16 | var NRMRC = path.join(process.env.HOME, '.nrmrc');
|
17 |
|
18 | var REGISTRY_ATTRS = [];
|
19 | var FIELD_IS_CURRENT = 'is-current';
|
20 | var FIELD_REPOSITORY = 'repository';
|
21 | var IGNORED_ATTRS = [FIELD_IS_CURRENT, FIELD_REPOSITORY];
|
22 |
|
23 |
|
24 | program
|
25 | .version(PKG.version);
|
26 |
|
27 | program
|
28 | .command('ls')
|
29 | .description('List all the registries')
|
30 | .action(onList);
|
31 |
|
32 | program
|
33 | .command('current')
|
34 | .description('Show current registry name')
|
35 | .action(showCurrent);
|
36 |
|
37 | program
|
38 | .command('use <registry>')
|
39 | .description('Change registry to registry')
|
40 | .action(onUse);
|
41 |
|
42 | program
|
43 | .command('add <registry> <url> [home]')
|
44 | .description('Add one custom registry')
|
45 | .action(onAdd);
|
46 |
|
47 | program
|
48 | .command('set-auth <registry> <value> [always]')
|
49 | .description('Set authorize information for a custom registry')
|
50 | .action(onSetAuth);
|
51 |
|
52 | program
|
53 | .command('set-email <registry> <value>')
|
54 | .description('Set email for a custom registry')
|
55 | .action(onSetEmail);
|
56 |
|
57 | program
|
58 | .command('set-hosted-repo <registry> <value>')
|
59 | .description('Set hosted npm repository for a custom registry to publish packages')
|
60 | .action(onSetRepository);
|
61 |
|
62 | program
|
63 | .command('del <registry>')
|
64 | .description('Delete one custom registry')
|
65 | .action(onDel);
|
66 |
|
67 | program
|
68 | .command('home <registry> [browser]')
|
69 | .description('Open the homepage of registry with optional browser')
|
70 | .action(onHome);
|
71 |
|
72 | program
|
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 |
|
81 | program
|
82 | .command('test [registry]')
|
83 | .description('Show response time for specific or all registries')
|
84 | .action(onTest);
|
85 |
|
86 | program
|
87 | .command('help', { isDefault: true })
|
88 | .description('Print this help')
|
89 | .action(function () {
|
90 | program.outputHelp();
|
91 | });
|
92 |
|
93 | program
|
94 | .parse(process.argv);
|
95 |
|
96 |
|
97 | if (process.argv.length === 2) {
|
98 | program.outputHelp();
|
99 | }
|
100 |
|
101 |
|
102 |
|
103 | function 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 |
|
119 | function 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 | }
|
131 | function 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 |
|
147 | function 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 |
|
185 | function 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 |
|
202 | function 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 += '/';
|
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 |
|
219 | function 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 |
|
233 | function 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 |
|
244 | function 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 |
|
255 | function 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 |
|
265 | function 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 |
|
331 | function 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 |
|
373 |
|
374 |
|
375 |
|
376 |
|
377 | function getCurrentRegistry(cbk) {
|
378 | npm.load(function(err, conf) {
|
379 | if (err) return exit(err);
|
380 | cbk(npm.config.get('registry'));
|
381 | });
|
382 | }
|
383 |
|
384 | function getCustomRegistry() {
|
385 | return fs.existsSync(NRMRC) ? ini.parse(fs.readFileSync(NRMRC, 'utf-8')) : {};
|
386 | }
|
387 |
|
388 | function setCustomRegistry(config, cbk) {
|
389 | echo(ini.stringify(config), '>', NRMRC, cbk);
|
390 | }
|
391 |
|
392 | function getAllRegistry() {
|
393 | return extend({}, registries, getCustomRegistry());
|
394 | }
|
395 |
|
396 | function printErr(err) {
|
397 | console.error('an error occured: ' + err);
|
398 | }
|
399 |
|
400 | function printMsg(infos) {
|
401 | infos.forEach(function(info) {
|
402 | console.log(info);
|
403 | });
|
404 | }
|
405 |
|
406 |
|
407 |
|
408 |
|
409 | function exit(err) {
|
410 | printErr(err);
|
411 | process.exit(1);
|
412 | }
|
413 |
|
414 | function line(str, len) {
|
415 | var line = new Array(Math.max(1, len - str.length)).join('-');
|
416 | return ' ' + line + ' ';
|
417 | }
|