1 | const fs = require('fs');
|
2 | const fse = require("fs-extra");
|
3 | const path = require('path');
|
4 | const ora = require('ora');
|
5 | const chalk = require('chalk');
|
6 | const inquirer = require('inquirer');
|
7 | const decompress = require('decompress');
|
8 | const md5File = require('md5-file');
|
9 | const request = require('request');
|
10 | const logger = require('./logger');
|
11 | const config = require("../../config");
|
12 | const utils = require("./index");
|
13 |
|
14 | function start() {
|
15 | let projectPath = path.resolve(process.cwd());
|
16 | let configInfo = require(path.resolve(projectPath, "eeui.config.js"));
|
17 | let serviceUrl = utils.getObject(configInfo, "serviceUrl");
|
18 | if (utils.count(serviceUrl) > 0) {
|
19 | logger.fatal("当前项目已自定义服务端网址(" + serviceUrl + "),自搭建服务端不支持一键云修复文件!");
|
20 | }
|
21 |
|
22 | let zipPackPath = path.resolve(config.zipPackDir);
|
23 | utils.mkdirsSync(zipPackPath);
|
24 | let count = utils.count(zipPackPath);
|
25 | let lists = utils.fileDirDisplay(zipPackPath, true);
|
26 | let files = lists.file.sort().reverse();
|
27 | let choices = [];
|
28 | for (let index in files) {
|
29 | if (!files.hasOwnProperty(index)) continue;
|
30 | if (choices.length >= 100) break;
|
31 | let tmp = files[index];
|
32 | choices.push(tmp.substr(count + 1));
|
33 | }
|
34 | if (choices.length === 0) {
|
35 | logger.fatal(`未找到buildZip文件包!`);
|
36 | }
|
37 | if (choices.length === 1) {
|
38 | logger.fatal(`未找到可对比的buildZip文件包!`);
|
39 | }
|
40 |
|
41 | let newZip,
|
42 | oldZip;
|
43 | inquirer.prompt([{
|
44 | type: 'list',
|
45 | name: 'name',
|
46 | message: `请选择修复包(新包):`,
|
47 | choices: choices,
|
48 | }]).then(function(newAnswers) {
|
49 | newZip = path.join(zipPackPath, newAnswers.name);
|
50 | choices.some((item, index) => {
|
51 | if (item === newAnswers.name) {
|
52 | choices.splice(index, 1);
|
53 | return true;
|
54 | }
|
55 | });
|
56 | inquirer.prompt([{
|
57 | type: 'list',
|
58 | name: 'name',
|
59 | message: `请选择被修复包(旧包):`,
|
60 | choices: choices,
|
61 | }]).then(function(oldAnswers) {
|
62 | oldZip = path.join(zipPackPath, oldAnswers.name);
|
63 | let spinFetch = ora('正在生成差异包...');
|
64 | spinFetch.start();
|
65 |
|
66 | let newPath = utils.rightDelete(newZip, '.zip');
|
67 | let oldPath = utils.rightDelete(oldZip, '.zip');
|
68 | fse.removeSync(newPath);
|
69 | fse.removeSync(oldPath);
|
70 | utils.mkdirsSync(newPath);
|
71 | utils.mkdirsSync(oldPath);
|
72 | decompress(newZip, newPath).then(() => {
|
73 | decompress(oldZip, oldPath).then(() => {
|
74 | let newLists = utils.fileDirDisplay(newPath).file;
|
75 | if (newLists.length === 0) {
|
76 | spinFetch.stop();
|
77 | fse.removeSync(newPath);
|
78 | fse.removeSync(oldPath);
|
79 | logger.fatal(`修复包没有任何文件`);
|
80 | return
|
81 | }
|
82 | let fileLists = [];
|
83 | newLists.forEach((newFile) => {
|
84 | let oldFile = newFile.replace(newPath, oldPath);
|
85 | if (!fs.existsSync(oldFile) || md5File.sync(newFile) !== md5File.sync(oldFile)) {
|
86 | fileLists.push(newFile)
|
87 | }
|
88 | });
|
89 | if (fileLists.length === 0) {
|
90 | spinFetch.stop();
|
91 | fse.removeSync(newPath);
|
92 | fse.removeSync(oldPath);
|
93 | logger.fatal(`没有差异的文件`);
|
94 | return
|
95 | }
|
96 |
|
97 | let diffPackPath = path.resolve(config.diffPackDir);
|
98 | utils.mkdirsSync(diffPackPath);
|
99 | let zipPath = diffPackPath + "/differ-" + utils.rightDelete(utils.leftDelete(newAnswers.name, 'build-'), '.zip') + "-" + utils.rightDelete(utils.leftDelete(oldAnswers.name, 'build-'), '.zip') + ".zip";
|
100 | if (fs.existsSync(zipPath)) {
|
101 | fse.removeSync(zipPath);
|
102 | }
|
103 | let entry = [];
|
104 | fileLists.forEach((tmp) => {
|
105 | entry.push({
|
106 | type: "file",
|
107 | root: newPath,
|
108 | path: tmp,
|
109 | });
|
110 | });
|
111 | utils.zipCompress({
|
112 | output: zipPath,
|
113 | entry: entry
|
114 | }, (output, err) => {
|
115 | spinFetch.stop();
|
116 | fse.removeSync(newPath);
|
117 | fse.removeSync(oldPath);
|
118 | if (err) {
|
119 | logger.fatal(`打包差异文件失败:${err}`);
|
120 | } else {
|
121 | step2(output, fileLists);
|
122 | }
|
123 | });
|
124 | });
|
125 | });
|
126 | });
|
127 | });
|
128 | }
|
129 |
|
130 | function step2(zipPath, fileLists) {
|
131 | logger.sep();
|
132 | logger.success(`找到修复文件${fileLists.length}个。`);
|
133 | logger.sep();
|
134 |
|
135 | let spinFetch = ora('正在获取应用版本...');
|
136 | spinFetch.start();
|
137 | request(utils.apiUrl(true) + 'apps/update?act=applists&token=' + utils.getToken(), (err, res, body) => {
|
138 | spinFetch.stop();
|
139 | let data = utils.jsonParse(body);
|
140 | if (data.ret === -1) {
|
141 | logger.warn('请先登录后再继续!');
|
142 | utils.login(true, () => {
|
143 | step2(zipPath, fileLists);
|
144 | });
|
145 | return;
|
146 | }
|
147 | if (data.ret !== 1) {
|
148 | logger.fatal(data.msg || '系统繁忙,请稍后再试!');
|
149 | }
|
150 | if (data.data.length === 0) {
|
151 | logger.fatal('没有找到应用,请先到控制台添加吧。');
|
152 | }
|
153 |
|
154 | let choices = [];
|
155 | data.data.forEach((item) => {
|
156 | choices.push({
|
157 | name: item.title + '(ID:' + item.id + ')',
|
158 | value: item.id
|
159 | })
|
160 | });
|
161 | inquirer.prompt([{
|
162 | type: 'list',
|
163 | name: 'appid',
|
164 | message: `请选择修复的应用:`,
|
165 | choices: choices,
|
166 | }, {
|
167 | type: 'input',
|
168 | name: 'version',
|
169 | message: "请输入修复的应用版本号(多个半角逗号分隔):",
|
170 | validate: function (value) {
|
171 | let array = (value + "").split(",");
|
172 | if (array.length === 0) {
|
173 | return '请输入要修复的版本号。';
|
174 | }
|
175 | let error = false;
|
176 | array.some((val) => {
|
177 | if (!(Math.ceil(val) === Math.floor(val) && Math.ceil(val) > 0)) {
|
178 | return error = true;
|
179 | }
|
180 | });
|
181 | if (error) {
|
182 | return '输入格式错误,版本号应为整数(多个半角逗号分隔)。';
|
183 | }
|
184 | return true;
|
185 | }
|
186 | }, {
|
187 | type: 'list',
|
188 | name: 'platform',
|
189 | message: '请选择修复的应用平台:',
|
190 | choices: [{
|
191 | name: '修复 Android、iOS',
|
192 | value: 'android,ios'
|
193 | }, {
|
194 | name: '仅修复 Android',
|
195 | value: 'android'
|
196 | }, {
|
197 | name: '仅修复 iOS',
|
198 | value: 'ios'
|
199 | }]
|
200 | }, {
|
201 | type: 'list',
|
202 | name: 'debug',
|
203 | message: '选择是否修复DEBUG版本:',
|
204 | choices: [{
|
205 | name: '排除DEBUG版本',
|
206 | value: 0
|
207 | }, {
|
208 | name: '包含DEBUG版本',
|
209 | value: 1
|
210 | }, {
|
211 | name: '仅DEBUG版本',
|
212 | value: 2
|
213 | }]
|
214 | }, {
|
215 | type: 'list',
|
216 | name: 'update_mode',
|
217 | message: '选择更新模式:',
|
218 | choices: [{
|
219 | name: '启动时触发更新',
|
220 | value: 0
|
221 | }, {
|
222 | name: '客户手动触发更新',
|
223 | value: 1
|
224 | }]
|
225 | }, {
|
226 | type: 'list',
|
227 | name: 'reboot',
|
228 | message: '选择修复完成后行为事件:',
|
229 | choices: [{
|
230 | name: '提示重启',
|
231 | value: 2
|
232 | }, {
|
233 | name: '静默',
|
234 | value: 0
|
235 | }, {
|
236 | name: '自动重启',
|
237 | value: 1
|
238 | }]
|
239 | }, {
|
240 | type: 'list',
|
241 | name: 'clear_cache',
|
242 | message: '选择修复完成后缓存管理:',
|
243 | choices: [{
|
244 | name: '保留缓存',
|
245 | value: 0
|
246 | }, {
|
247 | name: '清除缓存',
|
248 | value: 1
|
249 | }]
|
250 | }, {
|
251 | type: 'input',
|
252 | name: 'title',
|
253 | default: () => {
|
254 | return '一键修复包';
|
255 | },
|
256 | message: "请输入修复备注:",
|
257 | validate: (value) => {
|
258 | return value !== ''
|
259 | }
|
260 | }]).then(function(answers) {
|
261 | answers.zipPath = zipPath;
|
262 | step3(answers, fileLists);
|
263 | });
|
264 | });
|
265 | }
|
266 |
|
267 | function step3(answers, fileLists) {
|
268 | let spinFetch = ora('正在上传差异包...').start();
|
269 | request.post({
|
270 | url: utils.apiUrl(true) + 'apps/update',
|
271 | formData: {
|
272 | act: 'upload',
|
273 | token: utils.getToken(),
|
274 | zipfile: fs.createReadStream(answers.zipPath),
|
275 | }
|
276 | }, (error, response, body) => {
|
277 | spinFetch.stop();
|
278 | let data = utils.jsonParse(body);
|
279 | if (data.ret === -1) {
|
280 | logger.warn('请先登录后再继续!');
|
281 | utils.login(true, () => {
|
282 | step3(answers, fileLists);
|
283 | });
|
284 | return;
|
285 | }
|
286 | if (data.ret !== 1) {
|
287 | logger.fatal(data.msg || '系统繁忙,请稍后再试!');
|
288 | }
|
289 | answers.title = answers.title || "一键修复包";
|
290 | answers.valid = 1;
|
291 | answers.fileinfo = data.data;
|
292 | step4(answers, fileLists);
|
293 | });
|
294 | }
|
295 |
|
296 | function step4(answers, fileLists) {
|
297 | let spinFetch = ora('正在添加修复包...').start();
|
298 | request.post({
|
299 | url: utils.apiUrl(true) + 'apps/update',
|
300 | formData: {
|
301 | act: 'add-from-cli',
|
302 | token: utils.getToken(),
|
303 | D: JSON.stringify(answers),
|
304 | }
|
305 | }, (error, response, body) => {
|
306 | spinFetch.stop();
|
307 | let data = utils.jsonParse(body);
|
308 | if (data.ret === -1) {
|
309 | logger.warn('请先登录后再继续!');
|
310 | utils.login(true, () => {
|
311 | step4(answers, fileLists);
|
312 | });
|
313 | return;
|
314 | }
|
315 | if (data.ret !== 1) {
|
316 | logger.fatal(data.msg || '系统繁忙,请稍后再试!');
|
317 | }
|
318 | logger.sep();
|
319 | logger.success(`添加修复包成功(共${fileLists.length}个文件)。`);
|
320 | logger.info('更多详细设置可登录控制台 ' + chalk.underline(utils.consoleUrl(true)) + ' 查看。');
|
321 | logger.sep();
|
322 | });
|
323 | }
|
324 |
|
325 | module.exports = {start};
|