madp-cli1
Version:
A simple CLI for scaffolding madp projects, we provide madp-template to quickly build small and medium sized app.
1,641 lines (1,570 loc) • 57.1 kB
JavaScript
const fs = require("fs");
const fse = require("fs-extra");
const path = require("path");
const urls = require("url");
const chalk = require("chalk");
const lodash = require("lodash");
const tmp = require('tmp');
const child_process = require("child_process");
const inquirer = require("inquirer");
const ora = require("ora");
const request = require("request");
const compressing = require("compressing");
const decompress = require("decompress");
delete require.cache[require.resolve('../../config')];
let config = require("../../config");
const logger = require("../utils/logger");
const os = require("os");
const plugin = require("./../../lib/plugin");
const buildApp = require("./../../lib/builder/buildApp");
const shell = require("shelljs");
const qrcode = require("qrcode-terminal");
var FormData = require("form-data");
const LocalStorage = require("node-localstorage").LocalStorage,
localStorage = new LocalStorage(os.homedir() + "/.scratch");
const exec = require("child_process").execFile;
const zipDir = require('./transferZip')
const { idePath } = require("../../config");
let questions = (releaseLists) => {
return [
{
type: "list",
name: "release",
message: "请选择命令",
choices: releaseLists,
},
];
};
// process.stdin.setEncoding('utf8');
const utils = {
delTemplate() {
if(!localStorage.getItem("token")){
console.log('请先登录!');
return false
}
let typeList = localStorage.getItem('typeList')
if (typeList) {
typeList = eval('(' + typeList + ')')
} else {
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 )
typeList = body.data
localStorage.setItem("typeList", JSON.stringify(body.data));
}
}
)
}
inquirer
.prompt([
{
type: "list", // 类型(数字)
name: "type",
message: "请选择要删除的模板类型",
choices: typeList,
},
])
.then((res) => {
request(
{
url: config.serverUrl + "/cli/template/list?code=" + res.type,
method: "GET",
json: true,
headers: {
"content-type": "application/json",
authToken: localStorage.getItem("token"),
},
body: {
// code:ret.code
},
},
function (error, response, body) {
// console.log(body);
if (body.code == '00000' && body.data.length > 0) {
body.data.map((v) => {
v.value = v.code
v.name=v.name+'('+v.version+')'+v.description
});
inquirer
.prompt([
{
type: "list", // 类型(数字)
name: "code",
message: "请选择要删除的模板",
// filter: function (v) {// 最终结果
// return 'name['+v+']'
// },
choices: body.data,
},
])
.then((answers) => {
// console.log(answers);
request(
{
url: config.serverUrl + "/cli/template/delete",
method: "POST",
json: true,
headers: {
"content-type": "application/json",
authToken: localStorage.getItem("token"),
},
body: {
code: answers.code,
},
},
function (error, response, body) {
console.log(body.msg);
}
);
});
} else if (body.data && body.data.length == 0) {
console.log('该类型下无数据');
} else {
console.log(body.msg);
}
}
);
});
},
saveTemplate() {
if(!localStorage.getItem("token")){
console.log('请先登录!');
return false
}
if (!fs.existsSync(path.resolve(config.savePackDir))) {
utils.mkdirsSync(config.savePackDir);
}
let zipName = config.savePackDir +`/uniapp-save${utils.formatDate("YmdHis")}.zip`
let loading = ora('处理中...').start();
zipDir.zipFolder(process.cwd(),zipName,function(){
loading.stop()
let typeList = localStorage.getItem('typeList')
if (typeList) {
typeList = eval('(' + typeList + ')')
}
inquirer
.prompt([
{
type: "input", //
name: "name",
message: "请输入模板名称",
default: '默认模板'
},
{
type: "input",
name: "description",
message: "请输入模板描述",
default: '模板描述'
},
{
type: "input", // 类型(数字)
name: "version",
message: "请输入模板版本",
default: '1.0.1'
},
{
type: "list", // 类型(数字)
name: "type",
message: "请选择模板类型",
choices: typeList || ["ui_project", "seed_project", "template_project"],
},
]).then(answers => {
let loading = ora('保存中...').start();
let form = new FormData();
const file = fs.createReadStream(path.join(process.cwd(), zipName));
form.append("pack", file);
form.append("name", answers.name);
form.append("description", answers.description);
form.append("version", answers.version);
form.append("type", answers.type);
request(
{
url: config.serverUrl + "/cli/template/save",
method: "POST",
headers: {
// "Content-Type": `multipart/form-data; boundary=${form.getBoundary()}`,
"Content-Type": `multipart/form-data; boundary=${form.getBoundary()}`,
authToken: localStorage.getItem("token"),
},
body: form,
},
function (error, response, body) {
loading.stop();
const data = JSON.parse(body);
data ? console.log(`保存${data.msg}`) : console.log(body);
}
);
})
}
)
},
saveTemplate1() {
logger.info("不包含项目中的node_modules及.git等文件");
if(!localStorage.getItem("token")){
console.log('请先登录!');
return false
}
let currentPath = process.cwd();
let originPath = path.join(currentPath, '\/node_modules')
let destinationPath = os.homedir() + '\/.temp_node_modules'
let fileName = `temp-nodemodules`
let finalFilePath = ''
//打包文件如存在先删除
if (fs.existsSync(path.resolve(config.savePackDir))) {
// copyMObj.del(path.resolve(config.savePackDir))
fse.remove(path.resolve(config.savePackDir));
}
//存在nodemodules,先压缩到destinationPath下,并删除当前项目下的nodemodules
if (fs.existsSync(originPath)) {
let loadingO = ora('依赖处理中...').start();
this.compressFile(
fileName,
destinationPath,
function (path) {
finalFilePath = path
loadingO.stop()
// console.log(finalFilePath)
fse.remove(originPath);
let typeList = localStorage.getItem('typeList')
if (typeList) {
typeList = eval('(' + typeList + ')')
}
const _this = this
inquirer
.prompt([
{
type: "input", //
name: "name",
message: "请输入模板名称",
default: '默认模板'
},
{
type: "input",
name: "description",
message: "请输入模板描述",
default: '模板描述'
},
{
type: "input", // 类型(数字)
name: "version",
message: "请输入模板版本",
default: '1.0.1'
},
{
type: "list", // 类型(数字)
name: "type",
message: "请选择模板类型",
choices: typeList || ["ui_project", "seed_project", "template_project"],
},
])
.then((answers) => {
let loading = ora('处理中...').start();
utils.compressFile(
"uniapp-template",
config.savePackDir,
function (path) {
let form = new FormData();
const file = fs.createReadStream(path);
form.append("pack", file);
form.append("name", answers.name);
form.append("description", answers.description);
form.append("version", answers.version);
form.append("type", answers.type);
request(
{
url: config.serverUrl + "/cli/template/save",
method: "POST",
headers: {
// "Content-Type": `multipart/form-data; boundary=${form.getBoundary()}`,
"Content-Type": `multipart/form-data; boundary=${form.getBoundary()}`,
authToken: localStorage.getItem("token"),
},
body: form,
},
function (error, response, body) {
loading.stop();
const data = JSON.parse(body);
data ? console.log(`保存${data.msg}`) : console.log(body);
}
);
if (fs.existsSync(finalFilePath)) {
let loading1 = ora('依赖恢复中...').start();
utils.mkdirsSync(originPath);
decompress(finalFilePath, originPath).then(() => {
console.log('解压成功');
fse.remove(finalFilePath);
})
loading1.stop()
}
},
currentPath
);
});
}, originPath)
} else {
let typeList = localStorage.getItem('typeList')
if (typeList) {
typeList = eval('(' + typeList + ')')
}
inquirer
.prompt([
{
type: "input", //
name: "name",
message: "请输入模板名称",
default: '默认模板'
},
{
type: "input",
name: "description",
message: "请输入模板描述",
default: '模板描述'
},
{
type: "input", // 类型(数字)
name: "version",
message: "请输入模板版本",
default: '1.0.1'
},
{
type: "list", // 类型(数字)
name: "type",
message: "请选择模板类型",
choices: typeList || ["ui_project", "seed_project", "template_project"],
},
])
.then((answers) => {
let loading = ora('处理中...').start();
this.compressFile(
"uniapp-template",
config.savePackDir,
function (path) {
let form = new FormData();
const file = fs.createReadStream(path);
form.append("pack", file);
form.append("name", answers.name);
form.append("description", answers.description);
form.append("version", answers.version);
form.append("type", answers.type);
request(
{
url: config.serverUrl + "/cli/template/save",
method: "POST",
headers: {
// "Content-Type": `multipart/form-data; boundary=${form.getBoundary()}`,
"Content-Type": `multipart/form-data; boundary=${form.getBoundary()}`,
authToken: localStorage.getItem("token"),
},
body: form,
},
function (error, response, body) {
loading.stop();
const data = JSON.parse(body);
data ? console.log(`保存${data.msg}`) : console.log(body);
}
);
},
currentPath
);
});
}
// })
},
saveConfig(args) {
// console.log(args);
let datas = `module.exports = ${JSON.stringify(args, "", "\t")}`;
// console.log(datas);
fs.writeFile("./config.js", datas, "utf8", (err) => {
// \n为换行符
if (err) {
console.log("写入失败");
}
console.log("写入成功");
console.log("如需查看配置内容,请使用config l 命令");
});
},
openIDE() {
let idePath = ''
fs.readFile('./config.js', 'utf8', function (err, result) {
if (err) {
return console.log('文件读取失败!' + err.message);
}
idePath = result.split('idePath":')[1].trim()
idePath = idePath.slice(1, idePath.length - 3)
console.log(idePath);
if (idePath) {
inquirer
.prompt([
{
type: "input", // 类型(数字)
name: "projectName",
message: "请输入当前目录下的项目名称",
},
])
.then((answers) => {
switch (process.platform) {
case "darwin": //unix 系统内核
shell.exec(
`open -a ${idePath} ${answers.projectName}`,
function (code, stdout, stderr) { }
);
break;
case "win32": //windows 系统内核
if (!idePath) {
logger.error("请先配置要打开的IDE安装路径");
return false;
}
exec(idePath, [answers.projectName], function (err, data) {
if (err) {
throw err;
}
});
break;
}
});
} else {
console.log('未找到要打开的IDE,请先使用config命令配置')
}
});
},
showQRcode() {
//1.
//2.在控制台打印二维码
qrcode.generate(
"http://10.110.193.208:8084/",
{ small: true },
function (qrcode) {
console.log(qrcode);
}
);
},
uploadCode() {
if(!localStorage.getItem("token")){
console.log('请先登录!');
return false
}
const dir = "./dist/build";
try {
const files = fs.readdirSync(dir);
if (files && files.length > 0) {
inquirer
.prompt([
{
type: "input", //
name: "appId",
message: "请输入小程序APPID",
},
{
type: "input", //
name: "description",
message: "请输入描述",
},
{
type: "input", //
name: "version",
message: "请输入版本号",
},
{
type: "list", //
name: "uploadDir",
message: "请选择要上传的文件夹",
choices: files,
},
])
.then((answers) => {
console.log(answers);
this.compressFile(
answers.uploadDir || "upload-build",
path.resolve(config.uploadPackDir),
function (path) {
console.log(path);
let form = new FormData();
const file = fs.createReadStream(path);
form.append("pack", file);
form.append("appId", answers.appId);
form.append("description", answers.description);
form.append("version", answers.version);
request(
{
url: config.serverUrl + "/cli/upload",
method: "POST",
headers: {
"Content-Type": `multipart/form-data; boundary=${form.getBoundary()}`,
authToken: localStorage.getItem("token"),
},
body: form,
},
function (error, response, body) {
const data = JSON.parse(body);
console.log(data);
}
);
},
path.resolve("dist/build") + "/" + answers.uploadDir
);
});
} else {
console.log("请先运行build命令,编译后再执行upload进行上传");
}
} catch (err) {
console.log(err);
}
},
compressFile(name, url, callback, currentDir) {
let zipName = name + "-" + utils.formatDate("YmdHis");
let zipPackPath = url;
utils.mkdirsSync(zipPackPath);
let reUrl = zipPackPath + "/" + zipName + ".zip";
// console.log(reUrl);
utils.zipCompress(
{
output: reUrl,
entry: [
{
type: "dir",
path: currentDir || path.resolve(config.distDir),
},
],
},
() => {
// console.log(reUrl)
typeof callback == "function" && callback(reUrl);
}
);
},
//读当前文件夹package。json 缺少就报错
vertPackJson(support, str) {
if (support === true) {
let configFile = path.resolve(process.cwd(), "package.json");
if (fs.existsSync(configFile)) {
fs.readFile("package.json", (err, data) => {
if (err) {
console.log("读取错误");
return;
}
const { scripts } = JSON.parse(data.toString()); //将十六进制转化为字符串,进而转换成对象
let arr = [];
for (key in scripts) {
// console.log(key.includes(str))
// if(key.search('dev')!==-1){
if (key.includes(str)) {
arr.push({ name: key, shell: scripts[key] });
}
}
if (arr.length > 0) {
inquirer.prompt(questions(arr)).then((answers) => {
// console.log("anser", answers);
const myHost = this.getIpAddress();
// console.log(myHost);
this.exec(`npm run ${answers.release}`, false).then((res) => { });
});
}
});
} else {
this.verifyeeuiProject();
this.verifyeeuiTemplate();
if (str == "build") {
plugin.eeuiScript(null, true, () => {
buildApp.build(argv.s === true);
});
}
if (str == "dev") {
plugin.eeuiScript(null, true, () => {
buildApp.dev(argv.s === true);
});
}
}
}
},
//获取本机ip
getIpAddress() {
/**os.networkInterfaces() 返回一个对象,该对象包含已分配了网络地址的网络接口 */
var interfaces = os.networkInterfaces();
for (var devName in interfaces) {
var iface = interfaces[devName];
for (var i = 0; i < iface.length; i++) {
var alias = iface[i];
if (
alias.family === "IPv4" &&
alias.address !== "127.0.0.1" &&
!alias.internal
) {
return alias.address;
}
}
}
},
consoleUrl(support) {
if (support === true) {
let configFile = path.resolve(process.cwd(), "madp.config.js");
if (fs.existsSync(configFile)) {
let releaseConfig = {};
try {
releaseConfig = require(configFile);
} catch (e) {
//
}
if (
releaseConfig["consoleUrl"] &&
this.leftExists(releaseConfig["consoleUrl"], "http")
) {
return releaseConfig["consoleUrl"];
}
}
}
return "https://console.eeui.app/";
},
apiUrl(support) {
return this.consoleUrl(support) + "api/";
},
buildJS(cmd = "build") {
console.log(` => ${chalk.blue.bold("npm install&build")}`);
return this.exec("npm install", true).then(() => {
return this.exec("webpack --env.NODE_ENV=" + cmd);
});
},
execute(command, callback) {
exec1(command, function (error, stdout, stderr) {
callback(stdout);
});
},
exec(command, quiet) {
return new Promise((resolve, reject) => {
try {
let child = child_process.exec(
command,
{ encoding: "utf8" },
(error, stdout, stderr) => {
resolve();
}
);
if (!quiet) {
child.stdout.pipe(process.stdout);
}
// console.log(process.stderr,'22222')
child.stderr.pipe(process.stderr);
} catch (e) {
console.error("execute command failed :", command);
reject(e);
}
});
},
parseDevicesResult(result) {
if (!result) {
return [];
}
const devices = [];
const lines = result.trim().split(/\r?\n/);
for (let i = 0; i < lines.length; i++) {
let words = lines[i].split(/[ ,\t]+/).filter((w) => w !== "");
if (words[1] === "device") {
devices.push(words[0]);
}
}
return devices;
},
mkdirsSync(dirname) {
if (fse.existsSync(dirname)) {
return true;
} else {
if (this.mkdirsSync(path.dirname(dirname))) {
fse.mkdirSync(dirname);
return true;
}
}
},
getMiddle(string, start, end) {
if (this.isHave(start) && this.strExists(string, start)) {
string = string.substring(string.indexOf(start) + start.length);
} else if (start !== null) {
return "";
}
if (this.isHave(end) && this.strExists(string, end)) {
string = string.substring(0, string.indexOf(end));
} else if (end !== null) {
return "";
}
return string;
},
isHave(set) {
return !!(
set !== null &&
set !== "null" &&
set !== undefined &&
set !== "undefined" &&
set
);
},
isNullOrUndefined(obj) {
return typeof obj === "undefined" || obj === null;
},
isObject(obj) {
return this.isNullOrUndefined(obj) ? false : typeof obj === "object";
},
likeArray(obj) {
return this.isObject(obj) && typeof obj.length === "number";
},
isJson(obj) {
return this.isObject(obj) && !this.likeArray(obj);
},
strExists(string, find, lower) {
string += "";
find += "";
if (lower !== true) {
string = string.toLowerCase();
find = find.toLowerCase();
}
return string.indexOf(find) !== -1;
},
leftExists(string, find) {
string += "";
find += "";
return string.substring(0, find.length) === find;
},
rightExists(string, find) {
string += "";
find += "";
return string.substring(string.length - find.length) === find;
},
leftDelete(string, find) {
string += "";
find += "";
if (this.leftExists(string, find)) {
string = string.substring(find.length);
}
return string ? string : "";
},
rightDelete(string, find) {
string += "";
find += "";
if (this.rightExists(string, find)) {
string = string.substring(0, string.length - find.length);
}
return string ? string : "";
},
findIndexOf(str, cha, num) {
str += "";
cha += "";
let x = str.indexOf(cha);
for (let i = 0; i < num; i++) {
x = str.indexOf(cha, x + 1);
if (x === -1) {
break;
}
}
return x;
},
clone(myObj) {
if (typeof myObj !== "object") return myObj;
if (myObj === null) return myObj;
//
if (this.likeArray(myObj)) {
let [...myNewObj] = myObj;
return myNewObj;
} else {
let { ...myNewObj } = myObj;
return myNewObj;
}
},
count(obj) {
try {
if (typeof obj === "undefined") {
return 0;
}
if (typeof obj === "number") {
obj += "";
}
if (typeof obj.length === "number") {
return obj.length;
} else {
let i = 0,
key;
for (key in obj) {
i++;
}
return i;
}
} catch (e) {
return 0;
}
},
each(elements, callback) {
let i, key;
if (this.likeArray(elements)) {
if (typeof elements.length === "number") {
for (i = 0; i < elements.length; i++) {
if (callback.call(elements[i], i, elements[i]) === false)
return elements;
}
}
} else {
for (key in elements) {
if (!elements.hasOwnProperty(key)) continue;
if (callback.call(elements[key], key, elements[key]) === false)
return elements;
}
}
return elements;
},
getObject(obj, keys) {
let object = obj;
if (this.count(obj) === 0 || this.count(keys) === 0) {
return "";
}
let arr = keys.replace(/,/g, "|").replace(/\./g, "|").split("|");
this.each(arr, (index, key) => {
object = typeof object[key] === "undefined" ? "" : object[key];
});
return object;
},
moveEmptyDirParent(dirPath) {
let lists = this.fileDirDisplay(dirPath);
if (lists.dir.length === 0 && lists.file.length === 0) {
if (fs.existsSync(dirPath)) {
fse.removeSync(dirPath);
}
this.moveEmptyDirParent(path.resolve(dirPath, "../"));
}
},
fileDirDisplay(dirPath, currentDir) {
let lists = {
dir: [],
file: [],
};
let stats = this.pathType(dirPath);
switch (stats) {
case 1:
lists.file.push(dirPath);
return lists;
case 0:
return lists;
}
let files = fs.readdirSync(dirPath);
files.some((filename) => {
let filedir = path.join(dirPath, filename);
if ([".git", ".DS_Store", "__MACOSX"].indexOf(filename) !== -1) {
return false;
}
if (
this.rightExists(filename, ".iml") ||
this.rightExists(filename, ".xcuserdatad")
) {
return false;
}
if (this.rightExists(filedir, path.join("android", "build"))) {
return false;
}
let stats = this.pathType(filedir);
if (stats === 1) {
lists.file.push(filedir);
} else if (stats === 2 && currentDir !== true) {
lists.dir.push(filedir);
let tmps = this.fileDirDisplay(filedir);
lists.dir = lists.dir.concat(tmps.dir);
lists.file = lists.file.concat(tmps.file);
}
});
return lists;
},
replaceDictString(path, key, value) {
if (!fs.existsSync(path)) {
return;
}
let content = fs.readFileSync(path, "utf8");
let matchs = content.match(/<dict>(.*?)<\/dict>/g);
if (matchs) {
matchs.forEach((oldText) => {
oldText = oldText.substring(
oldText.lastIndexOf("<dict>"),
oldText.length
);
if (this.strExists(oldText, "<string>" + key + "</string>", true)) {
let searchValue = this.getMiddle(oldText, "<array>", "</array>");
if (searchValue) {
searchValue = "<array>" + searchValue + "</array>";
let stringValue =
"<string>" +
this.getMiddle(searchValue, "<string>", "</string>") +
"</string>";
let replaceValue = searchValue.replace(
new RegExp(stringValue, "g"),
"<string>" + value + "</string>"
);
let newText = oldText.replace(
new RegExp(searchValue, "g"),
replaceValue
);
let result = fs
.readFileSync(path, "utf8")
.replace(new RegExp(oldText, "g"), newText);
if (result) {
fs.writeFileSync(path, result, "utf8");
}
}
}
});
}
},
replaceEeuiLog(source) {
let rege = new RegExp(
"((\\s|{|\\[|\\(|,|;)console)\\.(debug|log|info|warn|error)\\((.*?)\\)",
"g"
);
let result;
while ((result = rege.exec(source)) != null) {
let newString = result[0].replace(result[1], result[2] + "eeuiLog");
source = source.replace(result[0], newString);
}
return source;
},
replaceModule(source) {
var rege = new RegExp(
"\\.(requireModule|isRegisteredModule)\\((['\"])(.*?)\\2\\)",
"g"
);
var result;
while ((result = rege.exec(source)) != null) {
var name = result[3];
if (
[
"websocket",
"screenshots",
"citypicker",
"picture",
"rongim",
"umeng",
"pay",
"audio",
"deviceInfo",
"communication",
"geolocation",
"recorder",
"accelerometer",
"compass",
"amap",
"seekbar",
"network",
].indexOf(name) !== -1
) {
name = "eeui/" + name;
}
if (utils.strExists(name, "/")) {
var newString = result[0].replace(
result[3],
utils.spritUpperCase(name)
);
source = source.replace(result[0], newString);
}
}
return source;
},
getQueryString: (search, name) => {
let reg = new RegExp("(^|&|\\?)" + name + "=([^&]*)", "i");
let r = search.match(reg);
if (r != null) return r[2];
return "";
},
removeRubbish(dirPath) {
let lists = [];
try {
let files = fs.readdirSync(dirPath);
files.some((filename) => {
let filedir = path.join(dirPath, filename);
if ([".git", ".DS_Store", "__MACOSX"].indexOf(filename) !== -1) {
fse.removeSync(filedir);
lists.push(filedir);
return false;
}
if (
this.rightExists(filename, ".iml") ||
this.rightExists(filename, ".xcuserdatad")
) {
fse.removeSync(filedir);
lists.push(filedir);
return false;
}
if (this.rightExists(filedir, path.join("android", "build"))) {
fse.removeSync(filedir);
lists.push(filedir);
return false;
}
//
let stats = this.pathType(filedir);
if (stats === 2) {
this.removeRubbish(filedir);
}
});
return lists;
} catch (e) {
return lists;
}
},
/**
* @param str
* @param defaultVal
* @returns {Object|*}
*/
jsonParse(str, defaultVal) {
try {
return JSON.parse(str);
} catch (e) {
return defaultVal ? defaultVal : {};
}
},
/**
*
* @param json
* @param defaultVal
* @returns {string|*}
*/
jsonStringify(json, defaultVal) {
try {
return JSON.stringify(json);
} catch (e) {
return defaultVal ? defaultVal : "";
}
},
runNum(str, fixed) {
let _s = Number(str);
if (_s + "" === "NaN") {
_s = 0;
}
if (/^[0-9]*[1-9][0-9]*$/.test(fixed)) {
_s = _s.toFixed(fixed);
let rs = _s.indexOf(".");
if (rs < 0) {
_s += ".";
for (let i = 0; i < fixed; i++) {
_s += "0";
}
}
}
return _s;
},
zeroFill(str, length, after) {
str += "";
if (str.length >= length) {
return str;
}
let _str = "",
_ret = "";
for (let i = 0; i < length; i++) {
_str += "0";
}
if (after || typeof after === "undefined") {
_ret = (_str + "" + str).substr(length * -1);
} else {
_ret = (str + "" + _str).substr(0, length);
}
return _ret;
},
timeStamp() {
return Math.round(new Date().getTime() / 1000);
},
formatDate(format, v) {
if (format === "") {
format = "Y-m-d H:i:s";
}
if (typeof v === "undefined") {
v = new Date().getTime();
} else if (/^(-)?\d{1,10}$/.test(v)) {
v = v * 1000;
} else if (/^(-)?\d{1,13}$/.test(v)) {
v = v * 1000;
} else if (/^(-)?\d{1,14}$/.test(v)) {
v = v * 100;
} else if (/^(-)?\d{1,15}$/.test(v)) {
v = v * 10;
} else if (/^(-)?\d{1,16}$/.test(v)) {
v = v * 1;
} else {
return v;
}
let dateObj = new Date(v);
if (parseInt(dateObj.getFullYear()) + "" === "NaN") {
return v;
}
//
format = format.replace(/Y/g, dateObj.getFullYear());
format = format.replace(/m/g, this.zeroFill(dateObj.getMonth() + 1, 2));
format = format.replace(/d/g, this.zeroFill(dateObj.getDate(), 2));
format = format.replace(/H/g, this.zeroFill(dateObj.getHours(), 2));
format = format.replace(/i/g, this.zeroFill(dateObj.getMinutes(), 2));
format = format.replace(/s/g, this.zeroFill(dateObj.getSeconds(), 2));
return format;
},
renderSize(value) {
if (null == value || value === "") {
return "0B";
}
let unitArr = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
let index,
srcsize = parseFloat(value);
index = Math.floor(Math.log(srcsize) / Math.log(1024));
let size = srcsize / Math.pow(1024, index);
if (srcsize > 1024 * 1024) {
size = size.toFixed(2);
} else {
size = Math.round(size);
}
let ret = size + unitArr[index] + "";
return ret.indexOf("NaN") !== -1 ? "0B" : ret;
},
execPath(originPath) {
return !/(\.web\.map|\.DS_Store|__MACOSX|Thumbs\.db|\.vue)$/.exec(
originPath
);
},
setToken(token) {
let cachePath = path.join(
require("os").homedir(),
"." + config.cacheDirName,
"token.cache"
);
fse.ensureFileSync(cachePath);
let cache = this.jsonParse(fs.readFileSync(cachePath, "utf8"));
cache.token = token;
fs.writeFileSync(cachePath, this.jsonStringify(cache), "utf8");
},
getToken() {
let cachePath = path.join(
require("os").homedir(),
"." + config.cacheDirName,
"token.cache"
);
fse.ensureFileSync(cachePath);
let cache = this.jsonParse(fs.readFileSync(cachePath, "utf8"));
return this.getObject(cache, "token");
},
login(support, type, callback) {
if (typeof support === "function") {
callback = support;
support = false;
}
// console.log(localStorage)
logger.warn("请使用管理员提供给您到的账号密码");
inquirer
.prompt([
{
type: "input",
name: "username",
message: "请输入用户名:",
},
{
type: "password",
name: "password",
message: "请输入登录密码:",
},
])
.then((answers) => {
// console.log(answers, localStorage)
if (type == "minprogram") {
let spinFetch = ora("正在登录...").start();
request(
{
url: config.serverUrl + "/cli/login",
method: "POST",
json: true,
headers: {
"content-type": "application/json",
},
body: answers,
},
function (error, response, body) {
spinFetch.stop();
// console.log(body)
if (body.code == "00000" && body.data) {
localStorage.setItem("token", body.data);
}
console.log(body.msg);
}
);
} else {
let spinFetch = ora("正在登录...").start();
request(
utils.apiUrl(support) +
"users/login?username=" +
answers.username +
"&userpass=" +
answers.userpass,
(err, res, body) => {
spinFetch.stop();
let data = this.jsonParse(body);
if (data.ret !== 1) {
logger.fatal(`登录失败:${data.msg}`);
}
this.setToken(data.data.token);
//
if (typeof callback === "function") {
callback(data.data);
}
}
);
}
})
.catch(console.error);
},
logout(callback) {
this.setToken("");
if (typeof callback === "function") {
callback();
}
},
projectVersion() {
let file = path.resolve(process.cwd(), "madp.config.js");
let pack = path.resolve(process.cwd(), "package.json");
let vers = "";
if (fse.existsSync(file) && fse.existsSync(pack)) {
vers = require(path.resolve(process.cwd(), "package.json")).version;
}
return vers;
},
versionFunegt(v1, v2) {
//相等:0,前面大:1,前面小:-1
v1 = (v1 + "")
.toLowerCase()
.replace(/^\s+|\s+$/g, "")
.replace(/^\.|\.$/g, "")
.replace(/^\s+|\s+$/g, "");
v2 = (v2 + "")
.toLowerCase()
.replace(/^\s+|\s+$/g, "")
.replace(/^\.|\.$/g, "")
.replace(/^\s+|\s+$/g, "");
if (v1 === v2) {
return 0;
}
if (/^[0-9]+$/.test(v1) && /^[0-9]+$/.test(v2)) {
v1 = Number(v1);
v2 = Number(v2);
if (v1 === v2) {
return 0;
}
return v1 > v2 ? 1 : -1;
}
let res;
let e1 = /^\d+/.exec(v1);
let e2 = /^\d+/.exec(v2);
if (e1 == null || e2 == null) {
res = [v1, v2].sort()[1];
return res === v1 ? 1 : -1;
}
res = utils.versionFunegt(e1[0], e2[0]);
if (res !== 0) {
return res;
}
return utils.versionFunegt(
v1.substring(e1[0].length),
v2.substring(e2[0].length)
);
},
verifyeeuiProject() {
//判断是否eeui项目
let file = path.resolve(process.cwd(), "madp.config.js");
if (!fs.existsSync(file)) {
logger.fatal(`当前目录缺少madp.config.js,无法进行此操作!`);
}
//判断eeui-cli版本需求
file = path.resolve(process.cwd(), "package.json");
if (fs.existsSync(file)) {
let packageInfo = utils.jsonParse(fs.readFileSync(file, "utf8"));
let current = require("../../package.json").version;
let eeuiclimin = packageInfo.eeuiclimin;
if (
utils.isHave(eeuiclimin) &&
utils.versionFunegt(eeuiclimin, current) > 0
) {
logger.fatal(
`当前${chalk.underline(
`eeui-cli@${current}`
)}版本过低,请升级至${chalk.underline(
`eeui-cli@${eeuiclimin}`
)}或以上!${chalk.underline(
`https://www.npmjs.com/package/eeui-cli`
)}`
);
}
}
// }
},
verifyeeuiTemplate() {
//判断是否新eeuiApp模板
// if (utils.versionFunegt("2.0.0", utils.projectVersion()) > 0) {
// logger.fatal(`当前${chalk.underline(`主程序@${utils.projectVersion()}`)}版本过低,请升级主程序!${chalk.underline(`https://eeui.app/guide/update.html`)}`);
// }
},
pluginsJson(isInstall, op) {
let configFile = path.resolve(op.rootDir, "plugins/config.json");
let configInfo = utils.jsonParse(
!fs.existsSync(configFile) ? {} : fs.readFileSync(configFile, "utf8")
);
if (!utils.isJson(configInfo["dependencies"])) {
configInfo["dependencies"] = {};
}
if (isInstall) {
if (typeof configInfo["dependencies"][op.name] !== "object") {
configInfo["dependencies"][op.name] = {};
}
configInfo["dependencies"][op.name]["requireName"] =
op.requireName || op.name;
configInfo["dependencies"][op.name]["name"] = op.name;
configInfo["dependencies"][op.name]["url"] = op.url || "local";
} else {
if (typeof configInfo["dependencies"][op.name] !== "undefined") {
delete configInfo["dependencies"][op.name];
}
}
fs.writeFileSync(
configFile,
JSON.stringify(this.sortObject(configInfo), null, "\t"),
"utf8"
);
},
sortObject(obj) {
return Object.keys(obj)
.sort()
.reduce((a, v) => {
a[v] = obj[v];
return a;
}, {});
},
sendWebSocket(ws, ver, data) {
if (data == null || typeof data !== "object") {
data = {};
}
data.version = ver;
if (ver === 2) {
ws.send(this.jsonStringify(data));
} else {
ws.send(data.type + ":" + data.value);
}
},
getAllAppboards(rundir) {
let lists = fs.readdirSync(path.resolve(rundir, "appboard"));
let array = [];
lists.forEach((item) => {
let sourcePath = path.resolve(rundir, "appboard/" + item);
let distPath = path.resolve(
rundir,
"../",
config.distDir,
"appboard/" + item
);
if (utils.rightExists(sourcePath, ".js")) {
let content = fs.readFileSync(
fs.existsSync(distPath) ? distPath : sourcePath,
"utf8"
);
let sourceName = path.relative(path.resolve(rundir), sourcePath);
if (/^win/.test(process.platform)) {
sourceName = sourceName.replace(/\\/g, "/");
}
array.push({
path: sourceName,
content: this.replaceModule(this.replaceEeuiLog(content)),
});
}
});
return array;
},
/**
* 获取演示模板列表(在线版)
* @param callback
*/
getOnlineDemoLists(type, callback) {
let array = [];
let loading = ora("正在获取演示模板列表...").start();
try {
//获取所有模板
// https://console.eeui.app/api/editor/case/cli_lists
// request(utils.apiUrl() + 'editor/case/cli_lists', (err, res, body) => {
request(config.templateReleaseUrl, (err, res, body) => {
let data = JSON.parse(body);
// let data={"ret":1,"msg":"success","data":[
// {"release":"1.1","title":"空模板","desc":"空模板","tree":"-1","config":{}},
// {"release":"1.1","title":"madp动态首页","desc":"根据内容管理的配置(json)动态组装eeui首页","tree":"123","config":{}}
// ]}
// body={"ret":1,"msg":"success","data":[{"release":"1.1","title":"helloword","desc":"Hello Word","tree":"5994504e5a799ea62c825224040a28e2","config":{}},{"release":"2.4","title":"official","desc":"\u5b98\u65b9\u6f14\u793a\u6a21\u677f (\u56fd\u9645\u5316)","tree":"b26e17af31027e6cc8551faec428e9a0","config":{}},{"release":"1.2","title":"official-cn","desc":"\u5b98\u65b9\u6f14\u793a\u6a21\u677f (\u4e2d\u6587\u7248)","tree":"6ec02866ffb4b281713241368911b5ab","config":{}},{"release":"1.0","title":"eleme","desc":"\u4eff\u997f\u4e86\u4e48\u5916\u5356","tree":"ad963a9828d2e3028fa368e1a7136345","config":{}},{"release":"1.2","title":"echarts","desc":"echarts\u56fe\u6807","tree":"931f6e86a8d0dd0b8370ee2f58045575","config":{}},{"release":"1.0","title":"login","desc":"\u767b\u5f55\u6ce8\u518c\u9875","tree":"dacffe0319b66a4e0dc530182b5e884b","config":{}},{"release":"1.01","title":"example-demo","desc":"\u4fee\u590d\u56fe\u7247\u663e\u793a\u4e0d\u51fa\u7684bug","tree":"6fcf2d1bfe043acb0b09768c84fb9c05","config":{}},{"release":"1.0","title":"bindingx-demo","desc":"bindingx\u6f14\u793a","tree":"08cac38e81a882bfad6c4174bf0c02d2","config":{}},{"release":"1.0","title":"music-player","desc":"\u97f3\u4e50\u64ad\u653e\u5668","tree":"600c9423e960ddc6e64fe50d1988f07c","config":{}},{"release":"1.0","title":"tiktok","desc":"\u9ad8\u4eff\u6296\u97f3\u6574\u9875\u64ad\u653e\u89c6\u9891","tree":"e93948b23c4567b22540456c08835f7d","config":{}},{"release":"1.0","title":"tabbar-tabcenter","desc":"tabbar\u9876\u90e8tab\u83dc\u5355\u5c45\u4e2d","tree":"fcd0a82ee9ebd1a502f33c27943a5ed8","config":{}},{"release":"1.0","title":"tabbar-coherence","desc":"\u6eda\u52a8\u9875\u9762\u4e2d\u589e\u52a0\u4e00\u4e2atabbar","tree":"7e1da5a752584aa0b45f2528aa9bb200","config":{}},{"release":"1.0","title":"tabbar-immersion","desc":"tabbar\u6bcf\u4e2a\u5b50\u9875\u9762\u9876\u90e8\u72b6\u6001\u680f\u4e0d\u540c\u6548\u679c","tree":"94caefb1595f612b12368ea28d10784c","config":{}}]}
loading.stop();
// let data = utils.jsonParse(body);
// if (data.ret === 1) {
data.forEach((item) => {
if (item.type == type) {
array.push({
name: item.name + " (" + item.tag_version + ")",
value: item,
});
}
});
callback("", array);
// }else{
// callback(data.msg);
// }
});
} catch (e) {
loading.stop();
callback("获取演示模板失败!");
}
},
/**
* 下载演示模板-①(在线版)
* @param tree
* @param callback
*/
downOnlineDemo(info, callback) {
let loadText = `正在下载演示模板...`;
let loading = ora(loadText);
loading.start();
try {
// https://console.eeui.app/api/editor/case/cli_downzip?tree=5994504e5a799ea62c825224040a28e2
// request(utils.apiUrl() + 'editor/case/cli_downzip?tree=' + tree, (err, res, body) => {
// {"ret":1,"msg":"success","data":{"size":5163,"zipurl":"https:\/\/console.eeui.app\/uploads\/temp\/editor\/1\/helloword\/5994504e5a799ea62c825224040a28e2.zip"}}
// let data={"ret":1,"msg":"success","data":{"name":"madp-template-cm","size":5163,"zipurl":"http://localhost:5000/madp-template-cm.zip"}}
// loading.stop();
// let data = utils.jsonParse(body);
// if (data.ret === 1) {
let savePath = path.join(
require("os").homedir(),
"." + config.cacheDirName,
"demo"
);
// console.log(info)
utils.mkdirsSync(savePath);
savePath = path.join(savePath, info.id + ".zip");
// loading.start();
if (!info.zipball_url) {
loading.stop();
callback("", "", info.tag_name);
return;
}
utils._downloadOnlineDemo(
info.zipball_url,
savePath,
(err) => {
loading.stop();
if (err) {
callback(err);
} else {
callback("", savePath, info.tag_name);
}
},
(res) => {
loading.text = loadText + `(${res.progress}, ${res.speed})`;
}
);
// }else{
// callback(data.msg || '下载演示模板失败!');
// }
// });
} catch (e) {
loading.stop();
callback("下载演示模板错误!");
}
},
/**
* 下载演示模板-②(在线版)
* @param url
* @param savePath
* @param callback
* @param progressCall
*/
_downloadOnlineDemo(url, savePath, callback, progressCall) {
let file = fs.createWriteStream(savePath);
file
.on("close", () => {
callback();
})
.on("error", (err) => {
callback(err);
});
//
let receivedBytes = 0;
let totalBytes = 0;
let speedBytes = 0;
let speedPer = "0B/S";
let speedInt = setInterval(() => {
speedPer =
utils.renderSize(Math.max(0, receivedBytes - speedBytes)) + "/S";
speedBytes = receivedBytes;
}, 1000);
request
.get(url)
.on("error", function (err) {
callback(`下载模板错误: ${err}`);
})
.on("response", function (res) {
if (res.statusCode !== 200) {
callback("Get zipUrl return a non-200 response.");
}
totalBytes = parseInt(res.headers["content-length"], 10);
if (isNaN(totalBytes)) totalBytes = 0;
})
.on("data", (chunk) => {
receivedBytes += chunk.length;
let progress = "0%";
if (totalBytes > 0) {
progress =
parseFloat(
Math.max(0, (receivedBytes / totalBytes) * 100).toFixed(2)
) + "%";
} else {
progress = utils.renderSize(receivedBytes);
}
progressCall &&
progressCall({
received: receivedBytes,
total: totalBytes,
speed: speedPer,
progress: progress,
});
})
.on("end", function () {
clearInterval(speedInt);
})
.pipe(file);
},
/**
* 压缩目录
* @param params = {?output:输出压缩包路径, entry:[{type:'dir', path:原文件夹路径, ?root:压缩根路径}, {type:'file', path:原文件路径, ?root:压缩根路径}]}
* @param callback
*/
zipCompress(params, callback) {
// console.log(params);
let output = this.getObject(params, "output"); //输出压缩包路径
let entry = this.getObject(params, "entry"); //压缩的文件夹路径或文件数组
if (this.count(output) === 0) {
output = tmp.tmpNameSync({ dir: require("os").tmpdir() }) + ".zip";
}
if (typeof entry === "string") {
entry = [
{
type: "dir",
root: entry,
path: entry,
},
];
}
if (!this.likeArray(entry)) {
entry = [entry];
}
//
let tmpPath = tmp.tmpNameSync({ dir: require("os").tmpdir() });
entry.forEach((item) => {
let filePath = item.path;
let fileRoot = item.root;
let leftPath = path.join(path.resolve(fileRoot || filePath), "/");
switch (item.type) {
case "dir":
let lists = this.fileDirDisplay(path.resolve(filePath));
lists