mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00
Use local copy of gourgeist
(#62)
This PR gets `gourgeist` passing our local CI and integrated into the broader workspace. There's some duplicate between concepts in `gourgeist` (like the `InterpreterInfo`) and structs we have elsewhere, but we can tackle those later.
This commit is contained in:
parent
7caf5f42b8
commit
0ca17a1cf2
10 changed files with 207 additions and 1572 deletions
1450
crates/gourgeist/Cargo.lock
generated
1450
crates/gourgeist/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -8,54 +8,27 @@ license = "MIT OR Apache-2.0"
|
|||
keywords = ["virtualenv", "venv", "python"]
|
||||
readme = "Readme.md"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
camino = { version = "1.1.6", features = ["serde1"] }
|
||||
clap = { version = "4.4.5", features = ["derive"] }
|
||||
configparser = "3.0.2"
|
||||
dirs = "5.0.1"
|
||||
fs-err = "2.9.0"
|
||||
install-wheel-rs = { version = "0.0.1", optional = true }
|
||||
minreq = { version = "2.10.0", optional = true, features = ["https"] }
|
||||
rayon = { version = "1.8.0", optional = true }
|
||||
seahash = "4.1.0"
|
||||
serde = { version = "1.0.188", features = ["derive"] }
|
||||
serde_json = "1.0.107"
|
||||
tempfile = "3.8.0"
|
||||
thiserror = "1.0.49"
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
which = "4.4.2"
|
||||
install-wheel-rs = { path = "../install-wheel-rs", optional = true }
|
||||
wheel-filename = { path = "../wheel-filename" }
|
||||
|
||||
camino = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
configparser = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
fs-err = { workspace = true }
|
||||
reqwest = { workspace = true, optional = true, features = ["blocking"] }
|
||||
rayon = { workspace = true, optional = true }
|
||||
seahash = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
which = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["install"]
|
||||
install = ["install-wheel-rs", "minreq"]
|
||||
install = ["install-wheel-rs", "reqwest"]
|
||||
parallel = ["rayon"]
|
||||
|
||||
# zip implementation
|
||||
[profile.dev.package.adler]
|
||||
opt-level = 3
|
||||
|
||||
[profile.profiling]
|
||||
inherits = "release"
|
||||
lto = "thin"
|
||||
debug = true
|
||||
|
||||
# The profile that 'cargo dist' will build with
|
||||
[profile.dist]
|
||||
inherits = "release"
|
||||
lto = "thin"
|
||||
|
||||
# Config for 'cargo dist'
|
||||
[workspace.metadata.dist]
|
||||
# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax)
|
||||
cargo-dist-version = "0.3.1"
|
||||
# CI backends to support
|
||||
ci = ["github"]
|
||||
# The installers to generate for each app
|
||||
installers = ["shell", "powershell"]
|
||||
# Target platforms to build apps for (Rust target-triple syntax)
|
||||
targets = ["x86_64-unknown-linux-gnu", "aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-pc-windows-msvc"]
|
||||
# Publish jobs to run in CI
|
||||
pr-run-mode = "plan"
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
//! Create a bare virtualenv without any packages install
|
||||
|
||||
use crate::interpreter::InterpreterInfo;
|
||||
use std::io;
|
||||
use std::io::{BufWriter, Write};
|
||||
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use fs_err as fs;
|
||||
#[cfg(unix)]
|
||||
use fs_err::os::unix::fs::symlink;
|
||||
use fs_err::File;
|
||||
use std::io;
|
||||
use std::io::{BufWriter, Write};
|
||||
use tracing::info;
|
||||
|
||||
use crate::interpreter::InterpreterInfo;
|
||||
|
||||
/// The bash activate scripts with the venv dependent paths patches out
|
||||
const ACTIVATE_TEMPLATES: &[(&str, &str)] = &[
|
||||
("activate", include_str!("activator/activate")),
|
||||
|
@ -27,27 +29,34 @@ const VIRTUALENV_PATCH: &str = include_str!("_virtualenv.py");
|
|||
/// Very basic `.cfg` file format writer.
|
||||
fn write_cfg(f: &mut impl Write, data: &[(&str, String); 8]) -> io::Result<()> {
|
||||
for (key, value) in data {
|
||||
writeln!(f, "{} = {}", key, value)?;
|
||||
writeln!(f, "{key} = {value}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Absolute paths of the virtualenv
|
||||
#[derive(Debug)]
|
||||
pub struct VenvPaths {
|
||||
pub(crate) struct VenvPaths {
|
||||
/// The location of the virtualenv, e.g. `.venv`
|
||||
pub root: Utf8PathBuf,
|
||||
#[allow(unused)]
|
||||
pub(crate) root: Utf8PathBuf,
|
||||
|
||||
/// The python interpreter.rs inside the virtualenv, on unix `.venv/bin/python`
|
||||
pub interpreter: Utf8PathBuf,
|
||||
#[allow(unused)]
|
||||
pub(crate) interpreter: Utf8PathBuf,
|
||||
|
||||
/// The directory with the scripts, on unix `.venv/bin`
|
||||
pub bin: Utf8PathBuf,
|
||||
#[allow(unused)]
|
||||
pub(crate) bin: Utf8PathBuf,
|
||||
|
||||
/// The site-packages directory where all the packages are installed to, on unix
|
||||
/// and python 3.11 `.venv/lib/python3.11/site-packages`
|
||||
pub site_packages: Utf8PathBuf,
|
||||
#[allow(unused)]
|
||||
pub(crate) site_packages: Utf8PathBuf,
|
||||
}
|
||||
|
||||
/// Write all the files that belong to a venv without any packages installed.
|
||||
pub fn create_bare_venv(
|
||||
pub(crate) fn create_bare_venv(
|
||||
location: &Utf8Path,
|
||||
base_python: &Utf8Path,
|
||||
info: &InterpreterInfo,
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
use crate::{crate_cache_dir, Error};
|
||||
use camino::{FromPathBufError, Utf8Path, Utf8PathBuf};
|
||||
use fs_err as fs;
|
||||
use fs_err::File;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
use std::io::{BufReader, Write};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::time::SystemTime;
|
||||
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use fs_err as fs;
|
||||
use fs_err::File;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
use crate::{crate_cache_dir, Error};
|
||||
|
||||
const QUERY_PYTHON: &str = include_str!("query_python.py");
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
|
@ -44,20 +46,19 @@ pub fn get_interpreter_info(interpreter: &Utf8Path) -> Result<InterpreterInfo, E
|
|||
debug!("Using cache entry {cache_file}");
|
||||
if modified == cache_entry.modified && interpreter == cache_entry.interpreter {
|
||||
return Ok(cache_entry.interpreter_info);
|
||||
} else {
|
||||
debug!(
|
||||
"Removing mismatching cache entry {cache_file} ({} {} {} {})",
|
||||
modified, cache_entry.modified, interpreter, cache_entry.interpreter
|
||||
);
|
||||
if let Err(remove_err) = fs::remove_file(&cache_file) {
|
||||
warn!("Failed to mismatching cache file at {cache_file}: {remove_err}")
|
||||
}
|
||||
}
|
||||
debug!(
|
||||
"Removing mismatching cache entry {cache_file} ({} {} {} {})",
|
||||
modified, cache_entry.modified, interpreter, cache_entry.interpreter
|
||||
);
|
||||
if let Err(remove_err) = fs::remove_file(&cache_file) {
|
||||
warn!("Failed to mismatching cache file at {cache_file}: {remove_err}");
|
||||
}
|
||||
}
|
||||
Err(cache_err) => {
|
||||
debug!("Removing broken cache entry {cache_file} ({cache_err})");
|
||||
if let Err(remove_err) = fs::remove_file(&cache_file) {
|
||||
warn!("Failed to remove broken cache file at {cache_file}: {remove_err} (original error: {cache_err})")
|
||||
warn!("Failed to remove broken cache file at {cache_file}: {remove_err} (original error: {cache_err})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +189,7 @@ pub fn parse_python_cli(cli_python: Option<Utf8PathBuf>) -> Result<Utf8PathBuf,
|
|||
)
|
||||
})?
|
||||
.try_into()
|
||||
.map_err(|err: FromPathBufError| err.into_io_error())?;
|
||||
.map_err(camino::FromPathBufError::into_io_error)?;
|
||||
info!("Resolved {python} to {python_in_path}");
|
||||
python_in_path
|
||||
};
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
use crate::bare::create_bare_venv;
|
||||
use std::io;
|
||||
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use dirs::cache_dir;
|
||||
use interpreter::InterpreterInfo;
|
||||
use std::io;
|
||||
use tempfile::PersistError;
|
||||
use thiserror::Error;
|
||||
|
||||
use interpreter::InterpreterInfo;
|
||||
pub use interpreter::{get_interpreter_info, parse_python_cli};
|
||||
|
||||
use crate::bare::create_bare_venv;
|
||||
|
||||
mod bare;
|
||||
mod interpreter;
|
||||
#[cfg(feature = "install")]
|
||||
|
@ -40,7 +42,7 @@ pub enum Error {
|
|||
},
|
||||
#[cfg(feature = "install")]
|
||||
#[error("Failed to contact pypi")]
|
||||
MinReq(#[from] minreq::Error),
|
||||
Request(#[from] reqwest::Error),
|
||||
#[cfg(feature = "install")]
|
||||
#[error("Failed to install {package}")]
|
||||
InstallWheel {
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
use camino::Utf8PathBuf;
|
||||
use clap::Parser;
|
||||
use gourgeist::{create_venv, get_interpreter_info, parse_python_cli};
|
||||
use std::error::Error;
|
||||
use std::process::ExitCode;
|
||||
use std::time::Instant;
|
||||
|
||||
use camino::Utf8PathBuf;
|
||||
use clap::Parser;
|
||||
use tracing::info;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
use tracing_subscriber::{fmt, EnvFilter};
|
||||
|
||||
use gourgeist::{create_venv, get_interpreter_info, parse_python_cli};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Cli {
|
||||
path: Option<Utf8PathBuf>,
|
||||
|
@ -38,10 +40,17 @@ fn main() -> ExitCode {
|
|||
let result = run();
|
||||
info!("Took {}ms", start.elapsed().as_millis());
|
||||
if let Err(err) = result {
|
||||
eprintln!("💥 virtualenv creator failed");
|
||||
#[allow(clippy::print_stderr)]
|
||||
{
|
||||
eprintln!("💥 virtualenv creator failed");
|
||||
}
|
||||
|
||||
let mut last_error: Option<&(dyn Error + 'static)> = Some(&err);
|
||||
while let Some(err) = last_error {
|
||||
eprintln!(" Caused by: {}", err);
|
||||
#[allow(clippy::print_stderr)]
|
||||
{
|
||||
eprintln!(" Caused by: {err}");
|
||||
}
|
||||
last_error = err.source();
|
||||
}
|
||||
ExitCode::FAILURE
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
use crate::bare::VenvPaths;
|
||||
use crate::interpreter::InterpreterInfo;
|
||||
use crate::{crate_cache_dir, Error};
|
||||
use camino::{FromPathBufError, Utf8Path, Utf8PathBuf};
|
||||
use fs_err as fs;
|
||||
use fs_err::File;
|
||||
use install_wheel_rs::{install_wheel, InstallLocation, WheelFilename};
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use std::io;
|
||||
use std::io::BufWriter;
|
||||
use std::str::FromStr;
|
||||
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use fs_err as fs;
|
||||
use fs_err::File;
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use tempfile::NamedTempFile;
|
||||
use tracing::info;
|
||||
|
||||
pub fn download_wheel_cached(filename: &str, url: &str) -> Result<Utf8PathBuf, Error> {
|
||||
use install_wheel_rs::{install_wheel, InstallLocation};
|
||||
use wheel_filename::WheelFilename;
|
||||
|
||||
use crate::bare::VenvPaths;
|
||||
use crate::interpreter::InterpreterInfo;
|
||||
use crate::{crate_cache_dir, Error};
|
||||
|
||||
pub(crate) fn download_wheel_cached(filename: &str, url: &str) -> Result<Utf8PathBuf, Error> {
|
||||
let wheels_cache = crate_cache_dir()?.join("wheels");
|
||||
let cached_wheel = wheels_cache.join(filename);
|
||||
if cached_wheel.is_file() {
|
||||
|
@ -28,8 +32,8 @@ pub fn download_wheel_cached(filename: &str, url: &str) -> Result<Utf8PathBuf, E
|
|||
.path()
|
||||
.to_path_buf()
|
||||
.try_into()
|
||||
.map_err(|err: FromPathBufError| err.into_io_error())?;
|
||||
let mut response = minreq::get(url).send_lazy()?;
|
||||
.map_err(camino::FromPathBufError::into_io_error)?;
|
||||
let mut response = reqwest::blocking::get(url)?;
|
||||
io::copy(&mut response, &mut BufWriter::new(&mut tempfile)).map_err(|err| {
|
||||
Error::WheelDownload {
|
||||
url: url.to_string(),
|
||||
|
@ -42,7 +46,7 @@ pub fn download_wheel_cached(filename: &str, url: &str) -> Result<Utf8PathBuf, E
|
|||
}
|
||||
|
||||
/// Install pip, setuptools and wheel from cache pypi with atm fixed wheels
|
||||
pub fn install_base_packages(
|
||||
pub(crate) fn install_base_packages(
|
||||
location: &Utf8Path,
|
||||
info: &InterpreterInfo,
|
||||
paths: &VenvPaths,
|
||||
|
@ -71,7 +75,8 @@ pub fn install_base_packages(
|
|||
install_wheel(
|
||||
&install_location,
|
||||
File::open(wheel_file)?,
|
||||
parsed_filename,
|
||||
&parsed_filename,
|
||||
false,
|
||||
false,
|
||||
&[],
|
||||
// Only relevant for monotrail style installation
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
//! Deprecated, use only as template when implementing caching
|
||||
|
||||
use crate::Error;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use dirs::data_dir;
|
||||
use fs_err as fs;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
/// Install wheel, pip and setuptools from the cache
|
||||
pub(crate) fn install_base_packages(
|
||||
bin_dir: &Utf8Path,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue