xdc-npm
Version:
xnpm 命令行客户端
179 lines (154 loc) • 4.53 kB
JavaScript
/** !
* Copyright(c) cnpmjs.org and other contributors.
* MIT Licensed
*
* Authors:
* fengmk2 <fengmk2@gmail.com> (http://fengmk2.com)
* dead_horse <dead_horse@qq.com> (http://deadhorse.me)
*/
require('colors');
const debug = require('debug')('xnpm:origin');
const match = require('auto-correct');
const spawn = require('cross-spawn');
const fs = require('fs');
const path = require('path');
const config = require('./config');
const parseArgv = require('./parse_argv');
const binaryMirrorConfig = require('binary-mirror-config').china;
const program = parseArgv();
const rawArgs = program.rawArgs.slice(2);
const args = [];
let isInstall = false;
const isWin = /^win/.test(process.platform);
let hasCNPM = false;
for (let i = 0; i < rawArgs.length; i++) {
let arg = rawArgs[i];
if (arg[0] !== '-') {
arg = correct(arg);
if (arg === 'tnpm') {
arg = '@tencent/tnpm';
console.log('redirect from `tnpm` to `@tencent/tnpm`');
}
if (i === 0 && (arg === 'i' || arg === 'install')) {
isInstall = true;
}
if (arg === '@tencent/tnpm') {
hasCNPM = true;
}
}
args.push(arg);
}
const CWD = process.cwd();
if (program.userconfig && !fs.existsSync(program.userconfig)) {
// make sure userconfig exists
// or it will throw: npm ERR! Error: default value must be string or number
fs.writeFileSync(program.userconfig, 'email =\n');
}
args.unshift(`--registry=${program.registry}`);
args.unshift(`--cache=${program.cache}`);
args.unshift('--no-audit');
if (program.disturl) {
args.unshift(`--disturl=${program.disturl}`);
}
if (program.userconfig) {
args.unshift(`--userconfig=${program.userconfig}`);
}
if (program.proxy) { // 默认用代理实现
args.unshift(`--proxy=${program.proxy}`);
} else {
args.unshift(`--proxy=${config.proxy}`);
}
function getBinaryMirrorsFromConfig() {
const result = {};
for (const binName in binaryMirrorConfig) {
const hostInfo = binaryMirrorConfig[binName];
const tnpmMirrorUrl = replaceWithTnpmMirror(hostInfo.host);
if (tnpmMirrorUrl && Object.keys(hostInfo).length === 1) {
result[binName] = tnpmMirrorUrl;
}
}
return result;
}
// 各种二进制包的参数
// https://github.com/cnpm/binary-mirror-config/blob/master/package.json
const binaryMirrors = Object.assign(getBinaryMirrorsFromConfig(), {
debug: `${config.mirrorsUrl}/node-inspector/`,
profiler: `${config.mirrorsUrl}/node-inspector/`,
node_sqlite3: `${config.mirrorsUrl}/`,
grpc_node: `${config.mirrorsUrl}/`,
fse: `${config.mirrorsUrl}/fsevents/`,
});
for (const binName in binaryMirrors) {
args.unshift(`--${binName}_binary_host_mirror=${binaryMirrors[binName]}`);
}
function finxnpmBin() {
if (isWin && isInstall && hasCNPM) {
// windows在用tnpm安装tnpm的时候,不能自己覆盖自己
return path.join(path.dirname(process.execPath), 'npm');
}
return path.join(__dirname, 'node_modules', '.bin', 'npm');
}
const npmBin = finxnpmBin();
debug('%s %s', npmBin, args.join(' '));
// 只有能被成功替换的才是能被使用的 mirror url,否则不要使用
function replaceWithTnpmMirror(url) {
if (!url) {
return '';
}
if (url.indexOf('https://cdn.npm.taobao.org') > -1) {
return url.replace('https://cdn.npm.taobao.org', config.taobaoNpmCdnUrl);
} if (url.indexOf('https://npm.taobao.org/mirrors') > -1) {
return url.replace('https://npm.taobao.org/mirrors', config.mirrorsUrl);
}
return '';
}
// 环境变量
function getEnvFromConfig() {
const result = {};
for (const k in binaryMirrorConfig.ENVS) {
const v = binaryMirrorConfig.ENVS[k];
const tnpmMirrorUrl = replaceWithTnpmMirror(v);
if (tnpmMirrorUrl) {
result[k] = tnpmMirrorUrl;
}
}
return result;
}
const env = getEnvFromConfig();
for (const k in process.env) {
env[k] = process.env[k];
}
// https://github.com/lovell/sharp/blob/master/install/libvips.js
env.SHARP_DIST_BASE_URL = `${config.taobaoNpmCdnUrl}/dist/sharp-libvips/`;
const npm = spawn(npmBin, args, {
env,
cwd: CWD,
stdio: [
process.stdin,
process.stdout,
process.stderr,
],
});
npm.on('exit', (code, signal) => {
process.exit(code);
});
/**
* correct command
* @return {[type]} [description]
*/
function correct(command) {
const cmds = [
'install',
'publish',
'adduser',
'author',
'config',
'unpublish',
];
for (let i = 0; i < cmds.length; i++) {
if (match(command, cmds[i])) {
return cmds[i];
}
}
return command;
}