madp-cli1
Version:
A simple CLI for scaffolding madp projects, we provide madp-template to quickly build small and medium sized app.
753 lines (737 loc) • 23.2 kB
JavaScript
const yargs = require("yargs");
const path = require("path");
const fse = require("fs-extra");
const chalk = require("chalk");
const inquirer = require("inquirer");
const ora = require("ora");
const decompress = require("decompress");
let config = require("./config");
const logger = require("./lib/utils/logger");
const utils = require("./lib/utils");
const project = require("./lib/utils/project");
const buildApp = require("./lib/builder/buildApp");
const plugin = require("./lib/plugin");
const create = require("./lib/plugin/create");
const publish = require("./lib/plugin/publish");
const update = require("./lib/utils/update");
const shell = require("shelljs");
const processChild = require("child_process");
const tmp = require('tmp');
const os = require("os");
const TemplateRelease = require("./template-release");
const templateRelease = new TemplateRelease(
config.cacheDirName,
config.versionReleaseUrl,
config.templateReleaseUrl,
config.methodsReleaseUrl
);
const isWin = /^win/.test(process.platform);
const fs = require("fs");
const request = require("request");
const LocalStorage = require("node-localstorage").LocalStorage,
localStorage = new LocalStorage(os.homedir()+"/.scratch");
let questions = (inputName, typeLists) => {
let applicationid = "";
return [
{
type: "input",
name: "name",
default: () => {
if (typeof inputName !== "string") inputName = "";
return inputName.trim() ? inputName.trim() : "madp-demo";
},
message: "请输入项目名称",
validate: (value) => {
let pass = value.match(/^[0-9a-z\-_]+$/i);
if (!pass) {
return "输入格式错误,请重新输入。";
}
if (value.indexOf("PluginDemo") > -1) {
return "名称不可包含:PluginDemo。";
}
if (fse.existsSync(value)) {
return "目录[" + value + "]已经存在,请重新输入。";
}
return true;
},
},
{
type: "list",
name: "projectType",
message: "请选择项目工程",
choices: typeLists,
},
];
};
let questions1 = (releaseLists) => {
return [
{
type: "list",
name: "release",
message: "请选择框架版本",
choices: releaseLists,
},
{
type: "list",
name: "location",
message: "请选择下载服务器",
choices: [
{
name: "Github服务器",
value: "github",
},
],
},
];
};
let methodsQuestions = (methodsTypeList) => {
return [
{
type: "list",
name: "methodsType",
message: "请选择方法集类型",
choices: methodsTypeList,
},
];
};
let methodsQuestions1 = (methodsList) => {
return [
{
type: "list",
name: "methodsRelease",
message: "请选择需要添加方法集",
choices: methodsList,
},
];
};
/**
* 创建 eeui 工程.
*/
function initProject(createName) {
// console.log(os.homedir())
if(!localStorage.getItem("token")){
console.log('请先登录!');
return false
}
let spinFetch = ora("正在请求,请稍后...");
spinFetch.start();
//发送请求获取项目类型
request(
{
url: config.serverUrl + "/cli/template/type",
method: "GET",
json: true,
headers: {
"content-type": "application/json",
authToken: localStorage.getItem("token"),
},
body: {},
},
function (error, response, body) {
spinFetch.stop();
if (body.code == "00000") {
body.data.map(v=>v.value=v.code)
// console.log(body.data)
localStorage.setItem("typeList",JSON.stringify( body.data));
inquirer
.prompt([
{
type: "list",
name: "type",
message: "请选创建项目类型",
choices: body.data,
},
])
.then((res) => {
// console.log(res)
const ret = body.data.find((v) => v.code == res.type);
if (ret.code) {
//根据项目类型,获取模板列表
request(
{
url: config.serverUrl + "/cli/template/list?code=" + ret.code,
method: "GET",
json: true,
headers: {
"content-type": "application/json",
authToken: localStorage.getItem("token"),
},
body: {},
},
function (error, response, body) {
// console.log(body.data)
let tempArray = [];
if (body.code == "00000") {
body.data.map((v) => {
v.value = v.code;
v.name=v.name+'('+v.version+')'+v.description
tempArray.push(v);
});
// console.log(tempArray,'tempArray272')
inquirer
.prompt(questions(createName, tempArray))
.then((res) => {
// console.log('answer', res)
let obj = tempArray.find(
(v) => v.code == res.projectType
);
res.projectType = obj.type;
res.zipball_url = obj.downloadUrl;
res.tag_name = obj.name;
res.tag_version = obj.version;
res.release = obj.value;
let _answers = JSON.parse(JSON.stringify(res));
// console.log('_answers', _answers)
let rundir = path.resolve(process.cwd(), res.name);
if (fse.existsSync(_answers.name)) {
logger.fatal(`目录[${_answers.name}]已经存在。`);
return;
}
// templateRelease.fetchRelease(_answers.release, _answers.location, _answers, (error, releasePath) => {
templateRelease._fetchMothods(
_answers,
(err, releasePath) => {
let finalLog = () => {
logger.success("创建项目完成。");
logger.sep();
logger.info("您可以运行一下命令开始。");
logger.info(
chalk.white(`1. cd ${_answers.name}`)
);
logger.info(chalk.white(`2. npm install`));
logger.info(chalk.white(`3. npm run dev`));
};
if (!err) {
finalLog();
}
}
);
});
}
}
);
}
});
} else if (body.code == "A0103") {
console.log(body.msg, ",请先登录");
} else {
console.log(body.msg);
}
}
);
}
/**
* 初始化演示模板
*/
function initDemo(type, callback) {
utils.getOnlineDemoLists(type, (error, demoLists) => {
if (error) {
typeof callback === "function" && callback(error);
return;
}
inquirer
.prompt([
{
type: "list",
name: "demoInfo",
message: "请选择初始化模板",
choices: demoLists,
},
])
.then((answers) => {
// answers=JSON.parse(answers)
utils.downOnlineDemo(answers.demoInfo, (error, downFile, name) => {
if (error) {
typeof callback === "function" && callback(error);
return;
}
typeof callback === "function" &&
callback("", downFile, answers.demoInfo, name);
});
})
.catch(console.error);
});
}
/**
* 设置模板
* @param rundir
*/
function setTemplate(rundir) {
inquirer
.prompt([
{
type: "confirm",
message: `此操作将重置src开发目录,是否继续操作?`,
name: "ok",
},
])
.then((answers) => {
if (answers.ok) {
let type = "madp";
initDemo(type, (error, downFile, info, pathName) => {
if (error) {
logger.warn(error);
return;
}
let srcDir = rundir + "/src";
let srcDir1 = rundir + "/src1";
let srcTmp = "/" + pathName;
decompress(downFile, path.resolve(srcDir1)).then(() => {
fse.copySync(path.resolve(srcDir1) + srcTmp, path.resolve(rundir));
fse.remove(path.resolve(srcDir1), (err) => {});
});
});
} else {
logger.fatal(`放弃设置模板操作!`);
}
})
.catch(console.error);
}
/**
* 列出可用的种子工程版本
*/
function displayReleases() {
let spinPod = ora("正在获取版本信息...");
spinPod.start();
templateRelease.fetchReleaseVersions((err, result) => {
spinPod.stop();
// if (err) {
// logger.fatal(err);
// return;
// }
// let array = [];
// result.some(t => {
// if (!utils.leftExists(t, "2")) {
// return false;
// }
// array.push(t);
// if (array.length >= 10) {
// return true;
// }
// });
let array = result;
// array=[{ name: 'madp-seed(1.0.0)', value: '1.0.0' }]
if (array.length === 0) {
logger.fatal("无可用版本!");
} else {
console.log("可用的种子工程版本:");
array.forEach((t) => {
console.log(chalk.green.underline(t.name));
});
}
});
}
/**
* 列出可用的模板版本
*/
function displayTemplateReleases() {
let spinPod = ora("正在获取模板信息...");
spinPod.start();
templateRelease.fetchTemplateReleaseVersions((err, result) => {
spinPod.stop();
let array = result;
if (array.length === 0) {
logger.fatal("无可用版本!");
} else {
console.log("可用的模板列表:");
array.forEach((t) => {
console.log(chalk.green.underline(t.name));
});
}
});
}
/**
* 生成appKey
* @param {string} path 文件路径.
*/
function changeAppKey(path) {
let configPath = path + "/madp.config.js";
if (!fse.existsSync(configPath)) {
return;
}
let config = require(configPath);
let content = "";
if (config === null || typeof config !== "object") {
return;
}
if (typeof config.appKey === "undefined") {
return;
}
let createRand = (len) => {
len = len || 32;
let $chars =
"ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678oOLl9gqVvUuI1";
let maxPos = $chars.length;
let pwd = "";
for (let i = 0; i < len; i++) {
pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
};
logger.info("正在创建appKey...");
config.appKey = createRand(32);
content +=
"/**\n * 配置文件\n * 参数详细说明:https://eeui.app/guide/config.html\n */\n";
content += "module.exports = ";
content += JSON.stringify(config, null, "\t");
content += ";";
fse.writeFileSync(configPath, content, "utf8");
//
let androidPath =
path + "/platforms/android/eeuiApp/app/src/main/assets/eeui/config.json";
if (fse.existsSync(androidPath)) {
fse.writeFileSync(androidPath, JSON.stringify(config), "utf8");
}
let iosPath = path + "/platforms/ios/eeuiApp/bundlejs/eeui/config.json";
if (fse.existsSync(androidPath)) {
fse.writeFileSync(iosPath, JSON.stringify(config), "utf8");
}
}
/**
* 追加方法集
* 第一步 列出可选择的方法集
* 第二步 选择某个方法集
* 第三步 将选择的方法集追加到已创建工程的src/utils目录下,
* utils目录不存在则先创建空目录,再copy
*/
function addMethods() {
let spinFetch = ora("正在下载方法集列表...");
spinFetch.start();
templateRelease.fetchMethodsRelease((err, result) => {
spinFetch.stop();
console.log("addMethods fetchMethodsRelease||||", result);
let lists = [];
let info = {};
let methodsTypeList = [];
let methodsList = [];
result.some((t) => {
t.value = t.name;
lists.push(t);
methodsList.push(t);
info[t.type] = t.type_name;
});
for (let i in info) {
methodsTypeList.push({ name: info[i], value: i });
}
if (lists.length === 0) {
logger.fatal("没有找到可用的方法集。");
return;
}
inquirer.prompt(methodsQuestions(methodsTypeList)).then((res) => {
console.log(res);
let info = JSON.parse(JSON.stringify(res));
let methodsReleaseList = [];
result.some((t) => {
if (t.type == info.methodsType) methodsReleaseList.push(t);
});
console.log("选择类型后的方法集列表||||", methodsReleaseList);
inquirer.prompt(methodsQuestions1(methodsReleaseList)).then((answer) => {
console.log(answer);
console.log(methodsReleaseList);
let _answer = JSON.parse(JSON.stringify(answer));
console.log("选择的方法集====", _answer.methodsRelease);
for (var [i, methods] of methodsReleaseList.entries()) {
if (methods.name === _answer.methodsRelease) {
_answer = Object.assign(_answer, methods);
}
}
console.log("选择的方法集data===", _answer);
templateRelease.fetchMothods(_answer, (error, releasePath) => {
console.log("templateRelease.fetchMothods=====", releasePath);
});
});
});
});
}
let args = yargs
.command({
command: "create [name]",
desc: "创建一个madp项目",
handler: (argv) => {
if (typeof argv.name === "string") {
if (fse.existsSync(argv.name)) {
logger.fatal(`目录“${argv.name}”已经存在。`);
return;
}
}
initProject(argv.name);
},
})
.command({
command: "lists",
desc: "列出创建可用的种子工程版本",
handler: () => {
displayReleases();
},
})
.command({
command: "template",
// desc: "设置App模板(初始化演示模板)",
desc: "列出创建可用的模板版本",
handler: () => {
displayTemplateReleases();
// utils.verifyeeuiProject();
// setTemplate(path.resolve(process.cwd()));
},
})
// .command({
// command: "update",
// desc: "项目主框架升级至最新版本",
// handler: () => {
// utils.verifyeeuiProject();
// utils.verifyeeuiTemplate();
// update.start();
// }
// })
.command({
command: "add methods",
desc: "追加方法集",
handler: (argv) => {
addMethods();
},
})
.command({
command: "vue [pageName]",
desc: "创建vue页面示例模板",
handler: (argv) => {
utils.verifyeeuiProject();
utils.verifyeeuiTemplate();
let pageName = utils.rightDelete(argv.pageName, ".vue").trim();
if (pageName) {
let dir = path.resolve(process.cwd(), "src");
if (!fse.existsSync(dir)) {
logger.fatal(`目录“src”不存在,当前目录非eeui项目。`);
return;
}
let filePath = dir + "/pages/" + pageName + ".vue";
if (fse.existsSync(filePath)) {
logger.fatal(`文件“${pageName}.vue”已经存在。`);
return;
}
let tmlPath = __dirname + "/lib/template/_template.vue";
if (!fse.existsSync(tmlPath)) {
logger.fatal(`模板文件不存在。`);
return;
}
fse.copySync(tmlPath, filePath);
logger.success(`模板文件“${pageName}.vue”成功创建。`);
} else {
logger.fatal(`请输入要创建的文件名称。`);
}
},
})
// .command({
// command: "plugin [command] [name]",
// desc: "添加、删除、创建或发布插件",
// handler: (argv) => {
// utils.verifyeeuiProject();
// utils.verifyeeuiTemplate();
// let op = {};
// op.name = argv.name;
// op.rootDir = process.cwd();
// op.dir = path.basename(process.cwd());
// op.simple = argv.s === true;
// switch (argv.command) {
// case 'add':
// case 'install':
// case 'i':
// plugin.add(op);
// break;
// case 'del':
// case 'remove':
// case 'uninstall':
// case 'u':
// plugin.remove(op);
// break;
// case 'repair':
// case 'r':
// plugin.repair(op);
// break;
// case 'script':
// plugin.eeuiScript(argv.name, true);
// break;
// case 'unscript':
// plugin.eeuiScript(argv.name, false);
// break;
// case 'create':
// case 'c':
// create.create(op);
// break;
// case 'publish':
// case 'upload':
// case 'p':
// publish.publish(op);
// break;
// }
// }
// })
.command({
command: "login",
desc: "登录",
handler: (argv) => {
utils.login(false, "minprogram");
},
})
.command({
command: "dev",
desc: "编译构造",
handler: (argv) => {
utils.vertPackJson(true, "dev");
// utils.verifyeeuiProject();
// utils.verifyeeuiTemplate();
// plugin.eeuiScript(null, true, () => {
// buildApp.dev(argv.s === true);
// });
},
})
.command({
command: "build",
desc: "编译构造并最小化输出结果",
handler: (argv) => {
utils.vertPackJson(true, "build");
// utils.verifyeeuiProject();
// utils.verifyeeuiTemplate();
// plugin.eeuiScript(null, true, () => {
// buildApp.build(argv.s === true);
// });
},
})
// .command({
// command: "preview",
// desc: "预览",
// handler: (argv) => {
// utils.showQRcode();
// },
// })
.command({
command: "upload",
desc: "上传",
handler: (argv) => {
// console.log(config)
utils.uploadCode();
},
})
.command({
command: "config [name]",
desc: "配置基本项",
handler: (argv) => {
if (argv.name && argv.name == "l") {
fs.readFile('./config.js', 'utf8', function (err, result) {
if (err) {
return console.log('文件读取失败!' + err.message);
}
result=result.split('{')[1].split('}')[0].split(',')
console.log('config.js文件读取成功,内容是:' + result);
});
} else {
switch (process.platform) {
case "darwin": //unix 系统内核
inquirer
.prompt([
{
type: "input", // 类型(数字)
name: "serverUrl",
message:
'请输入你的工具与服务端通信的服务器地址,例如"https://xxxbank.cn/cliserver/api/"',
default: config.serverUrl,
},
{
type: "input", // 类型(数字)
name: "idePath",
message: "请输入mac环境下IDE名称,不能包含空格,如HBuilderX",
default:'HBuilderX'
},
])
.then((answers) => {
// console.log('anser', answers)
config.serverUrl = answers.serverUrl;
config.idePath = answers.idePath;
// console.log(config)
utils.saveConfig(config);
});
break;
case "win32": //windows 系统内核
inquirer
.prompt([
{
type: "input", // 类型(数字)
name: "serverUrl",
message:
'请输入你的工具与服务端通信的服务器地址,例如"https://xxxbank.cn/cliserver/api/"',
default: config.serverUrl,
},
{
type: "input", // 类型(数字)
name: "idePath",
message: "请输入windows环境下IDE打开路径,如D:\\HBuilderX\\HBuilderX.exe",
default:'D:\\HBuilderX\\HBuilderX.exe'
},
])
.then((answers) => {
// console.log('anser', answers)
config.serverUrl = answers.serverUrl;
config.idePath = answers.idePath;
utils.saveConfig(config);
});
break;
}
}
},
})
.command({
command: "ide",
desc: "打开IDE",
handler: (argv) => {
utils.openIDE();
},
})
// .command({
// command: 'config [name]',
// desc: '查看配置',
// handler: (argv) => {
// console.log(argv.name)
// // console.log(config)
// },
// })
.command({
command: "save",
desc: "保存模板",
handler: (argv) => {
utils.saveTemplate();
},
})
.command({
command: "delete",
desc: "删除模板",
handler: (argv) => {
utils.delTemplate();
},
})
// .command({
// command: "publish",
// desc: "发布",
// handler: (argv) => {
// shell.exec(`npm login `, function (code, stdout, stderr) {
// console.log("code", code);
// console.log("Program output:", stdout);
// console.log("Program stderr:", stderr);
// });
// },
// })
.version(() => {
let text =
"madp-cli: " + chalk.underline(require("./package.json").version);
if (utils.projectVersion()) {
text += "\nmadp-template: " + chalk.underline(utils.projectVersion());
}
return text;
})
.help()
.alias({
h: "help",
v: "version",
s: "simple",
})
.strict(true).argv;
//发布模块: npm publish