use crate::model::CommandExecutor; use anyhow::Result; use log::{info, warn}; use std::path::Path; use tokio::process::Command; //定义国内python加速地址: https://mirrors.aliyun.com/pypi/simple const PYTHON_ACCELERATION_ADDRESS: &str = "https://mirrors.aliyun.com/pypi/simple"; //使用 uv安装 python 3.13,比如: uv python install 3.13 async fn install_python_3_13() -> Result<()> { let mut cmd = Command::new("uv"); cmd.arg("python") .arg("install") .arg("3.13") .kill_on_drop(true); match CommandExecutor::with_timeout(cmd.status(), 600).await { Ok(Ok(status)) => { if !status.success() { warn!("安装Python 3.13失败"); return Err(anyhow::anyhow!("安装Python 3.13失败")); } info!("安装Python 3.13成功"); Ok(()) } Ok(Err(e)) => { warn!("命令执行失败: {e}"); Err(anyhow::anyhow!("命令执行失败: {}", e)) } Err(e) => { warn!("执行超时或系统错误: {e}"); Err(anyhow::anyhow!("执行超时或系统错误: {}", e)) } } } // 检查 uv 虚拟环境是否存在 async fn check_and_create_uv_venv() -> Result<()> { info!("检查 uv 虚拟环境..."); // 检查 .venv 目录是否存在 if Path::new(".venv").exists() { info!("uv 虚拟环境已存在"); return Ok(()); } info!("未检测到 uv 虚拟环境,开始创建..."); let mut cmd = Command::new("uv"); cmd.arg("venv").kill_on_drop(true); match CommandExecutor::with_timeout(cmd.status(), 600).await { Ok(Ok(status)) => { if !status.success() { warn!("创建 uv 虚拟环境失败"); return Err(anyhow::anyhow!("创建 uv 虚拟环境失败")); } info!("创建 uv 虚拟环境成功"); Ok(()) } Ok(Err(e)) => { warn!("命令执行失败: {e}"); Err(anyhow::anyhow!("命令执行失败: {}", e)) } Err(e) => { warn!("执行超时或系统错误: {e}"); Err(anyhow::anyhow!("执行超时或系统错误: {}", e)) } } } /// 预热Python环境,安装常用依赖 async fn warm_up_python_env(custom_deps: Option>) -> Result<()> { info!("开始预热Python环境..."); // 默认Python依赖列表 let default_deps = [ "requests", "pandas", "numpy", "matplotlib", "scikit-learn", "pytest", "pydantic", "fastapi", "uvicorn", "sqlalchemy", "opencv-python", "python-docx", ]; // 使用自定义依赖或默认依赖 let deps_to_install = if let Some(deps) = custom_deps { info!("使用自定义Python依赖列表"); deps } else { info!("使用默认Python依赖列表"); default_deps.iter().map(|&s| s.to_string()).collect() }; let total_deps = deps_to_install.len(); info!("总共需要预热 {total_deps} 个Python依赖"); // 使用uv安装依赖 for (index, dep) in deps_to_install.iter().enumerate() { let progress = ((index + 1) as f32 / total_deps as f32 * 100.0) as u32; info!("预热进度: {progress}% - 正在安装Python依赖: {dep}"); let mut cmd = Command::new("uv"); cmd.arg("pip") .arg("install") .arg("--default-index") .arg(PYTHON_ACCELERATION_ADDRESS) .arg(dep) .kill_on_drop(true); match CommandExecutor::with_timeout(cmd.status(), 600).await { Ok(Ok(status)) => { if !status.success() { warn!("安装依赖 {dep} 失败"); } } Ok(Err(e)) => { warn!("命令执行失败: {e} - 依赖: {dep}"); continue; } Err(e) => { warn!("执行超时或系统错误: {e} - 依赖: {dep}"); continue; } } } info!("Python环境预热完成 (100%)"); Ok(()) } /// 预热JavaScript/TypeScript环境,缓存常用模块 async fn warm_up_js_env( custom_npm_packages: Option>, custom_jsr_packages: Option>, custom_node_modules: Option>, ) -> Result<()> { info!("开始预热JavaScript/TypeScript环境..."); // 默认npm包列表 let default_npm_packages = [ "lodash", "axios", "moment", "uuid", "express", "react", "react-dom", "typescript", "jest", "webpack", ]; // 默认JSR包列表 let default_jsr_packages = [ "@std/testing", "@std/http", "@std/path", "@std/fs", "@std/encoding/json", ]; // 默认Node.js内置模块列表 let default_node_modules = [ "crypto", "buffer", "fs", "path", "http", "https", "url", "util", "stream", "events", ]; // 使用自定义npm包或默认包 let npm_packages = if let Some(packages) = custom_npm_packages { info!("使用自定义npm包列表"); packages } else { info!("使用默认npm包列表"); default_npm_packages .iter() .map(|&s| s.to_string()) .collect() }; // 使用自定义JSR包或默认包 let jsr_packages = if let Some(packages) = custom_jsr_packages { info!("使用自定义JSR包列表"); packages } else { info!("使用默认JSR包列表"); default_jsr_packages .iter() .map(|&s| s.to_string()) .collect() }; // 使用自定义Node.js模块或默认模块 let node_modules = if let Some(modules) = custom_node_modules { info!("使用自定义Node.js模块列表"); modules } else { info!("使用默认Node.js模块列表"); default_node_modules .iter() .map(|&s| s.to_string()) .collect() }; // 计算总任务数 let total_tasks = npm_packages.len() + jsr_packages.len() + node_modules.len(); info!("总共需要预热 {total_tasks} 个JavaScript/TypeScript模块"); let mut completed_tasks = 0; // 预热npm包 for pkg in npm_packages.iter() { completed_tasks += 1; let progress = (completed_tasks as f32 / total_tasks as f32 * 100.0) as u32; info!("预热进度: {progress}% - 正在缓存npm包: {pkg}"); let mut cmd = Command::new("deno"); cmd.args(["cache", "--reload", &format!("npm:{pkg}")]) .kill_on_drop(true); match CommandExecutor::with_timeout(cmd.status(), 600).await { Ok(Ok(status)) => { if !status.success() { warn!("缓存npm包 {pkg} 失败"); } } Ok(Err(e)) => { warn!("命令执行失败: {e} - 包: {pkg}"); continue; } Err(e) => { warn!("执行超时或系统错误: {e} - 包: {pkg}"); continue; } } } // 预热JSR包 for pkg in jsr_packages.iter() { completed_tasks += 1; let progress = (completed_tasks as f32 / total_tasks as f32 * 100.0) as u32; info!("预热进度: {progress}% - 正在缓存JSR包: {pkg}"); let mut cmd = Command::new("deno"); cmd.args(["cache", "--reload", &format!("jsr:{pkg}")]) .kill_on_drop(true); match CommandExecutor::with_timeout(cmd.status(), 600).await { Ok(Ok(status)) => { if !status.success() { warn!("缓存JSR包 {pkg} 失败"); } } Ok(Err(e)) => { warn!("命令执行失败: {e} - 包: {pkg}"); continue; } Err(e) => { warn!("执行超时或系统错误: {e} - 包: {pkg}"); continue; } } } // 预热Node.js内置模块 for module in node_modules.iter() { completed_tasks += 1; let progress = (completed_tasks as f32 / total_tasks as f32 * 100.0) as u32; info!("预热进度: {progress}% - 正在缓存Node.js模块: {module}"); let mut cmd = Command::new("deno"); cmd.args(["cache", "--reload", &format!("node:{module}")]) .kill_on_drop(true); match CommandExecutor::with_timeout(cmd.status(), 600).await { Ok(Ok(status)) => { if !status.success() { warn!("缓存Node.js模块 {module} 失败"); } } Ok(Err(e)) => { warn!("命令执行失败: {e} - 模块: {module}"); continue; } Err(e) => { warn!("执行超时或系统错误: {e} - 包: {module}"); continue; } } } info!("JavaScript/TypeScript环境预热完成 (100%)"); Ok(()) } /// 预热所有脚本执行环境 pub async fn warm_up_all_envs( custom_python_deps: Option>, custom_npm_packages: Option>, custom_jsr_packages: Option>, custom_node_modules: Option>, ) -> Result<()> { info!("开始预热所有脚本执行环境..."); // 检查并创建 uv 虚拟环境 if let Err(e) = check_and_create_uv_venv().await { warn!("检查或创建 uv 虚拟环境失败: {e}"); } // 安装Python 3.13 if let Err(e) = install_python_3_13().await { warn!("安装Python 3.13失败: {e}"); } // 预热Python环境 if let Err(e) = warm_up_python_env(custom_python_deps).await { warn!("预热Python环境失败: {e}"); } // 预热JavaScript/TypeScript环境 if let Err(e) = warm_up_js_env( custom_npm_packages, custom_jsr_packages, custom_node_modules, ) .await { warn!("预热JavaScript/TypeScript环境失败: {e}"); } info!("所有脚本执行环境预热完成"); Ok(()) } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_warm_up_python_env() { // 测试默认依赖 warm_up_python_env(None).await.unwrap(); // 测试自定义依赖 let custom_deps = vec!["requests".to_string(), "pandas".to_string()]; warm_up_python_env(Some(custom_deps)).await.unwrap(); } #[tokio::test] async fn test_warm_up_js_env() { // 测试默认依赖 warm_up_js_env(None, None, None).await.unwrap(); // 测试自定义依赖 let custom_npm = vec!["lodash".to_string(), "axios".to_string()]; let custom_jsr = vec!["@std/testing".to_string()]; let custom_node = vec!["crypto".to_string(), "buffer".to_string()]; warm_up_js_env(Some(custom_npm), Some(custom_jsr), Some(custom_node)) .await .unwrap(); } }