ql-publish 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ql-publish",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "scripts": {},
5
5
  "dependencies": {
6
6
  "@alicloud/cdn20180510": "^7.0.1",
package/upload/clear.js CHANGED
@@ -95,7 +95,7 @@ const deleteFileByMapJson = async (sftp, currentSourceDir, mtime) => {
95
95
  } else {
96
96
  // 删除文件
97
97
  if (mtime >= item.attrs.mtime) {
98
- // console.log(`删除文件: ${sourcePath}`,);
98
+ // logger.info(`✅ 已删除文件: ${sourcePath}`);
99
99
  await sftp.unlink(sourcePath);
100
100
  }
101
101
  }
@@ -168,7 +168,7 @@ const getDirList = async () => {
168
168
  }
169
169
 
170
170
  folderNames = [...folderNames, ...result.objects.filter(obj => obj && obj.name)
171
- .map(obj => obj.name.split('/')[1])];
171
+ .map(obj => obj.name.split('/')[1])];
172
172
 
173
173
  nextMarker = result.nextMarker;
174
174
  } while (nextMarker);
package/upload/u.js CHANGED
@@ -7,6 +7,8 @@ const { PassThrough } = require('stream');
7
7
  const dayjs = require("dayjs");
8
8
  const refreshCdn = require("../cdn/refresh");
9
9
  const readline = require("readline");
10
+ const { exec } = require('child_process');
11
+ const fs = require('fs');
10
12
 
11
13
  const deleteFolder = () => {
12
14
  return new Promise(resolve => {
@@ -53,7 +55,7 @@ const deleteFolder = () => {
53
55
  logger.error('❌ 连接错误:', err);
54
56
  resolve(null);
55
57
  });
56
- conn.on('end', () => {});
58
+ conn.on('end', () => { });
57
59
  })
58
60
  }
59
61
 
@@ -323,7 +325,7 @@ const creatFileMap = async (sftp, currentSourceDir) => {
323
325
  await creatFileMap(sftp, sourcePath);
324
326
  } else {
325
327
  fileMapData.mtime = item.attrs.mtime > fileMapData.mtime ? item.attrs.mtime : fileMapData.mtime;
326
-
328
+
327
329
  // if (sourcePath.indexOf(`assets`) > -1) {
328
330
  // if (sourcePath.indexOf(`assets/_plugin`) === -1) {
329
331
  // fileMapData.deleteList.push(sourcePath)
@@ -427,8 +429,11 @@ const sshAction = async () => {
427
429
  }
428
430
  });
429
431
  });
430
- // 没有项目目录,直接返回
432
+ // 没有项目目录,创建项目目录后,return
431
433
  if (!await isHasDir(sftp, config.path)) {
434
+ logger.warn(`项目目录 ${config.path} 不存在,正在创建...`);
435
+ await ensureDirectoryExists(sftp, config.path);
436
+ logger.info(`✅ 项目目录 ${config.path} 创建成功`);
432
437
  return
433
438
  }
434
439
  if (config.backUp) {
@@ -456,46 +461,123 @@ const sshAction = async () => {
456
461
  }
457
462
  }
458
463
 
459
- const scpAction = async () => {
460
- // 清空目标目录文件
461
- // if (!await deleteFolder()) {
462
- // process.exit(1);
463
- // }
464
-
465
- logger.warn('开始上传文件到服务器...');
466
-
467
- let timer = null;
468
-
469
- const runTimer = () => {
470
- timer && clearTimeout(timer);
471
- timer = setTimeout(() => {
472
- if (!timer) return;
473
- logger.log('✅ 拼命上传中...');
474
- runTimer();
475
- }, Math.random() * 5000 + 1000);
476
- }
477
-
478
- runTimer();
479
- // 上传文件
480
- scpClient.scp(
481
- config.localPath,
482
- config,
483
- async (err) => {
484
- clearTimeout(timer);
485
- timer = null;
464
+ const compressAction = (localPath, archiveName) => {
465
+ return new Promise((resolve, reject) => {
466
+ logger.warn(`正在压缩文件: ${localPath} -> ${archiveName}`);
467
+ // 使用 tar 压缩,-C 切换到目录,. 表示压缩当前目录下所有文件
468
+ // COPYFILE_DISABLE=1 和 --no-xattrs 用于防止 macOS 的扩展属性(如 com.apple.provenance)被打包
469
+ exec(`COPYFILE_DISABLE=1 tar --no-xattrs -czf ${archiveName} -C ${localPath} .`, (err) => {
486
470
  if (err) {
487
- logger.error(`❌ ${process.env.NODE_ENV}环境:上传失败:`);
488
- logger.error(err);
489
- process.exit(1);
471
+ logger.error('❌ 压缩失败:', err);
472
+ reject(err);
490
473
  } else {
491
- logger.success(`🎉 ${process.env.NODE_ENV}环境:所有文件上传成功!`);
492
- // 刷新cdn
493
- config.cdn && config.cdn.list && await refreshCdn(config.cdn.list);
494
- logger.warn(`接下来1分钟后,记得清理旧项目版本,请手动执行 yarn clear:${process.env.NODE_ENV}`)
495
- process.exit(0);
474
+ logger.info('✅ 压缩成功');
475
+ resolve();
496
476
  }
477
+ });
478
+ });
479
+ };
480
+
481
+ const decompressRemoteAction = (config, remoteArchivePath, remoteExtractPath) => {
482
+ return new Promise((resolve, reject) => {
483
+ const conn = new Client();
484
+ conn.on('ready', () => {
485
+ logger.warn(`正在服务器解压文件: ${remoteArchivePath} -> ${remoteExtractPath}`);
486
+ // 确保目录存在(使用 -p 参数,如果已存在不会报错)
487
+ // 如果 mkdir -p 仍然报错(可能是权限问题或其他特殊情况),我们尝试直接解压
488
+ const command = `mkdir -p ${remoteExtractPath} 2>/dev/null; tar -xzf ${remoteArchivePath} -C ${remoteExtractPath} && rm ${remoteArchivePath}`;
489
+ conn.exec(command, (err, stream) => {
490
+ if (err) {
491
+ conn.end();
492
+ return reject(err);
493
+ }
494
+ stream.on('close', (code) => {
495
+ conn.end();
496
+ if (code === 0) {
497
+ logger.info('✅ 服务器解压成功');
498
+ resolve();
499
+ } else {
500
+ logger.error(`❌ 服务器解压失败,退出码: ${code}`);
501
+ reject(new Error(`Exit code ${code}`));
502
+ }
503
+ }).on('data', (data) => {
504
+ // console.log('STDOUT: ' + data);
505
+ }).stderr.on('data', (data) => {
506
+ logger.error('STDERR: ' + data);
507
+ });
508
+ });
509
+ }).on('error', (err) => {
510
+ logger.error('❌ 服务器连接失败:', err);
511
+ reject(err);
512
+ }).connect(config);
513
+ });
514
+ };
515
+
516
+ const scpAction = async () => {
517
+ const archiveName = 'dist.tar.gz';
518
+ const localArchivePath = path.join(process.cwd(), archiveName);
519
+ const remoteArchivePath = path.posix.join(config.path, archiveName);
520
+
521
+ try {
522
+ // 1. 本地压缩
523
+ await compressAction(config.localPath, localArchivePath);
524
+ logger.warn('开始上传压缩包到服务器...');
525
+ let timer = null;
526
+ const runTimer = () => {
527
+ timer && clearTimeout(timer);
528
+ timer = setTimeout(() => {
529
+ if (!timer) return;
530
+ logger.log('✅ 拼命上传中...');
531
+ runTimer();
532
+ }, Math.random() * 5000 + 1000);
533
+ }
534
+ runTimer();
535
+
536
+ // 2. 上传压缩包
537
+ await new Promise((resolve, reject) => {
538
+ scpClient.scp(
539
+ localArchivePath,
540
+ {
541
+ ...config,
542
+ path: config.path // 保持目标路径一致
543
+ },
544
+ (err) => {
545
+ clearTimeout(timer);
546
+ timer = null;
547
+ if (err) {
548
+ reject(err);
549
+ } else {
550
+ resolve();
551
+ }
552
+ }
553
+ );
554
+ });
555
+
556
+ logger.success('🎉 压缩包上传成功!');
557
+
558
+ // 3. 服务器解压
559
+ await decompressRemoteAction(config, remoteArchivePath, config.path);
560
+
561
+ // 4. 清理本地压缩包
562
+ if (fs.existsSync(localArchivePath)) {
563
+ fs.unlinkSync(localArchivePath);
497
564
  }
498
- );
565
+
566
+ logger.success(`🎉 ${process.env.NODE_ENV}环境:部署成功!`);
567
+
568
+ // 刷新cdn
569
+ config.cdn && config.cdn.list && await refreshCdn(config.cdn.list);
570
+ logger.warn(`接下来1分钟后,记得清理旧项目版本,请手动执行 yarn clear:${process.env.NODE_ENV}`)
571
+ process.exit(0);
572
+
573
+ } catch (err) {
574
+ if (fs.existsSync(localArchivePath)) {
575
+ fs.unlinkSync(localArchivePath);
576
+ }
577
+ logger.error(`❌ ${process.env.NODE_ENV}环境:操作失败:`);
578
+ logger.error(err);
579
+ process.exit(1);
580
+ }
499
581
  }
500
582
 
501
583
  const authProjectName = () => {