blob: 2699fa04310887dce5717b33d685cb07143b0ac6 [file] [log] [blame]
"use strict";
const debug = require('debug')('weex:cli');
const fse = require('fs-extra');
const path = require('path');
const colors = require('colors');
const onExist = require('on-exit');
const trash = require('./trash');
const installer = require('./installer');
const getNodeArgs = () => {
const nodeVersion = process.version;
const requiresHarmonyFlagRegex = /^v[45]\./;
const nodeArgs = [];
if (requiresHarmonyFlagRegex.test(nodeVersion)) {
nodeArgs.push("--harmony");
}
return nodeArgs;
};
const outputJson = async (json, file) => {
try {
await fse.outputJson(file, json)
} catch (err) {
console.error(err)
}
}
const readJson = async (file) => {
const content = await fse.readJson(file, { throws: false })
return content;
}
const install = async (name, version, opts) =>{
const start = Date.now();
const pkgFile = path.join(opts.root, 'node_modules', name, 'package.json');
// check lock
const lockFile = path.join(opts.root, '.lock');
const exists = await fse.exists(lockFile);
if (exists && !opts.force) {
let err = new Error('module is locked');
err.type = '_lock';
throw err;
}
let cleared = false;
let succeed = false;
const clear = async () => {
if (!cleared) {
debug('clear, lockfile: %s; succeed: %s; pkgfile: %s', lockFile, succeed, pkgFile);
try {
// unlock
fse.remove(lockFile);
if (!succeed) {
// if install fail, rollback
fse.remove(pkgFile);
}
} catch(e) {
debug('clear error', e.message);
}
cleared = true;
} else {
debug('already cleared');
}
}
// lock
await fse.ensureFile(lockFile);
onExist(clear);
try {
await _install(name, version, opts);
} catch(e) {
clear();
e.type = '_install';
throw e;
}
console.log(colors.yellow('\nStart checking Core, please wait ...'));
try {
await checkDependencies(path.join(opts.root, 'node_modules', name));
} catch(e) {
clear();
e.type = '_check';
throw e;
}
// read pkg again.
try {
pkgFile = await readJson(path.join(opts.root, 'node_modules', name, 'package.json'));
} catch(e) {}
if (!pkgFile) {
pkgFile = {};
}
debug('new package json: %o', pkgFile);
// mark install to success
succeed = true;
clear();
console.log(colors.yellow('compelied, cost ' + (Date.now() - start) / 1000 + 's'));
debug('install core done');
}
const _install = async (name, version, opts) => {
const realDir = path.join(opts.root, 'node_modules');
let t = Date.now();
const exists = await fse.exists(realDir);
if (exists) {
if (process.platform == 'win32') {
debug('use remove');
await fse.remove(realDir);
} else {
debug('use move');
const trashPath = opts.trash + '_core_' + t;
await fse.move(realDir, trashPath);
trash(trashPath);
}
}
debug('trash using: %ds', (Date.now() - t) / 1000);
t = Date.now();
await installer({
'registry': opts.registry || 'https://registry.npmjs.org/',
'root': opts.root,
'pkgs': [{'name': name, 'version': version}]
});
debug('install using: %ds', (Date.now() - t) / 1000);
}
const checkDependencies = async (dir) => {
let t = Date.now();
let pkgData = {};
try {
pkgData = await readJson(path.join(dir, 'package.json'));
} catch(e) {}
const deps = Object.keys(pkgData.dependencies || {});
if (deps.length > 0) {
await deps.map(dep => {
return new Promise(async (resolve, reject) => {
try {
let p = path.join(dir, 'node_modules', dep);
await fse.exists(p)
resolve();
} catch(e) {
reject(e);
}
});
});
}
debug('check using: %ds', (Date.now() - t) / 1000);
}
const confirm = (msg) => {
return new Promise(function resolver(resolve, reject) {
process.stdin.setEncoding('utf8');
process.stdin.resume();
process.stdout.write(msg);
process.stdin.once('data', function(data) {
const choice = data.trim().toLowerCase();
if (choice == 'y' || choice == '') {
resolve(true);
} else {
resolve(false);
}
process.stdin.pause();
});
});
}
module.exports = {
getNodeArgs,
readJson,
install,
confirm
}