mya-command-init
Version:
scaffold for mya
430 lines (347 loc) • 12 kB
JavaScript
var Promise = require('bluebird');
var fs = require('fs');
var path = require('path');
var exists = fs.existsSync;
var write = fs.writeFileSync;
var read = function(filepath) {
return fis.util.read(filepath);
};
var rVariable = /\$\{\{([\w\.\-_]+)(?:\s(.*?))?\}\}/g; // 模版中可替换的变量 ${{ conf_name }}
var child_process = require('child_process');
exports.name = 'init';
exports.usage = '<template> [project-name]';
exports.desc = 'scaffold with specifed template.';
exports.register = function(commander) {
var Scaffold = require('fis-scaffold-kernel');
var scaffold;
commander
// .option('-r, --root <path>', 'set project root')
// .option('--token <token>', 'private token')
// .option('-R, --repos <path>', 'set repos path')
// .option('--namespace <namespace>', 'repo namespace')
.action(function(template) {
var args = [].slice.call(arguments);
var options = args.pop();
var settings = {
// todo: root 改为 project name
root: args[1] || '',
token: options.token || 'KvifukV58VJTDNwhiBCG',
namespace: options.namespace || 'mya',
template: args[0] || 'default',
version: 1,
onCollectVariables: null,
onVaraiblesResolved: null,
onContentReplace: null,
onReplaced: null
};
if (!args[0]) {
commander.outputHelp();
return ;
}
// 根据 fis-conf.js 确定 root 目录
Promise.try(function() {
if (!settings.root) {
var findup = require('findup');
return new Promise(function(resolve, reject) {
var fup = findup(process.cwd(), 'fis-conf.js');
var dir = null;
fup.on('found', function(found) {
dir = found;
fup.stop();
});
fup.on('error', reject);
fup.on('end', function() {
resolve(dir);
});
})
.then(function(dir) {
settings.root = dir || process.cwd();
});
} else {
settings.root = path.resolve(process.cwd(), settings.root);
if (!fs.existsSync(settings.root)) {
fs.mkdirSync(settings.root);
}
}
})
// load fis-conf.js if exists.
// 读取用户配置信息。
// .then(function() {
// var filepath = path.resolve(settings.root, 'fis-conf.js');
// if (exists(filepath)) {
// require(filepath);
// }
// })
// downloading...
.then(function() {
fis.log.info('Dir: %s', settings.root);
return new Promise(function(resolve, reject) {
var SimpleTick = require('./lib/tick.js');
var bar;
var repos = settings.template;
var type = fis.config.get('scaffold.type', 'gitlab');
var idx = repos.indexOf(':');
if (~idx) {
type = repos.substring(0, idx);
repos = repos.substring(idx + 1);
}
if (!~repos.indexOf('/')) {
repos = fis.config.get('scaffold.namespace', settings.namespace) + '/scaffold-' + repos;
}
var token = fis.config.get('scaffold.token', settings.token || '');
function progress() {
bar = bar || new SimpleTick('downloading `' + repos + '` ');
bar.tick();
}
scaffold = new Scaffold({
type: type,
repos: options.repos || 'https://code.byted.org/',
log: {
level: 0
}
});
scaffold.download(repos, function(error, location) {
if (error) {
return reject(error);
}
bar.clear();
resolve(location)
}, progress, {token: token});
});
})
.then(function(tempdir) {
var script = path.join(tempdir, '.scaffold.js');
if (exists(script)) {
try {
require(script)(settings);
} catch(e) {}
scaffold.util.del(script);
if (settings.version > 1) {
rVariable = /\$\{\{([\w\.\-_]+)(?:\s+(.+?))?\}\}/g;
}
}
return tempdir;
})
// collect variables.
.then(function(tempdir) {
var files = scaffold.util.find(tempdir);
var variables = {};
files.forEach(function(filename) {
var m;
while ((m = rVariable.exec(filename))) {
variables[m[1]] = variables[m[1]] || m[2];
}
var contents = read(filename);
if (typeof contents !== 'string') {
return;
}
while ((m = rVariable.exec(contents))) {
variables[m[1]] = variables[m[1]] || m[2];
}
});
settings.onCollectVariables && settings.onCollectVariables(variables);
return {
files: files,
variables: variables,
dir: tempdir
};
})
// prompt
.then(function(info) {
var schema = [];
var variables = info.variables;
Object.keys(variables).sort().forEach(function(key) {
var option = variables[key] || {};
schema.push({
name: key,
required: option['default'] !== '::empty',
'default': option['default'] === '::empty' ? '' : option['default'],
'message': option['message'] || ''
});
});
if (schema.length) {
return new Promise(function(resolve, reject) {
scaffold.prompt(schema, function(error, result) {
if (error) {
return reject(error);
}
info.variables = result;
resolve(info);
});
});
}
settings.onVaraiblesResolved && settings.onVaraiblesResolved(info.variables, info);
return info;
})
// replace
.then(function(info) {
var files = info.files;
var variables = info.variables;
files.forEach(function(filepath) {
var contents = read(filepath);
if (typeof contents !== 'string') {
return;
}
contents = contents.replace(rVariable, function(_, key) {
return variables[key];
});
settings.onContentReplace && (contents = settings.onContentReplace(contents, filepath))
write(filepath, contents);
});
settings.onReplaced && settings.onReplaced(info);
return info;
})
// deliver
.then(function(info) {
var files = info.files;
var root = info.dir;
var variables = info.variables;
var roadmap = [];
files.forEach(function(filepath) {
if (rVariable.test(filepath)) {
var pattern = filepath.substring(root.length);
var resolved = pattern.replace(rVariable, function(_, key) {
return variables[key];
});
roadmap.push({
reg: pattern,
release: resolved
});
}
});
// roadmap.push({
// reg: /^\/readme\.md/i,
// release: false
// });
roadmap.push({
reg: /^.*$/i,
release: '$0'
});
scaffold.deliver(root, settings.root, roadmap);
return info;
})
// npm install
.then(function(info) {
var packageJson = path.join(settings.root, 'package.json');
if (exists(packageJson)) {
var config = require(packageJson);
if (config.dependencies || config.devDependencies) {
// run `npm install`
return new Promise(function(resolve, reject) {
scaffold.prompt([{
name: 'Run `npm install`?',
'default': 'y'
}], function(error, result) {
if (error) {
return reject(error);
}
if (/^\s*y\s*$/.test(result['Run `npm install`?'])) {
var spawn = child_process.spawn;
console.log('npm install');
process.stdout.write('downloading...');
var tId = setInterval(function() {
process.stdout.write('.');
}, 1000);
var npm = process.platform === "win32" ? "npm.cmd" : "npm";
var install = spawn(npm, ['install'], {
cwd: settings.root
});
install.stdout.pipe(process.stdout);
install.stderr.pipe(process.stderr);
install.on('error', function(reason) {
clearInterval(tId);
reject(reason);
});
install.on('close', function() {
clearInterval(tId);
resolve(info);
});
install.on('exit', function() {
clearInterval(tId);
});
} else {
resolve(info);
}
});
});
}
}
return info;
})
// fis install
.then(function(info) {
var json = path.join(settings.root, 'component.json');
if (exists(json)) {
var config = require(json);
// run `npm install`
return new Promise(function(resolve, reject) {
scaffold.prompt([{
name: 'Run `fis3 install`?',
'default': 'y'
}], function(error, result) {
if (error) {
return reject(error);
}
if (/^\s*y\s*$/.test(result['Run `fis3 install`?'])) {
var spawn = child_process.spawn;
console.log('npm install');
var spawn = child_process.spawn;
console.log('Installing components...');
var install = spawn(process.execPath, [process.argv[1], 'install']);
install.stdout.pipe(process.stdout);
install.stderr.pipe(process.stderr);
install.on('error', function(reason) {
reject(reason);
});
install.on('close', function() {
resolve(info);
});
} else {
resolve(info);
}
});
});
}
return info;
})
.then(function(info) {
var script = path.join(settings.root, '.build.sh');
if (exists(script)) {
return new Promise(function(resolve, reject) {
scaffold.prompt([{
name: 'Run `.build.sh`?',
'default': 'y'
}], function(error, result) {
if (error) {
return reject(error);
}
if (/^\s*y\s*$/.test(result['Run `.build.sh`?'])) {
var spawn = child_process.spawn;
console.log('sh .build.sh');
var build = spawn('sh', ['.build.sh'], {
cwd: settings.root
});
build.stdout.pipe(process.stdout);
build.stderr.pipe(process.stderr);
build.on('error', function(reason) {
scaffold.util.del(script);
reject(reason);
});
build.on('close', function() {
scaffold.util.del(script);
resolve(info);
});
} else {
scaffold.util.del(script);
resolve(info);
}
});
});
}
return info;
})
.then(function(info) {
console.log('\nDone!');
});
});
};