初始化提交
This commit is contained in:
236
scripts/setup.js
Normal file
236
scripts/setup.js
Normal file
@@ -0,0 +1,236 @@
|
||||
const exec = require('child_process').exec;
|
||||
const https = require('https');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const isWin = require('os').platform().indexOf('win32') > -1;
|
||||
const isLinux = require('os').platform().indexOf('linux') > -1;
|
||||
const isDarwin = require('os').platform().indexOf('darwin') > -1;
|
||||
const ROOT_DIR = `${__dirname}/../`;
|
||||
const l = m => console.log(m);
|
||||
|
||||
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
const runCmd = (cmd, shouldOutput = true, cwd = null) => {
|
||||
const startTime = new Date();
|
||||
const option = cwd ? {cwd} : {};
|
||||
const currentCwd = cwd || process.cwd();
|
||||
l(`[${startTime.toISOString()}] 开始执行命令: ${cmd}`);
|
||||
l(`执行目录: ${currentCwd}`);
|
||||
|
||||
return new Promise(r => {
|
||||
const childProcess = exec(cmd, option);
|
||||
l(`进程ID: ${childProcess.pid}`);
|
||||
let result = '';
|
||||
let error = '';
|
||||
|
||||
childProcess.stdout.on('data', function(data) {
|
||||
shouldOutput && console.log(data);
|
||||
result += data.toString();
|
||||
});
|
||||
|
||||
childProcess.stderr.on('data', (data) => {
|
||||
shouldOutput && console.log(data);
|
||||
error += data.toString();
|
||||
})
|
||||
|
||||
childProcess.on('exit', (code, signal) => {
|
||||
const endTime = new Date();
|
||||
const duration = (endTime - startTime) / 1000;
|
||||
l(`[${endTime.toISOString()}] 命令执行完成,耗时: ${duration}秒`);
|
||||
if (signal) {
|
||||
l(`进程被信号 ${signal} 终止`);
|
||||
}
|
||||
l(`退出码: ${code}`);
|
||||
r({code, signal, result, error})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const runCmdAndExitWhenFailed = async (cmd, msg, shouldOutput = true, cwd = null) => {
|
||||
l('----------------------------------------');
|
||||
l(`执行命令: ${cmd}`);
|
||||
l(`工作目录: ${cwd || process.cwd()}`);
|
||||
const ret = await runCmd(cmd, shouldOutput, cwd);
|
||||
if (ret.code !== 0 || ret.code === null) {
|
||||
l('命令执行失败:');
|
||||
l(msg);
|
||||
l(`命令: ${cmd}`);
|
||||
l(`工作目录: ${cwd || process.cwd()}`);
|
||||
l('退出码: ' + ret.code);
|
||||
l('错误输出: ' + ret.error);
|
||||
l('标准输出: ' + ret.result);
|
||||
l('系统信息:');
|
||||
l(`- 平台: ${process.platform}`);
|
||||
l(`- 架构: ${process.arch}`);
|
||||
l(`- Node版本: ${process.version}`);
|
||||
l(`- 内存使用: ${JSON.stringify(process.memoryUsage())}`);
|
||||
process.exit(1);
|
||||
}
|
||||
l('----------------------------------------');
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getMediaGetBinPath() {
|
||||
return path.join(ROOT_DIR, 'backend', 'bin', `media-get${isWin ? '.exe' : ''}`);
|
||||
}
|
||||
|
||||
async function checkAndUpdateMediaGet(currentMediaGetVersion) {
|
||||
const MediaGetService = require('../backend/src/service/media_fetcher/media_get');
|
||||
|
||||
const latestVersion = await MediaGetService.getLatestMediaGetVersion();
|
||||
if (latestVersion === false) {
|
||||
return;
|
||||
}
|
||||
if (currentMediaGetVersion.localeCompare(latestVersion, undefined, { numeric: true, sensitivity: 'base' }) >= 0) {
|
||||
l('当前 media-get 版本已经是最新版本');
|
||||
return;
|
||||
}
|
||||
l(`当前 media-get(${currentMediaGetVersion})版本不是最新版本, 开始更新到${latestVersion}`);
|
||||
await MediaGetService.downloadTheLatestMediaGet(latestVersion);
|
||||
}
|
||||
|
||||
function copyDir(src, dest) {
|
||||
fs.mkdirSync(dest);
|
||||
fs.readdirSync(src).forEach(file => {
|
||||
const srcPath = path.join(src, file);
|
||||
const destPath = path.join(dest, file);
|
||||
if (fs.statSync(srcPath).isDirectory()) {
|
||||
copyDir(srcPath, destPath);
|
||||
} else {
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function getPackageManager() {
|
||||
let ret = await runCmd('pnpm --version', false);
|
||||
if (ret.code === 0) {
|
||||
return 'pnpm';
|
||||
}
|
||||
ret = await runCmd('yarn --version', false);
|
||||
if (ret.code === 0) {
|
||||
return 'yarn';
|
||||
}
|
||||
|
||||
return 'npm';
|
||||
}
|
||||
|
||||
async function downloadMediaGetWithRetry(latestVersion) {
|
||||
const MediaGetService = require('../backend/src/service/media_fetcher/media_get');
|
||||
const maxRetries = 3;
|
||||
let retryCount = 0;
|
||||
|
||||
while (retryCount < maxRetries) {
|
||||
l(`尝试下载 media-get (第 ${retryCount + 1} 次尝试)`);
|
||||
const success = await MediaGetService.downloadTheLatestMediaGet(latestVersion);
|
||||
if (success) {
|
||||
return true;
|
||||
}
|
||||
retryCount++;
|
||||
if (retryCount < maxRetries) {
|
||||
l(`下载失败,等待 5 秒后重试...`);
|
||||
await sleep(5000);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
l('开始执行...');
|
||||
|
||||
// 检查 FFmpeg 安装和位置
|
||||
l('检查 FFmpeg 安装状态...');
|
||||
if (!process.env.CROSS_COMPILING) {
|
||||
const ffmpegRet = await runCmd('which ffmpeg && ls -l $(which ffmpeg)', true);
|
||||
l('FFmpeg location and permissions:');
|
||||
l(ffmpegRet.result);
|
||||
await runCmdAndExitWhenFailed('ffmpeg -version', '请先安装 ffmpeg', false);
|
||||
} else {
|
||||
l('跳过 FFmpeg 检查 (CROSS_COMPILING=1)');
|
||||
}
|
||||
|
||||
await runCmdAndExitWhenFailed('npm version', '请先安装 npm', false);
|
||||
|
||||
const pm = await getPackageManager();
|
||||
l(`安装 node_module via ${pm}`)
|
||||
l('开始安装后端依赖...');
|
||||
l(`执行命令: ${pm} install --production --verbose in ${path.join(ROOT_DIR, 'backend')}`);
|
||||
const backendInstallResult = await runCmdAndExitWhenFailed(`${pm} install --production --verbose`, '安装后端 node_module 失败', true, path.join(ROOT_DIR, 'backend'));
|
||||
l('后端依赖安装结果:');
|
||||
l('Exit code: ' + backendInstallResult.code);
|
||||
l('Output: ' + backendInstallResult.result);
|
||||
if (backendInstallResult.error) {
|
||||
l('Error output: ' + backendInstallResult.error);
|
||||
}
|
||||
|
||||
l('检查 media-get');
|
||||
const MediaGetService = require('../backend/src/service/media_fetcher/media_get');
|
||||
|
||||
const mediaGetPath = getMediaGetBinPath();
|
||||
l(`检查 media-get 权限: ${mediaGetPath}`);
|
||||
await runCmd(`ls -l ${mediaGetPath}`, true);
|
||||
|
||||
if (!fs.existsSync(mediaGetPath)) {
|
||||
const latestVersion = await MediaGetService.getLatestMediaGetVersion();
|
||||
if (latestVersion === false) {
|
||||
l('获取 media-get 最新版本失败,无法继续安装');
|
||||
return false;
|
||||
}
|
||||
l('开始下载核心程序 media-get');
|
||||
if (await downloadMediaGetWithRetry(latestVersion) === false) {
|
||||
l('下载核心程序 media-get 失败');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const currentMediaGetVersion = await MediaGetService.getLatestMediaGetVersion();
|
||||
await checkAndUpdateMediaGet(currentMediaGetVersion);
|
||||
}
|
||||
|
||||
l('开始安装前端依赖...');
|
||||
const frontendInstallResult = await runCmdAndExitWhenFailed(`${pm} install --verbose`, '安装前端 node_module 失败', true, path.join(ROOT_DIR, 'frontend'));
|
||||
l('前端依赖安装结果:');
|
||||
l('Exit code: ' + frontendInstallResult.code);
|
||||
l('Output: ' + frontendInstallResult.result);
|
||||
if (frontendInstallResult.error) {
|
||||
l('Error output: ' + frontendInstallResult.error);
|
||||
}
|
||||
|
||||
l('开始编译前端...');
|
||||
const buildResult = await runCmdAndExitWhenFailed(`${pm} run build`, '前端编译失败', true, path.join(ROOT_DIR, 'frontend'));
|
||||
l('前端编译结果:');
|
||||
l('Exit code: ' + buildResult.code);
|
||||
l('Output: ' + buildResult.result);
|
||||
if (buildResult.error) {
|
||||
l('Error output: ' + buildResult.error);
|
||||
}
|
||||
|
||||
l('删除老目录');
|
||||
try {
|
||||
fs.rmdirSync(path.join(ROOT_DIR, 'backend', 'public'), { recursive: true });
|
||||
} catch(e) {
|
||||
l('删除老目录失败,但继续执行: ' + e.message);
|
||||
}
|
||||
|
||||
l('拷贝前端目录');
|
||||
try {
|
||||
copyDir(path.join(ROOT_DIR, 'frontend', 'dist'), path.join(ROOT_DIR, 'backend', 'public'));
|
||||
} catch(e) {
|
||||
l('拷贝前端目录失败: ' + e.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
l('执行过程中出现错误:');
|
||||
l(error.stack || error.message || error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
run().then(isFine => {
|
||||
l(isFine ? `执行完毕,执行以下命令启动服务:\r\n\r\nnpm run app` : '执行出错,请检查');
|
||||
if (!isFine) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user