1use crate::{get_python_exec_path, warning_println};
2use anyhow::anyhow;
3use std::path::PathBuf;
4use std::process::{Command, Stdio};
5
6pub fn get_python_native_path(uv_path: &String) -> String {
20 if uv_path.is_empty() {
21 #[cfg(not(target_os = "windows"))]
22 let find_executable = "which";
23
24 #[cfg(target_os = "windows")]
26 let find_executable = "where";
27
28 let output = Command::new(find_executable)
29 .arg("python3")
30 .output()
31 .unwrap();
32 if output.status.success() {
33 String::from_utf8(output.stdout)
34 .unwrap_or("".to_string())
35 .trim()
36 .to_string()
37 } else {
38 "".to_string()
39 }
40 } else {
41 "".to_string()
42 }
43}
44
45fn validate_venv(venv_path: PathBuf) -> anyhow::Result<PathBuf> {
52 if !venv_path.exists() {
53 Err(anyhow!("{} not exists", venv_path.display().to_string()))
54 } else {
55 let python_exec_paths = get_python_exec_path(&venv_path);
56 if !python_exec_paths.exists() {
57 Err(anyhow!(
58 "Python executable {} not exists",
59 python_exec_paths.display().to_string()
60 ))
61 } else {
62 Ok(venv_path)
63 }
64 }
65}
66
67pub fn get_venv_path(
94 venv: PathBuf,
95 runtime_path: PathBuf,
96 uv_path: String,
97 python_native_path: String,
98 quiet: bool,
99 clean: bool,
100 files_to_clean: &mut Vec<PathBuf>,
101) -> PathBuf {
102 match validate_venv(venv) {
103 Ok(venv) => venv,
104 Err(e) => {
105 if !quiet {
106 warning_println!(
107 "Failed to validate provided venv: {}, looking for a possible one under current directory",
108 e
109 );
110 }
111 let possible_venv_dir_names = ["venv", ".venv"];
112 possible_venv_dir_names
113 .iter()
114 .map(|name| runtime_path.join(name))
115 .find(|path| path.exists())
116 .unwrap_or_else(|| {
117 prepare_venv(
118 quiet,
119 &runtime_path,
120 &uv_path,
121 &python_native_path,
122 clean,
123 files_to_clean,
124 )
125 })
126 }
127 }
128}
129
130fn prepare_venv(
131 quiet: bool,
132 runtime_path: &PathBuf,
133 uv_path: &String,
134 python_native_path: &String,
135 clean: bool,
136 files_to_clean: &mut Vec<PathBuf>,
137) -> PathBuf {
138 if !quiet {
139 warning_println!("No venv found in current directory, will generate one");
140 }
141 let new_venv_path = runtime_path.join(".venv");
142 let _ = Command::new(if uv_path.is_empty() {
143 &python_native_path
144 } else {
145 &uv_path
146 })
147 .args(["venv", &new_venv_path.to_str().unwrap()])
148 .stdout(if quiet {
149 Stdio::null()
150 } else {
151 Stdio::inherit()
152 })
153 .stderr(if quiet {
154 Stdio::null()
155 } else {
156 Stdio::inherit()
157 })
158 .output()
159 .unwrap();
160 if clean {
161 files_to_clean.push(new_venv_path.clone());
162 }
163 new_venv_path
164}