UNPKG

34 kBJavaScriptView Raw
1const fs = require('fs');
2const fse = require("fs-extra");
3const path = require("path");
4const urls = require("url");
5const chalk = require('chalk');
6const lodash = require("lodash");
7const child_process = require('child_process');
8const inquirer = require('inquirer');
9const ora = require('ora');
10const request = require('request');
11const tmp = require('tmp');
12const compressing = require('compressing');
13const config = require('../../config');
14const logger = require('../utils/logger');
15
16
17const utils = {
18
19 consoleUrl(support) {
20 if (support === true) {
21 let configFile = path.resolve(process.cwd(), "eeui.config.js");
22 if (fs.existsSync(configFile)) {
23 let releaseConfig = {};
24 try{
25 releaseConfig = require(configFile);
26 }catch (e) {
27 //
28 }
29 if (releaseConfig['consoleUrl'] && this.leftExists(releaseConfig['consoleUrl'], 'http')) {
30 return releaseConfig['consoleUrl'];
31 }
32 }
33 }
34 return 'https://console.eeui.app/';
35 },
36
37 apiUrl(support) {
38 return this.consoleUrl(support) + 'api/';
39 },
40
41 buildJS(cmd = 'build') {
42 console.log(` => ${chalk.blue.bold('npm install&build')}`);
43 return this.exec('npm install', true).then(() => {
44 return this.exec('webpack --env.NODE_ENV=' + cmd);
45 })
46 },
47
48 exec(command, quiet) {
49 return new Promise((resolve, reject) => {
50 try {
51 let child = child_process.exec(command, {encoding: 'utf8'}, () => {
52 resolve();
53 });
54 if (!quiet) {
55 child.stdout.pipe(process.stdout);
56 }
57 child.stderr.pipe(process.stderr);
58 } catch (e) {
59 console.error('execute command failed :', command);
60 reject(e);
61 }
62 })
63 },
64
65 parseDevicesResult(result) {
66 if (!result) {
67 return [];
68 }
69 const devices = [];
70 const lines = result.trim().split(/\r?\n/);
71 for (let i = 0; i < lines.length; i++) {
72 let words = lines[i].split(/[ ,\t]+/).filter((w) => w !== '');
73
74 if (words[1] === 'device') {
75 devices.push(words[0]);
76 }
77 }
78 return devices;
79 },
80
81 mkdirsSync(dirname) {
82 if (fse.existsSync(dirname)) {
83 return true;
84 } else {
85 if (this.mkdirsSync(path.dirname(dirname))) {
86 fse.mkdirSync(dirname);
87 return true;
88 }
89 }
90 },
91
92 getMiddle(string, start, end) {
93 if (this.isHave(start) && this.strExists(string, start)) {
94 string = string.substring(string.indexOf(start) + start.length);
95 } else if (start !== null) {
96 return "";
97 }
98 if (this.isHave(end) && this.strExists(string, end)) {
99 string = string.substring(0, string.indexOf(end));
100 } else if (end !== null) {
101 return "";
102 }
103 return string;
104 },
105
106 isHave(set) {
107 return !!(set !== null && set !== "null" && set !== undefined && set !== "undefined" && set);
108 },
109
110 isNullOrUndefined(obj) {
111 return typeof obj === "undefined" || obj === null;
112 },
113
114 isObject(obj) {
115 return this.isNullOrUndefined(obj) ? false : typeof obj === "object";
116 },
117
118 likeArray(obj) {
119 return this.isObject(obj) && typeof obj.length === 'number';
120 },
121
122 isJson(obj) {
123 return this.isObject(obj) && !this.likeArray(obj);
124 },
125
126 strExists(string, find, lower) {
127 string += "";
128 find += "";
129 if (lower !== true) {
130 string = string.toLowerCase();
131 find = find.toLowerCase();
132 }
133 return (string.indexOf(find) !== -1);
134 },
135
136 leftExists(string, find) {
137 string += "";
138 find += "";
139 return (string.substring(0, find.length) === find);
140 },
141
142 rightExists(string, find) {
143 string += "";
144 find += "";
145 return (string.substring(string.length - find.length) === find);
146 },
147
148 leftDelete(string, find) {
149 string += "";
150 find += "";
151 if (this.leftExists(string, find)) {
152 string = string.substring(find.length)
153 }
154 return string ? string : '';
155 },
156
157 rightDelete(string, find) {
158 string += "";
159 find += "";
160 if (this.rightExists(string, find)) {
161 string = string.substring(0, string.length - find.length)
162 }
163 return string ? string : '';
164 },
165
166 findIndexOf(str, cha, num) {
167 str+= "";
168 cha+= "";
169 let x = str.indexOf(cha);
170 for (let i = 0; i < num; i++) {
171 x = str.indexOf(cha, x + 1);
172 if (x === -1) {
173 break;
174 }
175 }
176 return x;
177 },
178
179 clone(myObj) {
180 if (typeof(myObj) !== 'object') return myObj;
181 if (myObj === null) return myObj;
182 //
183 if (this.likeArray(myObj)) {
184 let [...myNewObj] = myObj;
185 return myNewObj;
186 } else {
187 let {...myNewObj} = myObj;
188 return myNewObj;
189 }
190 },
191
192 count(obj) {
193 try {
194 if (typeof obj === "undefined") {
195 return 0;
196 }
197 if (typeof obj === "number") {
198 obj+= "";
199 }
200 if (typeof obj.length === 'number') {
201 return obj.length;
202 } else {
203 let i = 0, key;
204 for (key in obj) {
205 i++;
206 }
207 return i;
208 }
209 }catch (e) {
210 return 0;
211 }
212 },
213
214 each(elements, callback) {
215 let i, key;
216 if (this.likeArray(elements)) {
217 if (typeof elements.length === "number") {
218 for (i = 0; i < elements.length; i++) {
219 if (callback.call(elements[i], i, elements[i]) === false) return elements
220 }
221 }
222 } else {
223 for (key in elements) {
224 if (!elements.hasOwnProperty(key)) continue;
225 if (callback.call(elements[key], key, elements[key]) === false) return elements
226 }
227 }
228
229 return elements
230 },
231
232 getObject(obj, keys) {
233 let object = obj;
234 if (this.count(obj) === 0 || this.count(keys) === 0) {
235 return "";
236 }
237 let arr = keys.replace(/,/g, "|").replace(/\./g, "|").split("|");
238 this.each(arr, (index, key) => {
239 object = typeof object[key] === "undefined" ? "" : object[key];
240 });
241 return object;
242 },
243
244 moveEmptyDirParent(dirPath) {
245 let lists = this.fileDirDisplay(dirPath);
246 if (lists.dir.length === 0 && lists.file.length === 0) {
247 if (fs.existsSync(dirPath)) {
248 fse.removeSync(dirPath);
249 }
250 this.moveEmptyDirParent(path.resolve(dirPath, '../'));
251 }
252 },
253
254 fileDirDisplay(dirPath, currentDir) {
255 let lists = {
256 'dir': [],
257 'file': [],
258 };
259 let stats = this.pathType(dirPath);
260 switch (stats) {
261 case 1:
262 lists.file.push(dirPath);
263 return lists;
264 case 0:
265 return lists;
266 }
267 let files = fs.readdirSync(dirPath);
268 files.some((filename) => {
269 let filedir = path.join(dirPath, filename);
270 if ([".git", ".DS_Store", "__MACOSX"].indexOf(filename) !== -1) {
271 return false;
272 }
273 if (this.rightExists(filename, ".iml") || this.rightExists(filename, ".xcuserdatad")) {
274 return false;
275 }
276 if (this.rightExists(filedir, path.join("android", "build"))) {
277 return false;
278 }
279 let stats = this.pathType(filedir);
280 if (stats === 1) {
281 lists.file.push(filedir);
282 } else if (stats === 2 && currentDir !== true) {
283 lists.dir.push(filedir);
284 let tmps = this.fileDirDisplay(filedir);
285 lists.dir = lists.dir.concat(tmps.dir);
286 lists.file = lists.file.concat(tmps.file);
287 }
288 });
289 return lists;
290 },
291
292 replaceDictString(path, key, value) {
293 if (!fs.existsSync(path)) {
294 return;
295 }
296 let content = fs.readFileSync(path, 'utf8');
297 let matchs = content.match(/<dict>(.*?)<\/dict>/gs);
298 if (matchs) {
299 matchs.forEach((oldText) => {
300 oldText = oldText.substring(oldText.lastIndexOf('<dict>'), oldText.length);
301 if (this.strExists(oldText, '<string>' + key + '</string>', true)) {
302 let searchValue = this.getMiddle(oldText, '<array>', '</array>');
303 if (searchValue) {
304 searchValue = '<array>' + searchValue + '</array>';
305 let stringValue = '<string>' + this.getMiddle(searchValue, '<string>', '</string>') + '</string>';
306 let replaceValue = searchValue.replace(new RegExp(stringValue, "g"), '<string>' + value + '</string>');
307 let newText = oldText.replace(new RegExp(searchValue, "g"), replaceValue);
308 let result = fs.readFileSync(path, 'utf8').replace(new RegExp(oldText, "g"), newText);
309 if (result) {
310 fs.writeFileSync(path, result, 'utf8');
311 }
312 }
313 }
314 });
315 }
316 },
317
318 replaceEeuiLog(source) {
319 let rege = new RegExp("((\\s|{|\\[|\\(|,|;)console)\\.(debug|log|info|warn|error)\\((.*?)\\)", "g");
320 let result;
321 while ((result = rege.exec(source)) != null) {
322 let newString = result[0].replace(result[1], result[2] + "eeuiLog");
323 source = source.replace(result[0], newString);
324 }
325 return source;
326 },
327
328 replaceModule(source) {
329 var rege = new RegExp("\\.(requireModule|isRegisteredModule)\\(([\'\"])(.*?)\\2\\)", "g");
330 var result;
331 while ((result = rege.exec(source)) != null) {
332 var name = result[3];
333 if ([
334 'websocket',
335 'screenshots',
336 'citypicker',
337 'picture',
338 'rongim',
339 'umeng',
340 'pay',
341 'audio',
342 'deviceInfo',
343 'communication',
344 'geolocation',
345 'recorder',
346 'accelerometer',
347 'compass',
348 'amap',
349 'seekbar',
350 'network',
351 ].indexOf(name) !== -1) {
352 name = 'eeui/' + name;
353 }
354 if (utils.strExists(name, "/")) {
355 var newString = result[0].replace(result[3], utils.spritUpperCase(name));
356 source = source.replace(result[0], newString);
357 }
358 }
359 return source;
360 },
361
362 getQueryString: (search, name) => {
363 let reg = new RegExp("(^|&|\\?)" + name + "=([^&]*)", "i");
364 let r = search.match(reg);
365 if (r != null) return (r[2]);
366 return "";
367 },
368
369 removeRubbish(dirPath) {
370 let lists = [];
371 try {
372 let files = fs.readdirSync(dirPath);
373 files.some((filename) => {
374 let filedir = path.join(dirPath, filename);
375 if ([".git", ".DS_Store", "__MACOSX"].indexOf(filename) !== -1) {
376 fse.removeSync(filedir);
377 lists.push(filedir);
378 return false;
379 }
380 if (this.rightExists(filename, ".iml") || this.rightExists(filename, ".xcuserdatad")) {
381 fse.removeSync(filedir);
382 lists.push(filedir);
383 return false;
384 }
385 if (this.rightExists(filedir, path.join("android", "build"))) {
386 fse.removeSync(filedir);
387 lists.push(filedir);
388 return false;
389 }
390 //
391 let stats = this.pathType(filedir);
392 if (stats === 2) {
393 this.removeRubbish(filedir);
394 }
395 });
396 return lists;
397 }catch (e) {
398 return lists;
399 }
400 },
401
402 /**
403 * @param str
404 * @param defaultVal
405 * @returns {Object|*}
406 */
407 jsonParse(str, defaultVal) {
408 try{
409 return JSON.parse(str);
410 }catch (e) {
411 return defaultVal ? defaultVal : {};
412 }
413 },
414
415 /**
416 *
417 * @param json
418 * @param defaultVal
419 * @returns {string|*}
420 */
421 jsonStringify(json, defaultVal) {
422 try{
423 return JSON.stringify(json);
424 }catch (e) {
425 return defaultVal ? defaultVal : "";
426 }
427 },
428
429 runNum(str, fixed) {
430 let _s = Number(str);
431 if (_s + "" === "NaN") {
432 _s = 0;
433 }
434 if (/^[0-9]*[1-9][0-9]*$/.test(fixed)) {
435 _s = _s.toFixed(fixed);
436 let rs = _s.indexOf('.');
437 if (rs < 0) {
438 _s += ".";
439 for (let i = 0; i < fixed; i++) {
440 _s += "0";
441 }
442 }
443 }
444 return _s;
445 },
446
447 zeroFill(str, length, after) {
448 str += "";
449 if (str.length >= length) {
450 return str;
451 }
452 let _str = '', _ret = '';
453 for (let i = 0; i < length; i++) {
454 _str += '0';
455 }
456 if (after || typeof after === 'undefined') {
457 _ret = (_str + "" + str).substr(length * -1);
458 } else {
459 _ret = (str + "" + _str).substr(0, length);
460 }
461 return _ret;
462 },
463
464 timeStamp() {
465 return Math.round(new Date().getTime() / 1000);
466 },
467
468 formatDate(format, v) {
469 if (format === '') {
470 format = 'Y-m-d H:i:s';
471 }
472 if (typeof v === 'undefined') {
473 v = new Date().getTime();
474 } else if (/^(-)?\d{1,10}$/.test(v)) {
475 v = v * 1000;
476 } else if (/^(-)?\d{1,13}$/.test(v)) {
477 v = v * 1000;
478 } else if (/^(-)?\d{1,14}$/.test(v)) {
479 v = v * 100;
480 } else if (/^(-)?\d{1,15}$/.test(v)) {
481 v = v * 10;
482 } else if (/^(-)?\d{1,16}$/.test(v)) {
483 v = v * 1;
484 } else {
485 return v;
486 }
487 let dateObj = new Date(v);
488 if (parseInt(dateObj.getFullYear()) + "" === "NaN") {
489 return v;
490 }
491 //
492 format = format.replace(/Y/g, dateObj.getFullYear());
493 format = format.replace(/m/g, this.zeroFill(dateObj.getMonth() + 1, 2));
494 format = format.replace(/d/g, this.zeroFill(dateObj.getDate(), 2));
495 format = format.replace(/H/g, this.zeroFill(dateObj.getHours(), 2));
496 format = format.replace(/i/g, this.zeroFill(dateObj.getMinutes(), 2));
497 format = format.replace(/s/g, this.zeroFill(dateObj.getSeconds(), 2));
498 return format;
499 },
500
501 renderSize(value) {
502 if (null == value || value === '') {
503 return "0B";
504 }
505 let unitArr = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
506 let index,
507 srcsize = parseFloat(value);
508 index = Math.floor(Math.log(srcsize) / Math.log(1024));
509 let size = srcsize / Math.pow(1024, index);
510 if (srcsize > 1024 * 1024) {
511 size = size.toFixed(2);
512 }else{
513 size = Math.round(size);
514 }
515 let ret = (size + unitArr[index]) + "";
516 return (ret.indexOf("NaN") !== -1) ? "0B" : ret;
517 },
518
519 execPath(originPath) {
520 return !/(\.web\.map|\.DS_Store|__MACOSX|Thumbs\.db|\.vue)$/.exec(originPath);
521 },
522
523 setToken(token) {
524 let cachePath = path.join(require('os').homedir(), '.' + config.cacheDirName, 'token.cache');
525 fse.ensureFileSync(cachePath);
526 let cache = this.jsonParse(fs.readFileSync(cachePath, 'utf8'));
527 cache.token = token;
528 fs.writeFileSync(cachePath, this.jsonStringify(cache), 'utf8');
529 },
530
531 getToken() {
532 let cachePath = path.join(require('os').homedir(), '.' + config.cacheDirName, 'token.cache');
533 fse.ensureFileSync(cachePath);
534 let cache = this.jsonParse(fs.readFileSync(cachePath, 'utf8'));
535 return this.getObject(cache, 'token');
536 },
537
538 login(support, callback) {
539 if (typeof support === 'function') {
540 callback = support;
541 support = false;
542 }
543 logger.warn('请使用' + utils.consoleUrl(support) + '账号登录');
544 inquirer.prompt([{
545 type: 'input',
546 name: 'username',
547 message: "请输入用户名:",
548 }, {
549 type: 'password',
550 name: 'userpass',
551 message: "请输入登录密码:",
552 }]).then((answers) => {
553 let spinFetch = ora('正在登录...').start();
554 request(utils.apiUrl(support) + 'users/login?username=' + answers.username + "&userpass=" + answers.userpass, (err, res, body) => {
555 spinFetch.stop();
556 let data = this.jsonParse(body);
557 if (data.ret !== 1) {
558 logger.fatal(`登录失败:${data.msg}`);
559 }
560 this.setToken(data.data.token);
561 //
562 if (typeof callback === "function") {
563 callback(data.data);
564 }
565 });
566 }).catch(console.error);
567 },
568
569 logout(callback) {
570 this.setToken("");
571 if (typeof callback === "function") {
572 callback();
573 }
574 },
575
576 projectVersion() {
577 let file = path.resolve(process.cwd(), "eeui.config.js");
578 let pack = path.resolve(process.cwd(), "package.json");
579 let vers = "";
580 if (fse.existsSync(file) && fse.existsSync(pack)) {
581 vers = require(path.resolve(process.cwd(), "package.json")).version;
582 }
583 return vers;
584 },
585
586 versionFunegt(version1, version2) {
587 //前者大或者版本号不正确返回true
588 version1 = (version1 + ".").toLowerCase().replace(/(^\s+)|(\s+$)/gi, "");
589 version2 = (version2 + ".").toLowerCase().replace(/(^\s+)|(\s+$)/gi, "");
590 if (version1 === "." || version2 === ".") {
591 return true;
592 }
593 let array1 = version1.split(".");
594 let array2 = version2.split(".");
595 let result = false;
596 let v2;
597 array1.some((v1, i) => {
598 v1 = v1.trim();
599 v2 = (array2[i] || '').trim();
600 if (v1 === v2) {
601 return false;
602 }
603 result = v1 === [v1, v2].sort()[1];
604 return true;
605 });
606 return result;
607 },
608
609 verifyeeuiProject() {
610 //判断是否eeui项目
611 let file = path.resolve(process.cwd(), "eeui.config.js");
612 if (!fs.existsSync(file)) {
613 logger.fatal(`当前目录非eeui项目,无法进行此操作!`);
614 }
615 //判断eeui-cli版本需求
616 file = path.resolve(process.cwd(), "package.json");
617 if (fs.existsSync(file)) {
618 let packageInfo = utils.jsonParse(fs.readFileSync(file, 'utf8'));
619 let current = require('../../package.json').version;
620 let eeuiclimin = packageInfo.eeuiclimin;
621 if (utils.isHave(eeuiclimin) && utils.versionFunegt(eeuiclimin, current)) {
622 logger.fatal(`当前${chalk.underline(`eeui-cli@${current}`)}版本过低,请升级至${chalk.underline(`eeui-cli@${eeuiclimin}`)}或以上!${chalk.underline(`https://www.npmjs.com/package/eeui-cli`)}`);
623 }
624 }
625 },
626
627 verifyeeuiTemplate() {
628 //判断是否新eeuiApp模板
629 if (utils.versionFunegt("2.0.0", utils.projectVersion())) {
630 logger.fatal(`当前${chalk.underline(`主程序@${utils.projectVersion()}`)}版本过低,请升级主程序!${chalk.underline(`https://eeui.app/guide/update.html`)}`);
631 }
632 },
633
634 pluginsJson(isInstall, op) {
635 let configFile = path.resolve(op.rootDir, "plugins/config.json");
636 let configInfo = utils.jsonParse(!fs.existsSync(configFile) ? {} : fs.readFileSync(configFile, 'utf8'));
637 if (!utils.isJson(configInfo['dependencies'])) {
638 configInfo['dependencies'] = {};
639 }
640 if (isInstall) {
641 if (typeof configInfo['dependencies'][op.name] !== 'object') {
642 configInfo['dependencies'][op.name] = {};
643 }
644 configInfo['dependencies'][op.name]['requireName'] = op.requireName || op.name;
645 configInfo['dependencies'][op.name]['name'] = op.name;
646 configInfo['dependencies'][op.name]['url'] = op.url || "local";
647 } else {
648 if (typeof configInfo['dependencies'][op.name] !== "undefined") {
649 delete configInfo['dependencies'][op.name];
650 }
651 }
652 fs.writeFileSync(configFile, JSON.stringify(this.sortObject(configInfo), null, "\t"), 'utf8')
653 },
654
655 sortObject(obj) {
656 return Object.keys(obj).sort().reduce((a, v) => {
657 a[v] = obj[v];
658 return a;
659 }, {});
660 },
661
662 sendWebSocket(ws, ver, data) {
663 if (data == null || typeof data !== "object") {
664 data = {};
665 }
666 data.version = ver;
667 if (ver === 2) {
668 ws.send(this.jsonStringify(data));
669 }else{
670 ws.send(data.type + ':' + data.value);
671 }
672 },
673
674 getAllAppboards(rundir) {
675 let lists = fs.readdirSync(path.resolve(rundir, 'appboard'));
676 let array = [];
677 lists.forEach((item) => {
678 let sourcePath = path.resolve(rundir, 'appboard/' + item);
679 if (utils.rightExists(sourcePath, ".js")) {
680 let content = fs.readFileSync(sourcePath, 'utf8');
681 let sourceName = path.relative(path.resolve(rundir), sourcePath);
682 if (/^win/.test(process.platform)) {
683 sourceName = sourceName.replace(/\\/g, "/");
684 }
685 array.push({
686 path: sourceName,
687 content: this.replaceModule(this.replaceEeuiLog(content)),
688 });
689 }
690 });
691 return array;
692 },
693
694 /**
695 * 获取演示模板列表(在线版)
696 * @param callback
697 */
698 getOnlineDemoLists(callback) {
699 let array = [];
700 let loading = ora('正在获取演示模板列表...').start();
701 try {
702 request(utils.apiUrl() + 'editor/case/cli_lists', (err, res, body) => {
703 loading.stop();
704 let data = utils.jsonParse(body);
705 if (data.ret === 1) {
706 data.data.forEach((item) => {
707 array.push({
708 name: item.desc + ' (' + item.release + ')',
709 value: item
710 });
711 });
712 callback('', array);
713 }else{
714 callback(data.msg);
715 }
716 });
717 }catch (e) {
718 loading.stop();
719 callback('获取演示模板失败!');
720 }
721 },
722
723 /**
724 * 下载演示模板-①(在线版)
725 * @param tree
726 * @param callback
727 */
728 downOnlineDemo(tree, callback) {
729 let loadText = `正在下载演示模板...`;
730 let loading = ora(loadText);
731 loading.start();
732 try {
733 request(utils.apiUrl() + 'editor/case/cli_downzip?tree=' + tree, (err, res, body) => {
734 loading.stop();
735 let data = utils.jsonParse(body);
736 if (data.ret === 1) {
737 let savePath = path.join(require('os').homedir(), '.' + config.cacheDirName, 'demo');
738 utils.mkdirsSync(savePath);
739 savePath = path.join(savePath, tree + '.zip');
740 loading.start();
741 utils._downloadOnlineDemo(data.data.zipurl, savePath, (err) => {
742 loading.stop();
743 if (err) {
744 callback(err);
745 }else{
746 callback('', savePath);
747 }
748 }, (res) => {
749 loading.text = loadText + `(${res.progress}, ${res.speed})`;
750 })
751 }else{
752 callback(data.msg || '下载演示模板失败!');
753 }
754 });
755 }catch (e) {
756 loading.stop();
757 callback('下载演示模板错误!');
758 }
759 },
760
761 /**
762 * 下载演示模板-②(在线版)
763 * @param url
764 * @param savePath
765 * @param callback
766 * @param progressCall
767 */
768 _downloadOnlineDemo(url, savePath, callback, progressCall) {
769 let file = fs.createWriteStream(savePath);
770 file.on("close", () => {
771 callback()
772 }).on("error", (err) => {
773 callback(err)
774 });
775 //
776 let receivedBytes = 0;
777 let totalBytes = 0;
778 let speedBytes = 0;
779 let speedPer = "0B/S";
780 let speedInt = setInterval(() => {
781 speedPer = utils.renderSize(Math.max(0, receivedBytes - speedBytes)) + "/S";
782 speedBytes = receivedBytes;
783 }, 1000);
784 request.get(url)
785 .on("error", function (err) {
786 callback(`下载模板错误: ${err}`);
787 })
788 .on("response", function (res) {
789 if (res.statusCode !== 200) {
790 callback("Get zipUrl return a non-200 response.");
791 }
792 totalBytes = parseInt(res.headers['content-length'], 10);
793 if (isNaN(totalBytes)) totalBytes = 0;
794 })
795 .on('data', (chunk) => {
796 receivedBytes += chunk.length;
797 let progress = "0%";
798 if (totalBytes > 0) {
799 progress = parseFloat(Math.max(0, receivedBytes / totalBytes * 100).toFixed(2)) + "%";
800 }else{
801 progress = utils.renderSize(receivedBytes);
802 }
803 progressCall && progressCall({
804 received: receivedBytes,
805 total: totalBytes,
806 speed: speedPer,
807 progress: progress
808 });
809 })
810 .on("end", function () {
811 clearInterval(speedInt);
812 })
813 .pipe(file);
814 },
815
816 /**
817 * 压缩目录
818 * @param params = {?output:输出压缩包路径, entry:[{type:'dir', path:原文件夹路径, ?root:压缩根路径}, {type:'file', path:原文件路径, ?root:压缩根路径}]}
819 * @param callback
820 */
821 zipCompress(params, callback) {
822 let output = this.getObject(params, 'output'); //输出压缩包路径
823 let entry = this.getObject(params, 'entry'); //压缩的文件夹路径或文件数组
824 if (this.count(output) === 0) {
825 output = tmp.tmpNameSync({dir: require('os').tmpdir()}) + ".zip";
826 }
827 if (typeof entry === "string") {
828 entry = [{
829 type: 'dir',
830 root: entry,
831 path: entry
832 }];
833 }
834 if (!this.likeArray(entry)) {
835 entry = [entry];
836 }
837 //
838 let tmpPath = tmp.tmpNameSync({dir: require('os').tmpdir()});
839 entry.forEach((item) => {
840 let filePath = item.path;
841 let fileRoot = item.root;
842 let leftPath = path.join(path.resolve(fileRoot || filePath), "/");
843 switch (item.type) {
844 case 'dir':
845 let lists = this.fileDirDisplay(path.resolve(filePath));
846 lists.dir.forEach((tmpItem) => {
847 fse.ensureDirSync(path.resolve(tmpPath, this.leftDelete(tmpItem, leftPath)));
848 });
849 lists.file.forEach((tmpItem) => {
850 fse.copySync(tmpItem, path.resolve(tmpPath, this.leftDelete(tmpItem, leftPath)));
851 });
852 break;
853
854 case 'file':
855 fse.copySync(filePath, path.resolve(tmpPath, this.leftDelete(filePath, leftPath)));
856 break;
857 }
858 });
859 //
860 compressing.zip.compressDir(tmpPath, output, {
861 ignoreBase: true
862 }).then(() => {
863 fse.removeSync(tmpPath);
864 typeof callback === 'function' && callback(output, null);
865 }).catch((err) => {
866 fse.removeSync(tmpPath);
867 typeof callback === 'function' && callback(null, err);
868 });
869 },
870
871 /**
872 * 深复制修改配置文件
873 * @param rundir
874 * @param config
875 */
876 editConfig(rundir, config) {
877 if (config === null || typeof config !== 'object') {
878 return;
879 }
880 let configPath = path.resolve(rundir, 'eeui.config.js');
881 if (fs.existsSync(configPath)) {
882 let newConfig = lodash.merge(require(configPath), config);
883 if (newConfig !== null && typeof newConfig === 'object' && typeof newConfig.appKey !== 'undefined') {
884 let content = '';
885 content += "/**\n * 配置文件\n * 参数详细说明:https://eeui.app/guide/config.html\n */\n";
886 content += "module.exports = ";
887 content += JSON.stringify(newConfig, null, "\t");
888 content += ";";
889 fs.writeFileSync(configPath, content, 'utf8');
890 }
891 }
892 },
893
894 /**
895 * 斜杠格式化(如:aaa/bbb->aaaBbb、AAa/BbB->AAaBbB)
896 * @param string
897 * @returns {string|*}
898 */
899 spritUpperCase(string) {
900 try {
901 return string.replace(/\/+(\w)/g, function ($1) {
902 return $1.toLocaleUpperCase()
903 }).replace(/\//g, '');
904 } catch (e) {
905 return string;
906 }
907 },
908
909 /**
910 * 解析地址
911 * @param url
912 * @returns {{path: string, protocol: string, port: (*|string), query: string, host: string | * | string, source: *, params, hash: string}}
913 */
914 parseURL(url) {
915 let a = urls.parse(url);
916 return {
917 source: url,
918 protocol: (a.protocol || "").replace(':', ''),
919 host: a.hostname || "",
920 port: a.port || "",
921 query: decodeURIComponent(a.search || ""),
922 params: (function() {
923 let params = {},
924 seg = (a.search || "").replace(/^\?/, '').split('&'),
925 len = seg.length,
926 p;
927 for (let i = 0; i < len; i++) {
928 if (seg[i]) {
929 p = seg[i].split('=');
930 params[p[0]] = decodeURIComponent(p[1]);
931 }
932 }
933 return params;
934 })(),
935 hash: (a.hash || "").replace('#', ''),
936 path: (a.pathname || "").replace(/^([^\/])/, '/$1')
937 };
938 },
939
940 /**
941 * 同步eeui.config.js到项目
942 */
943 syncConfigToPlatforms() {
944 let file = path.resolve(process.cwd(), "eeui.config.js");
945 if (!fs.existsSync(file)) {
946 return;
947 }
948 //
949 let eeuiConfig = {};
950 try{
951 delete require.cache[file];
952 eeuiConfig = require(file);
953 }catch (e) {
954 return;
955 }
956 //
957 let androidFile = path.resolve(process.cwd(), "platforms/android/eeuiApp/app/src/main/assets/eeui/config.json");
958 if (fs.existsSync(androidFile)) {
959 let tempConfig = lodash.merge(utils.jsonParse(fs.readFileSync(androidFile, 'utf8')), eeuiConfig);
960 fs.writeFileSync(androidFile, JSON.stringify(tempConfig, null, "\t"), 'utf8')
961 }
962 //
963 let iosFile = path.resolve(process.cwd(), "platforms/ios/eeuiApp/bundlejs/eeui/config.json");
964 if (fs.existsSync(iosFile)) {
965 let tempConfig = lodash.merge(utils.jsonParse(fs.readFileSync(iosFile, 'utf8')), eeuiConfig);
966 fs.writeFileSync(iosFile, JSON.stringify(tempConfig, null, "\t"), 'utf8')
967 }
968 },
969
970 /**
971 * 路径类型(1:文件,2:目录,0:错误)
972 * @param p
973 * @returns {number}
974 */
975 pathType(p) {
976 try {
977 let s = fs.statSync(p);
978 if (s.isFile()) {
979 return 1;
980 } else if (s.isDirectory()) {
981 return 2;
982 }
983 } catch (e) {
984 //
985 }
986 return 0;
987 },
988
989 /**
990 * 目录下只有一个目录时把它移动出来
991 * @param dirPath
992 */
993 onlyOneDirMoveToParent(dirPath) {
994 let tempArray = fs.readdirSync(dirPath);
995 if (utils.count(tempArray) === 1) {
996 tempArray.forEach((tempName) => {
997 let originalDir = path.join(dirPath, tempName);
998 let stats = utils.pathType(originalDir);
999 if (stats === 2) {
1000 let tempDir = path.resolve(dirPath, "../__temp-" + Math.random().toString(36).substring(2));
1001 fse.removeSync(tempDir);
1002 fse.moveSync(originalDir, tempDir, {overwrite: true});
1003 fse.removeSync(dirPath);
1004 fse.moveSync(tempDir, dirPath, {overwrite: true});
1005 fse.removeSync(tempDir);
1006 }
1007 });
1008 }
1009 }
1010};
1011
1012module.exports = utils;