1use std::env;
8use std::path::PathBuf;
9use std::process::Command;
10
11pub fn python_package_dir() -> Option<PathBuf> {
18 static DIR: std::sync::OnceLock<Option<PathBuf>> = std::sync::OnceLock::new();
19 DIR.get_or_init(|| {
20 if let Some(root) = env::var_os("XIL_CODEROOT") {
21 let p = PathBuf::from(root).join("src").join("xil_pipeline");
22 if p.join("__init__.py").is_file() {
23 return Some(p);
24 }
25 }
26 let beside_py_bin = env::var_os("XIL_PY_BIN")
27 .map(PathBuf::from)
28 .and_then(|p| p.parent().map(|d| d.join("python")));
29 beside_py_bin
30 .into_iter()
31 .chain([PathBuf::from("python3")])
32 .find_map(|python| ask(&python))
33 })
34 .clone()
35}
36
37fn ask(python: &std::path::Path) -> Option<PathBuf> {
38 let out = Command::new(python)
39 .args([
40 "-c",
41 "import os, xil_pipeline; print(os.path.dirname(xil_pipeline.__file__))",
42 ])
43 .output()
44 .ok()?;
45 let dir = String::from_utf8_lossy(&out.stdout).trim().to_string();
46 (out.status.success() && !dir.is_empty()).then(|| PathBuf::from(dir))
47}
48
49pub fn describe() -> String {
52 let mut out = String::new();
53 match python_package_dir() {
54 Some(d) => out.push_str(&format!("worker scripts: {}\n", d.display())),
55 None => out.push_str(
56 "worker scripts: NOT FOUND (set XIL_CODEROOT to the xil-pipeline checkout)\n",
57 ),
58 }
59 let package = python_package_dir();
60 for venv in ["venv-chatterbox", "venv-whisper", "venv-mmaudio"] {
61 let python = xil_core::workspace::resolve_venv_python(venv, None, package.as_deref());
62 let missing = format!(
63 "not found (run: xil setup {})",
64 venv.trim_start_matches("venv-")
65 );
66 out.push_str(&format!(
67 "{venv}: {}\n",
68 python.as_deref().unwrap_or(missing.as_str())
69 ));
70 }
71 out
72}