Browse Source

添加打包部署脚本-deploy-h5.js

dengdx 10 hours ago
parent
commit
0fc47b8875
1 changed files with 381 additions and 0 deletions
  1. 381 0
      .build/deploy-h5.js

+ 381 - 0
.build/deploy-h5.js

@@ -0,0 +1,381 @@
+#!/usr/bin/env node
+
+const { execSync, spawn } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+const readline = require('readline');
+
+// 创建命令行交互接口
+const rl = readline.createInterface({
+  input: process.stdin,
+  output: process.stdout
+});
+
+// 配置信息
+const CONFIG = {
+  buildCommand: 'npm run build:h5',
+  localDistPath: 'dist/h5',
+  remoteHost: '192.168.110.13',
+  remoteUser: 'ccos',  // 默认用户名
+  remotePassword: 'ccos',  // 默认密码
+  remoteTargetPath: '/home/ccos/dros/linux-arm64-unpacked/h5',
+  remotePackagePath: '/home/ccos/dros/linux-arm64-unpacked',
+  smbHost: '192.168.110.197',
+  smbShare: 'Shared_Folder',
+  smbUser: 'zskk',
+  smbPassword: 'zskk',
+  smbTargetDir: 'dros_human'
+};
+
+// 日志输出函数
+function log(message, type = 'info') {
+  const timestamp = new Date().toLocaleString('zh-CN');
+  const prefix = {
+    info: '📝',
+    success: '✅',
+    error: '❌',
+    warning: '⚠️'
+  }[type] || '📝';
+  console.log(`${prefix} [${timestamp}] ${message}`);
+}
+
+// 执行命令并输出日志
+function executeCommand(command, description, options = {}) {
+  log(`开始: ${description}`, 'info');
+  try {
+    const result = execSync(command, {
+      stdio: 'inherit',
+      encoding: 'utf-8',
+      ...options
+    });
+    log(`完成: ${description}`, 'success');
+    return result;
+  } catch (error) {
+    log(`失败: ${description}`, 'error');
+    log(`错误信息: ${error.message}`, 'error');
+    throw error;
+  }
+}
+
+// 使用 Node.js SSH2 执行远程命令
+async function executeSSHCommand(host, user, password, command, description, timeout = 600000) {
+  log(`开始: ${description}`, 'info');
+  
+  return new Promise((resolve, reject) => {
+    const { NodeSSH } = require('node-ssh');
+    const ssh = new NodeSSH();
+    
+    ssh.connect({
+      host: host,
+      username: user,
+      password: password,
+      tryKeyboard: true,
+      readyTimeout: 30000
+    })
+    .then(() => {
+      // 设置命令执行超时时间(默认 10 分钟)
+      return ssh.execCommand(command, {
+        execOptions: {
+          timeout: timeout
+        }
+      });
+    })
+    .then((result) => {
+      if (result.code === 0) {
+        log(`完成: ${description}`, 'success');
+        if (result.stdout) {
+          console.log(result.stdout);
+        }
+        ssh.dispose();
+        resolve(result);
+      } else {
+        log(`失败: ${description}`, 'error');
+        if (result.stderr) {
+          log(`错误信息: ${result.stderr}`, 'error');
+        }
+        ssh.dispose();
+        reject(new Error(result.stderr || '命令执行失败'));
+      }
+    })
+    .catch((error) => {
+      log(`失败: ${description}`, 'error');
+      log(`错误信息: ${error.message}`, 'error');
+      ssh.dispose();
+      reject(error);
+    });
+  });
+}
+
+// 使用 SCP 上传文件
+async function uploadViaSCP(host, user, password, localPath, remotePath, description) {
+  log(`开始: ${description}`, 'info');
+  
+  return new Promise((resolve, reject) => {
+    const { NodeSSH } = require('node-ssh');
+    const ssh = new NodeSSH();
+    
+    ssh.connect({
+      host: host,
+      username: user,
+      password: password,
+      tryKeyboard: true
+    })
+    .then(() => {
+      return ssh.putDirectory(localPath, remotePath, {
+        recursive: true,
+        concurrency: 10,
+        validate: (itemPath) => {
+          return true;
+        },
+        tick: (localPath, remotePath, error) => {
+          if (error) {
+            log(`上传失败: ${localPath}`, 'error');
+          }
+        }
+      });
+    })
+    .then((status) => {
+      if (status) {
+        log(`完成: ${description}`, 'success');
+        ssh.dispose();
+        resolve();
+      } else {
+        log(`失败: ${description}`, 'error');
+        ssh.dispose();
+        reject(new Error('文件上传失败'));
+      }
+    })
+    .catch((error) => {
+      log(`失败: ${description}`, 'error');
+      log(`错误信息: ${error.message}`, 'error');
+      ssh.dispose();
+      reject(error);
+    });
+  });
+}
+
+// 读取 package.json 中的版本号
+function getVersionFromPackageJson() {
+  try {
+    const packageJsonPath = path.join(__dirname, '..', 'package.json');
+    const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
+    return packageJson.version;
+  } catch (error) {
+    log('无法读取 package.json 文件', 'error');
+    throw new Error('无法获取版本号,请检查 package.json 文件');
+  }
+}
+
+// 倒计时确认远程服务器凭据
+function confirmRemoteCredentials() {
+  return new Promise((resolve) => {
+    let countdown = 10;
+    log(`将使用远程服务器凭据: 用户名=${CONFIG.remoteUser}, 密码=${CONFIG.remotePassword}`, 'info');
+    log(`${countdown} 秒后自动使用默认凭据,按回车键立即确认,输入 'n' 修改...`, 'warning');
+    
+    const timer = setInterval(() => {
+      countdown--;
+      if (countdown > 0) {
+        process.stdout.write(`\r⏱️  倒计时: ${countdown} 秒...`);
+      }
+    }, 1000);
+    
+    const timeout = setTimeout(() => {
+      clearInterval(timer);
+      process.stdout.write('\r✅ 使用默认凭据\n');
+      rl.removeAllListeners('line');
+      resolve({ user: CONFIG.remoteUser, password: CONFIG.remotePassword });
+    }, 10000);
+    
+    rl.once('line', (input) => {
+      clearTimeout(timeout);
+      clearInterval(timer);
+      process.stdout.write('\r');
+      
+      const trimmedInput = input.trim().toLowerCase();
+      if (trimmedInput === 'n' || trimmedInput === 'no') {
+        // 用户选择修改
+        rl.question('请输入远程服务器用户名: ', (user) => {
+          const trimmedUser = user.trim() || CONFIG.remoteUser;
+          rl.question('请输入远程服务器密码: ', (password) => {
+            const trimmedPassword = password.trim() || CONFIG.remotePassword;
+            resolve({ user: trimmedUser, password: trimmedPassword });
+          });
+        });
+      } else {
+        // 用户按回车或其他输入,使用默认值
+        log('使用默认凭据', 'success');
+        resolve({ user: CONFIG.remoteUser, password: CONFIG.remotePassword });
+      }
+    });
+  });
+}
+
+// 检查本地构建目录是否存在
+function checkLocalBuildPath() {
+  if (!fs.existsSync(CONFIG.localDistPath)) {
+    log(`本地构建目录不存在: ${CONFIG.localDistPath}`, 'warning');
+    return false;
+  }
+  return true;
+}
+
+// 检查 node-ssh 是否已安装
+function checkNodeSSH() {
+  try {
+    require.resolve('node-ssh');
+    return true;
+  } catch (e) {
+    return false;
+  }
+}
+
+// 构建 H5 文件
+function buildH5() {
+  log('开始构建 H5 文件...', 'info');
+  executeCommand(CONFIG.buildCommand, '构建 H5 项目');
+  
+  if (!checkLocalBuildPath()) {
+    throw new Error('构建完成但未找到输出目录');
+  }
+  
+  log(`构建文件位于: ${CONFIG.localDistPath}`, 'success');
+}
+
+// 复制文件到远程服务器
+async function copyToRemoteServer(remoteUser, remotePassword) {
+  log(`开始复制文件到远程服务器 ${CONFIG.remoteHost}...`, 'info');
+  
+  // 先清空远程目标目录
+  await executeSSHCommand(
+    CONFIG.remoteHost,
+    remoteUser,
+    remotePassword,
+    `rm -rf ${CONFIG.remoteTargetPath}/* && mkdir -p ${CONFIG.remoteTargetPath}`,
+    '清空远程目标目录'
+  );
+  
+  // 使用 SCP 复制文件
+  await uploadViaSCP(
+    CONFIG.remoteHost,
+    remoteUser,
+    remotePassword,
+    CONFIG.localDistPath,
+    CONFIG.remoteTargetPath,
+    '复制文件到远程服务器'
+  );
+}
+
+// 在远程服务器上打包
+async function packageOnRemoteServer(version, remoteUser, remotePassword) {
+  const packageName = `linux-arm64-app-human-first-${version}.tar.gz`;
+  log(`开始在远程服务器上打包: ${packageName}`, 'info');
+  
+  // 在 /home/ccos/dros/ 目录下打包 linux-arm64-unpacked 文件夹
+  const packageDir = '/home/ccos/dros';
+  const targetFolder = 'linux-arm64-unpacked';
+  const packagePath = `${packageDir}/${packageName}`;
+  
+  await executeSSHCommand(
+    CONFIG.remoteHost,
+    remoteUser,
+    remotePassword,
+    `cd ${packageDir} && tar -czvf ${packageName} ${targetFolder}`,
+    '远程打包'
+  );
+  
+  log(`打包完成: ${packageName}`, 'success');
+  log(`打包文件位置: ${packagePath}`, 'info');
+  return packageName;
+}
+
+// 传输打包文件到共享文件夹
+async function transferToSharedFolder(packageName, remoteUser, remotePassword) {
+  log(`开始传输打包文件到 ${CONFIG.smbHost}...`, 'info');
+  log('提示: 大文件传输可能需要较长时间,请耐心等待...', 'info');
+  
+  // 打包文件在 /home/ccos/dros/ 目录下
+  const remotePackageFile = `/home/ccos/dros/${packageName}`;
+  
+  // 直接在 192.168.110.13 上使用 smbclient 传输到 192.168.110.197
+  // 添加 --timeout 参数设置 smbclient 超时时间(单位:秒)
+  const smbCommand = `smbclient //${CONFIG.smbHost}/${CONFIG.smbShare} -U "${CONFIG.smbUser}%${CONFIG.smbPassword}" --timeout 600 -c "cd ${CONFIG.smbTargetDir}; put ${remotePackageFile} ${packageName}"`;
+  
+  // 设置 SSH 命令超时为 15 分钟(900000 毫秒)
+  await executeSSHCommand(
+    CONFIG.remoteHost,
+    remoteUser,
+    remotePassword,
+    smbCommand,
+    '从远程服务器直接上传到共享文件夹',
+    900000
+  );
+  
+  // 可选:清理远程服务器上的打包文件
+  try {
+    await executeSSHCommand(
+      CONFIG.remoteHost,
+      remoteUser,
+      remotePassword,
+      `rm -f ${remotePackageFile}`,
+      '清理远程服务器打包文件'
+    );
+  } catch (error) {
+    log('清理远程打包文件失败(可忽略)', 'warning');
+  }
+}
+
+// 主函数
+async function main() {
+  console.log('\n========================================');
+  console.log('🚀 H5 构建与部署脚本');
+  console.log('========================================\n');
+  
+  try {
+    // 检查 node-ssh 是否已安装
+    if (!checkNodeSSH()) {
+      log('检测到缺少 node-ssh 依赖,正在安装...', 'warning');
+      executeCommand('npm install node-ssh', '安装 node-ssh');
+    }
+    
+    // 1. 读取版本号
+    const version = getVersionFromPackageJson();
+    log(`从 package.json 读取版本号: ${version}`, 'success');
+    console.log('');
+    
+    // 2. 倒计时确认远程服务器凭据
+    const credentials = await confirmRemoteCredentials();
+    rl.close();
+    
+    log(`远程服务器用户: ${credentials.user}`, 'info');
+    console.log('\n========================================\n');
+    
+    // 4. 构建 H5 文件
+    buildH5();
+    console.log('\n========================================\n');
+    
+    // 5. 复制到远程服务器
+    await copyToRemoteServer(credentials.user, credentials.password);
+    console.log('\n========================================\n');
+    
+    // 6. 在远程服务器上打包
+    const packageName = await packageOnRemoteServer(version, credentials.user, credentials.password);
+    console.log('\n========================================\n');
+    
+    // 7. 传输到共享文件夹
+    await transferToSharedFolder(packageName, credentials.user, credentials.password);
+    console.log('\n========================================\n');
+    
+    log('🎉 所有步骤完成!', 'success');
+    log(`打包文件: ${packageName}`, 'success');
+    log(`已上传到: //${CONFIG.smbHost}/${CONFIG.smbShare}/${CONFIG.smbTargetDir}/${packageName}`, 'success');
+    
+  } catch (error) {
+    log('部署过程中发生错误', 'error');
+    log(error.message, 'error');
+    process.exit(1);
+  }
+}
+
+// 运行主函数
+main();