findpython/providers/
mod.rs

1use std::path::PathBuf;
2
3use crate::helpers;
4use crate::PythonVersion;
5use lazy_static::lazy_static;
6
7mod asdf;
8mod path;
9mod pyenv;
10mod rye;
11
12#[cfg(feature = "pyo3")]
13pub mod pyobject;
14
15#[cfg(windows)]
16mod winreg;
17
18#[cfg(windows)]
19lazy_static! {
20    pub static ref ALL_PROVIDERS: [&'static str; 5] = ["path", "pyenv", "rye", "asdf", "winreg"];
21}
22
23#[cfg(not(windows))]
24lazy_static! {
25    pub static ref ALL_PROVIDERS: [&'static str; 4] = ["path", "pyenv", "rye", "asdf"];
26}
27
28pub trait Provider: Send + Sync {
29    fn create() -> Option<Self>
30    where
31        Self: Sized;
32
33    fn find_pythons(&self) -> Vec<PythonVersion>;
34}
35
36pub fn get_provider(name: &str) -> Option<Box<dyn Provider>> {
37    match name {
38        "path" => path::PathProvider::create().map(|p| Box::new(p) as Box<dyn Provider>),
39        "pyenv" => pyenv::PyenvProvider::create().map(|p| Box::new(p) as Box<dyn Provider>),
40        "rye" => rye::RyeProvider::create().map(|p| Box::new(p) as Box<dyn Provider>),
41        "asdf" => asdf::AsdfProvider::create().map(|p| Box::new(p) as Box<dyn Provider>),
42        #[cfg(windows)]
43        "winreg" => winreg::WinRegProvider::create().map(|p| Box::new(p) as Box<dyn Provider>),
44        _ => None,
45    }
46}
47
48/// Find all Python versions under the given path.
49/// ### Arguments:
50///
51/// path: The path to search for Python versions under.
52/// as_interpreter: Whether to use the path as an interpreter.
53///     Must not be true if it might be a wrapper script.
54///
55/// ### Returns:
56/// A list of Python versions found under the given path.
57pub fn find_pythons_from_path(path: &PathBuf, as_interpreter: bool) -> Vec<PythonVersion> {
58    match path.read_dir() {
59        Ok(entries) => entries
60            .into_iter()
61            .filter_map(|entry| {
62                let path = entry.ok()?.path();
63                if helpers::path_is_python(&path) {
64                    let mut python = PythonVersion::new(path.to_owned());
65                    if as_interpreter {
66                        python = python.with_interpreter(path.to_owned());
67                    }
68                    Some(python)
69                } else {
70                    None
71                }
72            })
73            .collect(),
74        Err(_) => vec![],
75    }
76}