|
@@ -4,16 +4,14 @@
|
|
|
* Copyright © 2025 imengyu.top imengyu-update-server
|
|
* Copyright © 2025 imengyu.top imengyu-update-server
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-import { confirm , input } from '@inquirer/prompts';
|
|
|
|
|
-import { writeFile, readFile, access, unlink, readdir, stat, constants } from 'node:fs/promises';
|
|
|
|
|
-import { exec } from 'node:child_process';
|
|
|
|
|
-import fs from 'fs';
|
|
|
|
|
-import archiver from 'archiver';
|
|
|
|
|
-import path, { resolve } from 'node:path';
|
|
|
|
|
|
|
+import { confirm, select, input } from '@inquirer/prompts';
|
|
|
|
|
+import { writeFile, readFile, access, unlink, stat, constants } from 'node:fs/promises';
|
|
|
|
|
+import path from 'node:path';
|
|
|
import OSS from 'ali-oss';
|
|
import OSS from 'ali-oss';
|
|
|
import cliProgress from 'cli-progress';
|
|
import cliProgress from 'cli-progress';
|
|
|
import { selectVersion } from './index.mjs';
|
|
import { selectVersion } from './index.mjs';
|
|
|
import { config } from './postConfig.mjs';
|
|
import { config } from './postConfig.mjs';
|
|
|
|
|
+import { readFileRange, compressZip, execAsync } from './utils.mjs';
|
|
|
import { dirname } from 'node:path';
|
|
import { dirname } from 'node:path';
|
|
|
import { fileURLToPath } from 'node:url';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
|
|
|
@@ -23,40 +21,9 @@ import { fileURLToPath } from 'node:url';
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
|
const __dirname = dirname(__filename);
|
|
const __dirname = dirname(__filename);
|
|
|
|
|
|
|
|
-function readFileRange(file, start, length) {
|
|
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
|
|
- fs.open(file, 'r', (err, fd) => {
|
|
|
|
|
- if (err) {
|
|
|
|
|
- reject('Error opening file:', er);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- const buffer = Buffer.alloc(length);
|
|
|
|
|
- fs.read(fd, buffer, 0, length, start, (err, bytesRead, buffer) => {
|
|
|
|
|
- if (err) {
|
|
|
|
|
- reject('Error reading file:', err)
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- fs.close(fd, (err) => {
|
|
|
|
|
- if (err) {
|
|
|
|
|
- reject('Error closing file:', err)
|
|
|
|
|
- return ;
|
|
|
|
|
- }
|
|
|
|
|
- resolve(buffer);
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
-}
|
|
|
|
|
-export function pad(num, n) {
|
|
|
|
|
- var strNum = num.toString();
|
|
|
|
|
- var len = strNum.length;
|
|
|
|
|
- while (len < n) {
|
|
|
|
|
- strNum = "0" + strNum;
|
|
|
|
|
- len++;
|
|
|
|
|
- }
|
|
|
|
|
- return strNum;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+const UPLOAD_APP_TYPE_LOCAL = 1;
|
|
|
|
|
+const UPLOAD_APP_TYPE_ALI_OSS = 2;
|
|
|
|
|
+
|
|
|
async function getConfig() {
|
|
async function getConfig() {
|
|
|
let postConfig = {
|
|
let postConfig = {
|
|
|
lastVersion: '',
|
|
lastVersion: '',
|
|
@@ -82,29 +49,114 @@ async function getUpdateInfo(postConfig) {
|
|
|
let updateInfo = await input({ message: '输入更新信息', default: postConfig.lastUpdateInfo });
|
|
let updateInfo = await input({ message: '输入更新信息', default: postConfig.lastUpdateInfo });
|
|
|
if (updateInfo === 'git') {
|
|
if (updateInfo === 'git') {
|
|
|
console.log('开始获取git提交信息');
|
|
console.log('开始获取git提交信息');
|
|
|
- updateInfo = await new Promise((resolve, reject) => {
|
|
|
|
|
- exec('git log -1 --pretty=format:"%h %s"', (error, stdout, stderr) => {
|
|
|
|
|
- if (error) {
|
|
|
|
|
- reject(error);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- resolve(stdout);
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- console.log('使用git提交信息作为更新信息');
|
|
|
|
|
|
|
+ updateInfo = await execAsync('git log -1 --pretty=format:"%h %s"');
|
|
|
|
|
+ console.log('使用git提交信息 "' + updateInfo + '" 作为更新信息');
|
|
|
}
|
|
}
|
|
|
return updateInfo;
|
|
return updateInfo;
|
|
|
}
|
|
}
|
|
|
|
|
+async function uploadMulitPartLarge(axiosInstance, fileInfo, filePath) {
|
|
|
|
|
+
|
|
|
|
|
+ console.log('开始分片上传');
|
|
|
|
|
+
|
|
|
|
|
+ const multuploadInfo = (await axiosInstance.post('/update-large-token', {
|
|
|
|
|
+ fileSize: fileInfo.size,
|
|
|
|
|
+ fileName: path.basename(filePath)
|
|
|
|
|
+ })).data;
|
|
|
|
|
+ const chunkSize = multuploadInfo.splitPartSize;
|
|
|
|
|
+
|
|
|
|
|
+ const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
|
|
|
|
+ bar1.start(100, 0);
|
|
|
|
|
+
|
|
|
|
|
+ for (let i = 0; i < multuploadInfo.allChunks; i++) {
|
|
|
|
|
+ const start = i * chunkSize;
|
|
|
|
|
+ const len = Math.min(start + chunkSize, fileInfo.size) - start;
|
|
|
|
|
+ const uploadZipContent = await readFileRange(filePath, start, len);
|
|
|
|
|
+ const subFormData = new FormData();
|
|
|
|
|
+ subFormData.append("file", new Blob([ uploadZipContent ], { type : 'application/zip' }), 'upload.zip');
|
|
|
|
|
+ subFormData.append("key", multuploadInfo.key);
|
|
|
|
|
+ subFormData.append("info", JSON.stringify({}));
|
|
|
|
|
+
|
|
|
|
|
+ (await axiosInstance.post('/update-large', subFormData, {
|
|
|
|
|
+ headers: { 'Content-Type': 'multipart/form-data' }
|
|
|
|
|
+ })).data;
|
|
|
|
|
+
|
|
|
|
|
+ bar1.update(Math.floor(i / multuploadInfo.allChunks * 100));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bar1.update(100);
|
|
|
|
|
+ bar1.stop();
|
|
|
|
|
+
|
|
|
|
|
+ return multuploadInfo.key;
|
|
|
|
|
+}
|
|
|
|
|
+async function aliOSSMultipartUpload(client, fileName, uploadFile, progressCallback) {
|
|
|
|
|
+
|
|
|
|
|
+ const fileInfo = await stat(uploadFile); // 获取文件信息
|
|
|
|
|
+ const partSize = 10 * 1024 * 1024; // 分片大小,这里使用10MB
|
|
|
|
|
+ const partCount = Math.ceil(fileInfo.size / partSize); // 计算总分片数
|
|
|
|
|
+
|
|
|
|
|
+ console.log(`开始分片上传到阿里OSS,文件大小: ${(fileInfo.size / 1024 / 1024).toFixed(2)}MB,分片数: ${partCount}`);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 初始化分片上传
|
|
|
|
|
+ const multipartUpload = await client.initMultipartUpload(fileName);
|
|
|
|
|
+ const uploadId = multipartUpload.uploadId;
|
|
|
|
|
+
|
|
|
|
|
+ // 上传分片
|
|
|
|
|
+ const parts = [];
|
|
|
|
|
+ for (let i = 0; i < partCount; i++) {
|
|
|
|
|
+ const start = i * partSize;
|
|
|
|
|
+ const len = Math.min(partSize, fileInfo.size - start);
|
|
|
|
|
+
|
|
|
|
|
+ // 读取文件分片
|
|
|
|
|
+ const fileData = await readFileRange(uploadFile, start, len);
|
|
|
|
|
+
|
|
|
|
|
+ // 上传分片
|
|
|
|
|
+ const partResult = await client.uploadPart(fileName, fileData, uploadId, i + 1);
|
|
|
|
|
+ parts.push({
|
|
|
|
|
+ ETag: partResult.res.headers.etag,
|
|
|
|
|
+ PartNumber: i + 1
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 计算并回调进度
|
|
|
|
|
+ const progress = (i + 1) / partCount;
|
|
|
|
|
+ if (progressCallback) {
|
|
|
|
|
+ progressCallback(progress);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ console.log(`已上传分片 ${i + 1}/${partCount} (${(progress * 100).toFixed(2)}%)`);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 完成分片上传
|
|
|
|
|
+ await client.completeMultipartUpload(fileName, uploadId, parts);
|
|
|
|
|
+
|
|
|
|
|
+ console.log('阿里OSS分片上传完成');
|
|
|
|
|
+
|
|
|
|
|
+ // 获取上传后的文件URL
|
|
|
|
|
+ const url = await client.generateObjectUrl(fileName);
|
|
|
|
|
+ return url;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('阿里OSS分片上传失败:', error);
|
|
|
|
|
+ throw error;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
//App更新与提交
|
|
//App更新与提交
|
|
|
//========================================
|
|
//========================================
|
|
|
|
|
|
|
|
export async function postAppUpdate(axiosInstance, param) {
|
|
export async function postAppUpdate(axiosInstance, param) {
|
|
|
const postConfig = await getConfig();
|
|
const postConfig = await getConfig();
|
|
|
- const versionId = await selectVersion(false, postConfig.lastVersion);
|
|
|
|
|
|
|
+ const { versionId, versionName } = await selectVersion(postConfig.lastVersion);
|
|
|
const updateInfo = await getUpdateInfo(postConfig);
|
|
const updateInfo = await getUpdateInfo(postConfig);
|
|
|
|
|
|
|
|
- await axiosInstance.post('/update-post', { config: { type: 2, test: true, versionId, uploadWebConfig: config.uploadWebConfig, submitKey: config.submitKey } });
|
|
|
|
|
|
|
+ const serverConfig = await axiosInstance.post('/update-post', {
|
|
|
|
|
+ config: {
|
|
|
|
|
+ type: 2,
|
|
|
|
|
+ test: true,
|
|
|
|
|
+ versionId,
|
|
|
|
|
+ uploadAppConfig: {},
|
|
|
|
|
+ submitKey: config.submitKey
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
postConfig.lastVersion = versionId;
|
|
postConfig.lastVersion = versionId;
|
|
|
postConfig.lastUpdateInfo = updateInfo;
|
|
postConfig.lastUpdateInfo = updateInfo;
|
|
@@ -126,13 +178,13 @@ export async function postAppUpdate(axiosInstance, param) {
|
|
|
}));
|
|
}));
|
|
|
|
|
|
|
|
const force = await confirm({ message: '强制更新?', default: false });
|
|
const force = await confirm({ message: '强制更新?', default: false });
|
|
|
- const updateNext = hotfix ? false : await confirm({ message: '作为下个版本?', default: false });
|
|
|
|
|
- const versionCode = config.buildAppGetVersion();
|
|
|
|
|
|
|
+ const updateNext = await confirm({ message: '作为下个版本?', default: false });
|
|
|
|
|
+ const versionCode = await config.buildAppGetVersion(versionName);
|
|
|
|
|
|
|
|
await saveConfig(postConfig);
|
|
await saveConfig(postConfig);
|
|
|
|
|
|
|
|
if (updateSource === 'rebuild')
|
|
if (updateSource === 'rebuild')
|
|
|
- await config.buildAppCallback(param, versionCode, postConfig.lastTodaySubVersion);
|
|
|
|
|
|
|
+ await config.buildAppCallback(param, versionCode, versionName, postConfig.lastTodaySubVersion);
|
|
|
else if (updateSource === 'uploaded-alioss') {
|
|
else if (updateSource === 'uploaded-alioss') {
|
|
|
const fileName = await input({ message: '输入已上传的阿里OSS文件路径' });
|
|
const fileName = await input({ message: '输入已上传的阿里OSS文件路径' });
|
|
|
try {
|
|
try {
|
|
@@ -161,7 +213,8 @@ export async function postAppUpdate(axiosInstance, param) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const uploadFile = await config.buildAppGetUploadFile(param);
|
|
|
|
|
|
|
+ const uploadFile = await config.buildAppGetUploadFile(param, versionCode, versionName);
|
|
|
|
|
+ const fileName = `${await config.buildAppGetOSSFileName(param, versionCode, path.basename(uploadFile), uploadFile)}`;
|
|
|
try {
|
|
try {
|
|
|
await access(uploadFile, constants.R_OK)
|
|
await access(uploadFile, constants.R_OK)
|
|
|
} catch {
|
|
} catch {
|
|
@@ -178,12 +231,16 @@ export async function postAppUpdate(axiosInstance, param) {
|
|
|
|
|
|
|
|
const formData = new FormData();
|
|
const formData = new FormData();
|
|
|
formData.append("file", new Blob([ appData ], { type : 'application/zip' }));
|
|
formData.append("file", new Blob([ appData ], { type : 'application/zip' }));
|
|
|
- formData.append("type", 2);
|
|
|
|
|
- formData.append("versionId", versionId);
|
|
|
|
|
- formData.append("updateInfo", updateInfo);
|
|
|
|
|
- formData.append("uploadAppConfig", { updateAsNext: updateNext });
|
|
|
|
|
- formData.append("force", force);
|
|
|
|
|
- formData.append("versionCode", versionCode);
|
|
|
|
|
|
|
+ formData.append("config", JSON.stringify({
|
|
|
|
|
+ type: 2,
|
|
|
|
|
+ versionId,
|
|
|
|
|
+ versionCode,
|
|
|
|
|
+ updateInfo,
|
|
|
|
|
+ updateCustomConfig: await config.getCustomConfig(param, true, versionName),
|
|
|
|
|
+ uploadAppConfig: { updateAsNext: updateNext },
|
|
|
|
|
+ force,
|
|
|
|
|
+ fileName,
|
|
|
|
|
+ }));
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
const result = (await axiosInstance.post('/update-post', formData, {
|
|
const result = (await axiosInstance.post('/update-post', formData, {
|
|
@@ -191,67 +248,80 @@ export async function postAppUpdate(axiosInstance, param) {
|
|
|
})).data;
|
|
})).data;
|
|
|
console.log('上传成功');
|
|
console.log('上传成功');
|
|
|
console.log('新更新ID: ' + result.updateId);
|
|
console.log('新更新ID: ' + result.updateId);
|
|
|
- console.log('删除构建文件');
|
|
|
|
|
-
|
|
|
|
|
- await unlink(uploadFile);
|
|
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
console.error('上传失败', e);
|
|
console.error('上传失败', e);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
} else {
|
|
} else {
|
|
|
- //阿里OSS上传
|
|
|
|
|
- //请求STS进行临时授权
|
|
|
|
|
- const stsToken = (await axiosInstance.post('/update-ali-oss-sts')).data;
|
|
|
|
|
- const client = new OSS({
|
|
|
|
|
- region: stsToken.Region,
|
|
|
|
|
- accessKeyId: stsToken.AccessKeyId,
|
|
|
|
|
- accessKeySecret: stsToken.AccessKeySecret,
|
|
|
|
|
- stsToken: stsToken.SecurityToken,
|
|
|
|
|
- bucket: stsToken.Bucket,
|
|
|
|
|
- refreshSTSToken: async () => {
|
|
|
|
|
- const refreshToken = (await axiosInstance.get("/update-ali-oss-sts")).data;
|
|
|
|
|
- return {
|
|
|
|
|
- accessKeyId: refreshToken.AccessKeyId,
|
|
|
|
|
- accessKeySecret: refreshToken.AccessKeySecret,
|
|
|
|
|
- stsToken: refreshToken.SecurityToken,
|
|
|
|
|
- };
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- //小于96mb则直接上传,否则分片上传
|
|
|
|
|
- const fileName = `/${await config.buildAppGetOSSFileName(param)}`;
|
|
|
|
|
|
|
|
|
|
- console.log('Start upload to ali oss');
|
|
|
|
|
|
|
+ let ossConfig;
|
|
|
|
|
+ let multuploadedKey;
|
|
|
|
|
+
|
|
|
|
|
+ if (serverConfig.uploadAppType === UPLOAD_APP_TYPE_LOCAL) {
|
|
|
|
|
+ //本地大文件上传
|
|
|
|
|
+ multuploadedKey = await uploadMulitPartLarge(axiosInstance, fileInfo, uploadFile);
|
|
|
|
|
+ } else if (serverConfig.uploadAppType === UPLOAD_APP_TYPE_ALI_OSS) {
|
|
|
|
|
+ //阿里OSS上传
|
|
|
|
|
+ //请求STS进行临时授权
|
|
|
|
|
+ const stsToken = (await axiosInstance.post('/update-ali-oss-sts')).data;
|
|
|
|
|
+ const client = new OSS({
|
|
|
|
|
+ region: stsToken.Region,
|
|
|
|
|
+ accessKeyId: stsToken.AccessKeyId,
|
|
|
|
|
+ accessKeySecret: stsToken.AccessKeySecret,
|
|
|
|
|
+ stsToken: stsToken.SecurityToken,
|
|
|
|
|
+ bucket: stsToken.Bucket,
|
|
|
|
|
+ refreshSTSToken: async () => {
|
|
|
|
|
+ const refreshToken = (await axiosInstance.get("/update-ali-oss-sts")).data;
|
|
|
|
|
+ return {
|
|
|
|
|
+ accessKeyId: refreshToken.AccessKeyId,
|
|
|
|
|
+ accessKeySecret: refreshToken.AccessKeySecret,
|
|
|
|
|
+ stsToken: refreshToken.SecurityToken,
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ //小于96mb则直接上传,否则分片上传
|
|
|
|
|
+
|
|
|
|
|
+ console.log('Start upload to ali oss');
|
|
|
|
|
+
|
|
|
|
|
+ let returnUrl = '';
|
|
|
|
|
+ if (fileInfo.size < 96 * 1024 * 1024) {
|
|
|
|
|
+ const result = await client.put(fileName, uploadFile);
|
|
|
|
|
+ returnUrl = result.url;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
|
|
|
|
+ bar1.start(100, 0);
|
|
|
|
|
+ returnUrl = await aliOSSMultipartUpload(client, fileName, uploadFile, (p) => {
|
|
|
|
|
+ bar1.update(p * 100);
|
|
|
|
|
+ });
|
|
|
|
|
+ bar1.update(100);
|
|
|
|
|
+ bar1.stop();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- let returnUrl = '';
|
|
|
|
|
- if (fileInfo.size < 96 * 1024 * 1024) {
|
|
|
|
|
- const result = await client.put(fileName, uploadFile);
|
|
|
|
|
- returnUrl = result.url;
|
|
|
|
|
|
|
+ ossConfig = {
|
|
|
|
|
+ ossPath: fileName,
|
|
|
|
|
+ ossPublic: returnUrl,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ console.log('Upload to ali oss done');
|
|
|
} else {
|
|
} else {
|
|
|
- const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
|
|
|
|
- bar1.start(100, 0);
|
|
|
|
|
- await aliOSSMultipartUpload(client, fileName, uploadFile, (p) => {
|
|
|
|
|
- bar1.update(p * 100);
|
|
|
|
|
- });
|
|
|
|
|
- bar1.update(100);
|
|
|
|
|
- bar1.stop();
|
|
|
|
|
|
|
+ console.error('错误的 uploadAppType 配置 ' + serverConfig.uploadAppType);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- console.log('Upload to ali oss done');
|
|
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
const result = (await axiosInstance.post('/update-post', {
|
|
const result = (await axiosInstance.post('/update-post', {
|
|
|
- type: 2,
|
|
|
|
|
- ossConfig: {
|
|
|
|
|
- ossPath: fileName,
|
|
|
|
|
- ossPublic: returnUrl,
|
|
|
|
|
|
|
+ config: {
|
|
|
|
|
+ type: 2,
|
|
|
|
|
+ ossConfig,
|
|
|
|
|
+ multuploadedKey,
|
|
|
|
|
+ uploadAppConfig: {
|
|
|
|
|
+ updateAsNext: updateNext,
|
|
|
|
|
+ },
|
|
|
|
|
+ updateCustomConfig: await config.getCustomConfig(param, true, versionName),
|
|
|
|
|
+ versionId,
|
|
|
|
|
+ updateInfo,
|
|
|
|
|
+ versionCode: versionCode,
|
|
|
|
|
+ fileName
|
|
|
},
|
|
},
|
|
|
- uploadAppConfig: {
|
|
|
|
|
- updateAsNext: updateNext,
|
|
|
|
|
- },
|
|
|
|
|
- versionId,
|
|
|
|
|
- updateInfo,
|
|
|
|
|
- versionCode: versionCode
|
|
|
|
|
})).data;
|
|
})).data;
|
|
|
console.log('上传成功');
|
|
console.log('上传成功');
|
|
|
console.log('新更新ID: ' + result.updateId);
|
|
console.log('新更新ID: ' + result.updateId);
|
|
@@ -269,7 +339,7 @@ export async function postWebUpdate(axiosInstance, param) {
|
|
|
const noDelete = param.ndelete;
|
|
const noDelete = param.ndelete;
|
|
|
|
|
|
|
|
const postConfig = await getConfig();
|
|
const postConfig = await getConfig();
|
|
|
- const versionId = await selectVersion(false, postConfig.lastVersion);
|
|
|
|
|
|
|
+ const { versionId, versionName } = await selectVersion(postConfig.lastVersion);
|
|
|
const updateInfo = await getUpdateInfo(postConfig);
|
|
const updateInfo = await getUpdateInfo(postConfig);
|
|
|
|
|
|
|
|
postConfig.lastVersion = versionId;
|
|
postConfig.lastVersion = versionId;
|
|
@@ -288,16 +358,7 @@ export async function postWebUpdate(axiosInstance, param) {
|
|
|
|
|
|
|
|
if (!skipBuild && config.buildWebCommand) {
|
|
if (!skipBuild && config.buildWebCommand) {
|
|
|
console.log('正在执行构建...');
|
|
console.log('正在执行构建...');
|
|
|
-
|
|
|
|
|
- await new Promise((resolve, reject) => {
|
|
|
|
|
- exec(config.buildWebCommand, function(err, stdout) {
|
|
|
|
|
- if (err)
|
|
|
|
|
- reject(err);
|
|
|
|
|
- else
|
|
|
|
|
- resolve();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
|
|
+ await execAsync(config.buildWebCommand);
|
|
|
console.log('构建完成');
|
|
console.log('构建完成');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -313,52 +374,9 @@ export async function postWebUpdate(axiosInstance, param) {
|
|
|
const outputPath = __dirname + '/upload.zip';
|
|
const outputPath = __dirname + '/upload.zip';
|
|
|
const skipFiles = config?.buildWebOptions?.skipFiles ?? [];
|
|
const skipFiles = config?.buildWebOptions?.skipFiles ?? [];
|
|
|
|
|
|
|
|
- function checkPathSkip(path) {
|
|
|
|
|
- if (!skipFiles || skipFiles.length === 0)
|
|
|
|
|
- return;
|
|
|
|
|
- return skipFiles.find((item) => path.startsWith(item));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
if (!skipBuild) {
|
|
if (!skipBuild) {
|
|
|
console.log('开始压缩zip...');
|
|
console.log('开始压缩zip...');
|
|
|
-
|
|
|
|
|
- const output = fs.createWriteStream(outputPath);
|
|
|
|
|
- const archive = archiver('zip', {
|
|
|
|
|
- zlib: { level: 9 } // Sets the compression level.
|
|
|
|
|
- });
|
|
|
|
|
- archive.pipe(output);
|
|
|
|
|
-
|
|
|
|
|
- async function loopDir(path, subPrefix) {
|
|
|
|
|
- const files = await readdir(path);
|
|
|
|
|
- for (const file of files) {
|
|
|
|
|
- const subPath = subPrefix + '/' + file;
|
|
|
|
|
- if (checkPathSkip(subPath))
|
|
|
|
|
- continue;
|
|
|
|
|
- const filestat = await stat(distDir + subPath);
|
|
|
|
|
- if (filestat.isDirectory()) {
|
|
|
|
|
- await loopDir(distDir + subPath, subPath);
|
|
|
|
|
- } else {
|
|
|
|
|
- archive.file(distDir + subPath, { name: subPath });
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- await loopDir(distDir, '')
|
|
|
|
|
-
|
|
|
|
|
- console.log('等待压缩zip...');
|
|
|
|
|
-
|
|
|
|
|
- const waitArchive = new Promise((resolve, reject) => {
|
|
|
|
|
- output.on('close', function() {
|
|
|
|
|
- console.log(archive.pointer() + ' total bytes');
|
|
|
|
|
- console.log('archiver has been finalized and the output file descriptor has closed.');
|
|
|
|
|
- resolve();
|
|
|
|
|
- });
|
|
|
|
|
- archive.on('error', function(err) {
|
|
|
|
|
- reject(err);
|
|
|
|
|
- });
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- await archive.finalize();
|
|
|
|
|
- await waitArchive;
|
|
|
|
|
|
|
+ await compressZip(distDir, outputPath, skipFiles);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
console.log('开始上传zip');
|
|
console.log('开始上传zip');
|
|
@@ -374,41 +392,14 @@ export async function postWebUpdate(axiosInstance, param) {
|
|
|
updateInfo,
|
|
updateInfo,
|
|
|
versionCode,
|
|
versionCode,
|
|
|
uploadWebConfig: config.uploadWebConfig,
|
|
uploadWebConfig: config.uploadWebConfig,
|
|
|
|
|
+ updateCustomConfig: await config.getCustomConfig(param, true, versionName),
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (fileInfo.size < 8 * 1024 * 1024) {
|
|
if (fileInfo.size < 8 * 1024 * 1024) {
|
|
|
const uploadZipContent = await readFile(outputPath);
|
|
const uploadZipContent = await readFile(outputPath);
|
|
|
formData.append("file", new Blob([ uploadZipContent ], { type : 'application/zip' }), 'upload.zip');
|
|
formData.append("file", new Blob([ uploadZipContent ], { type : 'application/zip' }), 'upload.zip');
|
|
|
} else {
|
|
} else {
|
|
|
- const multuploadInfo = (await axiosInstance.post('/update-large-token', {
|
|
|
|
|
- fileSize: fileInfo.size,
|
|
|
|
|
- fileName: path.basename(outputPath)
|
|
|
|
|
- })).data;
|
|
|
|
|
- const chunkSize = multuploadInfo.splitPartSize;
|
|
|
|
|
-
|
|
|
|
|
- const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
|
|
|
|
- bar1.start(100, 0);
|
|
|
|
|
-
|
|
|
|
|
- for (let i = 0; i < multuploadInfo.allChunks; i++) {
|
|
|
|
|
- const start = i * chunkSize;
|
|
|
|
|
- const len = Math.min(start + chunkSize, fileInfo.size) - start;
|
|
|
|
|
- const uploadZipContent = await readFileRange(outputPath, start, len);
|
|
|
|
|
- const subFormData = new FormData();
|
|
|
|
|
- subFormData.append("file", new Blob([ uploadZipContent ], { type : 'application/zip' }), 'upload.zip');
|
|
|
|
|
- subFormData.append("key", multuploadInfo.key);
|
|
|
|
|
- subFormData.append("info", JSON.stringify({}));
|
|
|
|
|
-
|
|
|
|
|
- (await axiosInstance.post('/update-large', subFormData, {
|
|
|
|
|
- headers: { 'Content-Type': 'multipart/form-data' }
|
|
|
|
|
- })).data;
|
|
|
|
|
-
|
|
|
|
|
- bar1.update(Math.floor(i / multuploadInfo.allChunks * 100));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- bar1.update(100);
|
|
|
|
|
- bar1.stop();
|
|
|
|
|
-
|
|
|
|
|
- submitConfig.multuploadedKey = multuploadInfo.key;
|
|
|
|
|
|
|
+ submitConfig.multuploadedKey = await uploadMulitPartLarge(axiosInstance, fileInfo, outputPath);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
try {
|