7964bfbb2b
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
76 lines
2.0 KiB
Rust
76 lines
2.0 KiB
Rust
use std::error::Error;
|
|
use std::path::PathBuf;
|
|
use std::process::ExitCode;
|
|
use std::time::Instant;
|
|
|
|
use anstream::eprintln;
|
|
use clap::Parser;
|
|
use directories::ProjectDirs;
|
|
use tracing::info;
|
|
use tracing_subscriber::layer::SubscriberExt;
|
|
use tracing_subscriber::util::SubscriberInitExt;
|
|
use tracing_subscriber::{fmt, EnvFilter};
|
|
|
|
use uv_cache::Cache;
|
|
use uv_interpreter::{find_default_python, find_requested_python};
|
|
use uv_virtualenv::{create_bare_venv, Prompt};
|
|
|
|
#[derive(Parser, Debug)]
|
|
struct Cli {
|
|
path: Option<PathBuf>,
|
|
#[clap(short, long)]
|
|
python: Option<String>,
|
|
#[clap(long)]
|
|
prompt: Option<String>,
|
|
#[clap(long)]
|
|
system_site_packages: bool,
|
|
}
|
|
|
|
fn run() -> Result<(), uv_virtualenv::Error> {
|
|
let cli = Cli::parse();
|
|
let location = cli.path.unwrap_or(PathBuf::from(".venv"));
|
|
let cache = if let Some(project_dirs) = ProjectDirs::from("", "", "uv-virtualenv") {
|
|
Cache::from_path(project_dirs.cache_dir())?
|
|
} else {
|
|
Cache::from_path(".cache")?
|
|
};
|
|
let interpreter = if let Some(python_request) = &cli.python {
|
|
find_requested_python(python_request, &cache)?.ok_or(
|
|
uv_interpreter::Error::NoSuchPython(python_request.to_string()),
|
|
)?
|
|
} else {
|
|
find_default_python(&cache)?
|
|
};
|
|
create_bare_venv(
|
|
&location,
|
|
&interpreter,
|
|
Prompt::from_args(cli.prompt),
|
|
cli.system_site_packages,
|
|
Vec::new(),
|
|
)?;
|
|
Ok(())
|
|
}
|
|
|
|
fn main() -> ExitCode {
|
|
tracing_subscriber::registry()
|
|
.with(fmt::layer())
|
|
.with(EnvFilter::from_default_env())
|
|
.init();
|
|
|
|
let start = Instant::now();
|
|
let result = run();
|
|
info!("Took {}ms", start.elapsed().as_millis());
|
|
if let Err(err) = result {
|
|
eprintln!("💥 virtualenv creator failed");
|
|
|
|
let mut last_error: Option<&(dyn Error + 'static)> = Some(&err);
|
|
while let Some(err) = last_error {
|
|
eprintln!(" Caused by: {err}");
|
|
last_error = err.source();
|
|
}
|
|
ExitCode::FAILURE
|
|
} else {
|
|
ExitCode::SUCCESS
|
|
}
|
|
}
|