py_executer_lib/
py_executer_lib.rs1pub mod macros;
2
3use anyhow::anyhow;
4use colored::*;
5use std::collections::HashMap;
6use std::process::Command;
7use std::{env, path::PathBuf};
8
9fn append_pwd_to_pythonpath(current_dir: PathBuf) -> HashMap<String, String> {
11 if !current_dir.exists() {
12 error_println!(
13 "Current directory not valid: {}",
14 current_dir.display().to_string().bold()
15 );
16 HashMap::new()
17 } else {
18 let mut path = env::var("PYTHONPATH").unwrap_or_default();
19 if !path.contains(¤t_dir.to_string_lossy().to_string()) {
20 if !path.is_empty() {
21 path.push(':');
22 }
23 path.push_str(current_dir.to_string_lossy().to_string().as_str());
24 return HashMap::from([("PYTHONPATH".to_string(), path)]);
25 }
26 HashMap::new()
27 }
28}
29
30pub fn set_additional_env_var(
32 additional_env_from_args: Vec<String>,
33 quiet: bool,
34) -> HashMap<String, String> {
35 let mut additional_env = HashMap::new();
36
37 let current_dir = env::current_dir().unwrap();
39 additional_env.extend(append_pwd_to_pythonpath(current_dir));
40
41 for env_var in additional_env_from_args {
42 if let Some(pos) = env_var.find('=') {
43 let key = env_var[..pos].to_string();
44 let value = env_var[pos + 1..].to_string();
45 additional_env.insert(key.clone(), value.clone());
46 if !quiet {
47 println!("Setting env: {} = {}", key.bold(), value);
48 }
49 } else {
50 if !quiet {
51 warning_println!(
52 "Warning: Ignoring malformed environment variable: {}",
53 env_var.bold()
54 );
55 }
56 }
57 }
58 additional_env
59}
60
61pub fn validate_to_absolute_path(script_path: &PathBuf) -> anyhow::Result<PathBuf> {
73 match script_path.canonicalize() {
74 Ok(path) => {
75 if !path.exists() {
76 return Err(anyhow!("{} not exists", path.display().to_string().bold()));
77 }
78 Ok(path)
79 }
80 Err(err) => Err(anyhow!("Failed to get absolute path of script: {}", err)),
81 }
82}
83
84pub fn get_uv_path() -> anyhow::Result<String> {
85 #[cfg(not(target_os = "windows"))]
87 let find_executable = "which";
88
89 #[cfg(target_os = "windows")]
91 let find_executable = "where";
92
93 let output = Command::new(find_executable).arg("uv").output()?;
94 if output.status.success() {
95 let path = String::from_utf8(output.stdout)?.trim().to_string();
97 Ok(path)
98 } else {
99 eprintln!("Please run the following command to install uv:");
103 #[cfg(not(target_os = "windows"))]
104 eprintln!("wget -qO- https://astral.sh/uv/install.sh | sh");
105
106 #[cfg(target_os = "windows")]
108 eprintln!(
109 "powershell -ExecutionPolicy ByPass -c \"irm https://astral.sh/uv/install.ps1 | iex\""
110 );
111 Err(anyhow!("uv not installed"))
112 }
113}
114
115pub fn get_python_exec_path(venv_path: &PathBuf) -> PathBuf {
116 PathBuf::from(if cfg!(target_os = "windows") {
117 venv_path
118 .join("Scripts")
119 .join("python.exe")
120 .to_string_lossy()
121 .to_string()
122 } else {
123 venv_path
124 .join("bin")
125 .join("python")
126 .to_string_lossy()
127 .to_string()
128 })
129}
130
131#[test]
132fn test_validate_to_absolute_path() {
133 let script_path = PathBuf::from("test.py");
134 let result = validate_to_absolute_path(&script_path);
135 assert!(result.is_ok());
136 println!("Script path: {}", result.unwrap().display().to_string());
137
138 let non_existent_path = PathBuf::from("");
139 let result = validate_to_absolute_path(&non_existent_path);
140 assert!(result.is_err());
141 println!("Error: {}", result.unwrap_err());
142}