Files
uv/crates/uv-virtualenv/src/lib.rs
T
konsti 7964bfbb2b Move architecture and operating system probing to Python (#2381)
The architecture of uv does not necessarily match that of the python
interpreter (#2326). In cross compiling/testing scenarios the operating
system can also mismatch. To solve this, we move arch and os detection
to python, vendoring the relevant pypa/packaging code, preventing
mismatches between what the python interpreter was compiled for and what
uv was compiled for.

To make the scripts more manageable, they are now a directory in a
tempdir and we run them with `python -m` . I've simplified the
pypa/packaging code since we're still building the tags in rust. A
`Platform` is now instantiated by querying the python interpreter for
its platform. The pypa/packaging files are copied verbatim for easier
updates except a `lru_cache()` python 3.7 backport.

Error handling is done by a `"result": "success|error"` field that allow
passing error details to rust:

```console
$ uv venv --no-cache
  × Can't use Python at `/home/konsti/projects/uv/.venv/bin/python3`
  ╰─▶ Unknown operation system `linux`
```

I've used the [maturin sysconfig
collection](https://github.com/PyO3/maturin/tree/855f6d2cb1fb8fb43c2bb9e500ab0e5e84bd3140/sysconfig)
as reference. I'm unsure how to test these changes across the wide
variety of platforms.

Fixes #2326
2024-03-13 11:51:14 +00:00

69 lines
1.9 KiB
Rust

use std::io;
use std::path::Path;
use platform_tags::PlatformError;
use thiserror::Error;
use uv_interpreter::{Interpreter, PythonEnvironment};
pub use crate::bare::create_bare_venv;
mod bare;
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
IO(#[from] io::Error),
#[error("Failed to determine python interpreter to use")]
InterpreterError(#[from] uv_interpreter::Error),
#[error(transparent)]
Platform(#[from] PlatformError),
#[error("Reserved key used for pyvenv.cfg: {0}")]
ReservedConfigKey(String),
}
/// The value to use for the shell prompt when inside a virtual environment.
#[derive(Debug)]
pub enum Prompt {
/// Use the current directory name as the prompt.
CurrentDirectoryName,
/// Use the fixed string as the prompt.
Static(String),
/// Default to no prompt. The prompt is then set by the activator script
/// to the virtual environment's directory name.
None,
}
impl Prompt {
/// Determine the prompt value to be used from the command line arguments.
pub fn from_args(prompt: Option<String>) -> Self {
match prompt {
Some(prompt) if prompt == "." => Self::CurrentDirectoryName,
Some(prompt) => Self::Static(prompt),
None => Self::None,
}
}
}
/// Create a virtualenv.
pub fn create_venv(
location: &Path,
interpreter: Interpreter,
prompt: Prompt,
system_site_packages: bool,
extra_cfg: Vec<(String, String)>,
) -> Result<PythonEnvironment, Error> {
// Create the virtualenv at the given location.
let virtualenv = create_bare_venv(
location,
&interpreter,
prompt,
system_site_packages,
extra_cfg,
)?;
// Create the corresponding `PythonEnvironment`.
let interpreter = interpreter.with_virtualenv(virtualenv);
Ok(PythonEnvironment::from_interpreter(interpreter))
}