virtualenv_rs/
lib.rs

1use crate::bare::create_bare_venv;
2use camino::{Utf8Path, Utf8PathBuf};
3use dirs::cache_dir;
4use interpreter::InterpreterInfo;
5use std::io;
6use tempfile::PersistError;
7use thiserror::Error;
8
9pub use interpreter::{get_interpreter_info, parse_python_cli};
10
11mod bare;
12mod interpreter;
13#[cfg(feature = "install")]
14mod packages;
15#[cfg(not(feature = "install"))]
16mod virtualenv_cache;
17
18#[derive(Debug, Error)]
19pub enum Error {
20    #[error(transparent)]
21    IO(#[from] io::Error),
22    /// It's effectively an io error with extra info
23    #[error(transparent)]
24    Persist(#[from] PersistError),
25    /// Adds url and target path to the io error
26    #[error("Failed to download wheel from {url} to {path}")]
27    WheelDownload {
28        url: String,
29        path: Utf8PathBuf,
30        #[source]
31        err: io::Error,
32    },
33    #[error("Failed to determine python interpreter to use")]
34    InvalidPythonInterpreter(#[source] Box<dyn std::error::Error + Sync + Send>),
35    #[error("Failed to query python interpreter at {interpreter}")]
36    PythonSubcommand {
37        interpreter: Utf8PathBuf,
38        #[source]
39        err: io::Error,
40    },
41    #[cfg(feature = "install")]
42    #[error("Failed to contact pypi")]
43    MinReq(#[from] minreq::Error),
44    #[cfg(feature = "install")]
45    #[error("Failed to install {package}")]
46    InstallWheel {
47        package: String,
48        #[source]
49        err: install_wheel_rs::Error,
50    },
51}
52
53pub(crate) fn crate_cache_dir() -> io::Result<Utf8PathBuf> {
54    Ok(cache_dir()
55        .and_then(|path| Utf8PathBuf::from_path_buf(path).ok())
56        .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Couldn't detect cache dir"))?
57        .join(env!("CARGO_PKG_NAME")))
58}
59
60/// Create a virtualenv and if not bare, install `wheel`, `pip` and `setuptools`.
61pub fn create_venv(
62    location: &Utf8Path,
63    base_python: &Utf8Path,
64    info: &InterpreterInfo,
65    bare: bool,
66) -> Result<(), Error> {
67    let paths = create_bare_venv(location, base_python, info)?;
68
69    if !bare {
70        #[cfg(feature = "install")]
71        {
72            packages::install_base_packages(location, info, &paths)?;
73        }
74        #[cfg(not(feature = "install"))]
75        {
76            virtualenv_cache::install_base_packages(
77                &paths.bin,
78                &paths.interpreter,
79                &paths.site_packages,
80            )?;
81        }
82    }
83
84    Ok(())
85}