Skip to content

Commit acd821a

Browse files
committed
Merge branch 'main' into deploy
2 parents 99a5ba2 + 263667b commit acd821a

35 files changed

+4242
-343
lines changed

avrdude/[email protected]

-251 KB
Binary file not shown.

avrdude/postinstall.js

Lines changed: 255 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
const fs = require('fs');
22
const { spawn } = require('child_process');
33
const path = require('path');
4+
const https = require('https');
5+
6+
// test
47

58
// 确保 __dirname 有值,如果没有则使用当前工作目录
69
const srcDir = __dirname || "";
710
// 确保目标目录有值,空字符串会导致解压到当前目录
811
const destDir = process.env.AILY_TOOLS_PATH || "";
912
const _7zaPath = process.env.AILY_7ZA_PATH || "";
13+
const zipDownloadBaseUrl = process.env.AILY_ZIP_URL + '/tools';
1014

11-
// 使用传统的回调式 API 并用 Promise 包装
12-
function readdir(dir) {
13-
return new Promise((resolve, reject) => {
14-
fs.readdir(dir, (err, files) => {
15-
if (err) reject(err);
16-
else resolve(files);
17-
});
18-
});
19-
}
2015

2116
// 重试函数封装
2217
async function withRetry(fn, maxRetries = 3, retryDelay = 1000) {
@@ -39,6 +34,98 @@ async function withRetry(fn, maxRetries = 3, retryDelay = 1000) {
3934
throw new Error(`经过 ${maxRetries} 次尝试后操作仍然失败: ${lastError.message}`);
4035
}
4136

37+
38+
function getZipFileName() {
39+
// 读取package.json文件,获取name和version
40+
const prefix = "@aily-project/tool-";
41+
const packageJson = require('./package.json');
42+
const packageName = packageJson.name.replace(prefix, "");
43+
const packageVersion = packageJson.version;
44+
return `${packageName}@${packageVersion}.7z`;
45+
}
46+
47+
48+
function getZipFile() {
49+
const zipFileName = getZipFileName();
50+
const downloadUrl = `${zipDownloadBaseUrl}/${zipFileName}`;
51+
52+
return new Promise((resolve, reject) => {
53+
console.log(`正在下载: ${downloadUrl}`);
54+
const filePath = path.join(__dirname, zipFileName);
55+
56+
if (fs.existsSync(filePath)) {
57+
console.log(`文件已存在: ${zipFileName}`);
58+
resolve(zipFileName);
59+
return;
60+
}
61+
62+
const fileStream = fs.createWriteStream(filePath);
63+
64+
https.get(downloadUrl, (response) => {
65+
if (response.statusCode !== 200) {
66+
fileStream.close();
67+
fs.unlink(filePath, () => { });
68+
reject(new Error(`下载失败: 状态码 ${response.statusCode}`));
69+
return;
70+
}
71+
72+
// 获取文件总大小
73+
const totalSize = parseInt(response.headers['content-length'] || 0, 10);
74+
let downloadedSize = 0;
75+
let lastPercentage = -1;
76+
77+
// 设置下载进度显示
78+
response.on('data', (chunk) => {
79+
downloadedSize += chunk.length;
80+
81+
// 计算下载百分比
82+
if (totalSize > 0) {
83+
const percentage = Math.floor((downloadedSize / totalSize) * 100);
84+
85+
// 每增加1%才更新进度,避免过多输出
86+
if (percentage > lastPercentage) {
87+
lastPercentage = percentage;
88+
const downloadSizeMB = (downloadedSize / (1024 * 1024)).toFixed(2);
89+
const totalSizeMB = (totalSize / (1024 * 1024)).toFixed(2);
90+
process.stdout.write(`\r下载进度: ${percentage}% (${downloadSizeMB}MB / ${totalSizeMB}MB)`);
91+
}
92+
}
93+
});
94+
95+
response.pipe(fileStream);
96+
97+
fileStream.on('finish', () => {
98+
fileStream.close();
99+
// 输出换行,确保后续日志正常显示
100+
if (totalSize > 0) {
101+
console.log('');
102+
}
103+
console.log(`成功下载 ${zipFileName}`);
104+
resolve(zipFileName);
105+
});
106+
107+
fileStream.on('error', (err) => {
108+
fs.unlink(filePath, () => { });
109+
reject(err);
110+
});
111+
}).on('error', (err) => {
112+
fs.unlink(filePath, () => { });
113+
reject(err);
114+
});
115+
});
116+
}
117+
118+
119+
// 使用传统的回调式 API 并用 Promise 包装
120+
function readdir(dir) {
121+
return new Promise((resolve, reject) => {
122+
fs.readdir(dir, (err, files) => {
123+
if (err) reject(err);
124+
else resolve(files);
125+
});
126+
});
127+
}
128+
42129
// 使用 Promise 和 async/await 简化异步操作
43130
async function extractArchives() {
44131
try {
@@ -65,44 +152,175 @@ async function extractArchives() {
65152
fs.mkdirSync(destDir, { recursive: true });
66153
}
67154

68-
// 读取目录并过滤出 .7z 文件
69-
const files = await readdir(srcDir);
70-
const archiveFiles = files.filter(file => path.extname(file).toLowerCase() === '.7z');
155+
// 确保 ZIP URL 已设置
156+
if (!process.env.AILY_ZIP_URL) {
157+
throw new Error('未设置下载基础 URL (AILY_ZIP_URL 环境变量未设置)');
158+
}
159+
160+
if (!fs.existsSync(destDir)) {
161+
console.log(`目标目录不存在,创建: ${destDir}`);
162+
try {
163+
fs.mkdirSync(destDir, { recursive: true });
164+
} catch (mkdirErr) {
165+
throw new Error(`无法创建目标目录: ${destDir}, 错误: ${mkdirErr.message}`);
166+
}
167+
}
71168

72-
console.log(`找到 ${archiveFiles.length} 个 .7z 文件`);
169+
// 下载zip文件
170+
let fileName;
171+
try {
172+
fileName = await withRetry(getZipFile, 3, 2000);
173+
console.log(`已下载文件: ${fileName}`);
174+
} catch (downloadErr) {
175+
throw new Error(`无法下载zip文件: ${downloadErr.message}`);
176+
}
73177

74-
// 处理每个压缩文件
75-
for (const file of archiveFiles) {
76-
if (!file) {
77-
console.error('文件名为空,跳过');
78-
continue;
178+
// 检查下载的文件是否存在和大小是否正常
179+
const zipFilePath = path.join(__dirname, fileName);
180+
try {
181+
const stats = fs.statSync(zipFilePath);
182+
// if (stats.size < 1048576) { // 1MB = 1024 * 1024 bytes
183+
// throw new Error(`下载的文件异常小 (${stats.size} 字节),可能下载不完整或被截断`);
184+
// }
185+
console.log(`文件大小: ${(stats.size / (1024 * 1024)).toFixed(2)}MB`);
186+
} catch (statErr) {
187+
if (statErr.code === 'ENOENT') {
188+
throw new Error(`下载的文件不存在: ${zipFilePath}`);
189+
} else {
190+
throw new Error(`检查文件失败: ${statErr.message}`);
79191
}
192+
}
80193

81-
const srcPath = path.join(srcDir, file);
82-
console.log(`准备解压: ${srcPath}`);
194+
// 在解压前检查并清理目标目录中的同名文件夹
195+
try {
196+
await checkAndCleanExistingFolder(fileName, destDir);
197+
} catch (cleanErr) {
198+
throw new Error(`清理旧文件夹失败: ${cleanErr.message}`);
199+
}
200+
201+
// 解压zip文件
202+
try {
203+
await withRetry(async () => {
204+
await unpack(zipFilePath, destDir);
205+
}, 3, 2000); // 最多重试3次,每次间隔2秒
206+
console.log(`已解压 ${fileName}${destDir}`);
83207

208+
// 解压成功后重命名文件夹(将@替换为_)
84209
try {
85-
await withRetry(async () => {
86-
await unpack(srcPath, destDir);
87-
}, 3, 2000); // 最多重试3次,每次间隔2秒
88-
console.log(`已解压 ${file}${destDir}`);
89-
90-
// // 重命名
91-
// const newName = path.basename(file, '.7z');
92-
// const destPath = path.join(destDir, newName);
93-
94-
// // 将newName中的@替换为_
95-
// const newName2 = newName.replace('@', '_');
96-
// const newPath = path.join(destDir, newName2);
97-
// fs.renameSync(destPath, newPath);
98-
// console.log(`已重命名 ${destPath} 为 ${newPath}`);
99-
100-
} catch (error) {
101-
console.error(`解压 ${file} 失败:`, error);
210+
await renameExtractedFolder(fileName, destDir);
211+
} catch (renameErr) {
212+
throw new Error(`重命名文件夹失败: ${renameErr.message}`);
102213
}
214+
215+
// 解压成功后可以删除压缩文件
216+
// fs.unlinkSync(zipFilePath);
217+
// console.log(`已删除临时文件: ${fileName}`);
218+
} catch (unpackErr) {
219+
throw new Error(`解压失败: ${unpackErr.message}`);
103220
}
104221
} catch (err) {
105222
console.error('无法读取目录:', err);
223+
process.exit(1);
224+
}
225+
}
226+
227+
// 检查并清理目标目录中的同名文件夹
228+
async function checkAndCleanExistingFolder(zipFileName, targetDir) {
229+
// 从压缩文件名推断解压后的文件夹名
230+
// 例如:[email protected] -> avr_1.0.0 (将@替换为_)
231+
// const folderName = zipFileName.replace(/\.(7z|zip)$/i, '').replace('@', '_');
232+
const folderName = zipFileName.replace(/\.(7z|zip)$/i, '');
233+
const targetFolderPath = path.join(targetDir, folderName);
234+
235+
if (fs.existsSync(targetFolderPath)) {
236+
console.log(`检测到已存在的文件夹: ${targetFolderPath}`);
237+
console.log(`正在删除旧文件夹...`);
238+
239+
try {
240+
// 递归删除整个文件夹
241+
await withRetry(async () => {
242+
if (typeof fs.rmSync === 'function') {
243+
fs.rmSync(targetFolderPath, { recursive: true, force: true });
244+
} else {
245+
// 使用备用方法删除文件夹(适用于旧版本 Node.js)
246+
await rimraf(targetFolderPath);
247+
}
248+
}, 3, 1000);
249+
console.log(`已成功删除旧文件夹: ${folderName}`);
250+
} catch (rmErr) {
251+
throw new Error(`删除文件夹失败: ${rmErr.message}`);
252+
}
253+
}
254+
}
255+
256+
// 递归删除目录的备用函数(适用于旧版本 Node.js)
257+
async function rimraf(dir) {
258+
return new Promise((resolve, reject) => {
259+
if (!fs.existsSync(dir)) {
260+
resolve();
261+
return;
262+
}
263+
264+
try {
265+
const stats = fs.statSync(dir);
266+
if (stats.isDirectory()) {
267+
const files = fs.readdirSync(dir);
268+
const promises = files.map(file => {
269+
const filePath = path.join(dir, file);
270+
return rimraf(filePath);
271+
});
272+
273+
Promise.all(promises)
274+
.then(() => {
275+
fs.rmdir(dir, resolve);
276+
})
277+
.catch(reject);
278+
} else {
279+
fs.unlink(dir, resolve);
280+
}
281+
} catch (err) {
282+
reject(err);
283+
}
284+
});
285+
}
286+
287+
// 重命名解压后的文件夹(将@替换为_)
288+
async function renameExtractedFolder(zipFileName, targetDir) {
289+
// 从压缩文件名获取解压后的原始文件夹名
290+
291+
const originalFolderName = zipFileName.replace(/\.(7z|zip)$/i, '');
292+
const newFolderName = originalFolderName.replace('@', '_');
293+
294+
// 如果文件夹名没有变化,则不需要重命名
295+
if (originalFolderName === newFolderName) {
296+
console.log(`文件夹名无需重命名: ${originalFolderName}`);
297+
return;
298+
}
299+
300+
const originalFolderPath = path.join(targetDir, originalFolderName);
301+
const newFolderPath = path.join(targetDir, newFolderName);
302+
303+
if (fs.existsSync(originalFolderPath)) {
304+
try {
305+
// 使用重试机制进行重命名
306+
await withRetry(async () => {
307+
return new Promise((resolve, reject) => {
308+
fs.rename(originalFolderPath, newFolderPath, (err) => {
309+
if (err) {
310+
reject(new Error(`重命名文件夹失败: ${err.message}`));
311+
} else {
312+
resolve();
313+
}
314+
});
315+
});
316+
}, 3, 1000);
317+
318+
console.log(`已重命名文件夹: ${originalFolderName} -> ${newFolderName}`);
319+
} catch (renameErr) {
320+
throw new Error(`无法重命名文件夹 ${originalFolderName}${newFolderName}: ${renameErr.message}`);
321+
}
322+
} else {
323+
console.warn(`未找到需要重命名的文件夹: ${originalFolderPath}`);
106324
}
107325
}
108326

bossac/[email protected]

-875 KB
Binary file not shown.

0 commit comments

Comments
 (0)