From c62d0f4318492463907f65b65f856aec1fa8f604 Mon Sep 17 00:00:00 2001 From: bluss Date: Wed, 24 Apr 2024 21:56:50 +0200 Subject: [PATCH] Use uv in rye build when enabled (#978) The `build` package supports uv since version 1.2.0 - it can use either uv or pip as installer. The main way to use it would be to install `build[uv]` but rye already has uv installed separately, build will find it on the path as a fallback, so this can work for rye. build is implicitly tested by test_publish. Relates to #668 --- CHANGELOG.md | 2 ++ rye/src/bootstrap.rs | 4 ++-- rye/src/cli/build.rs | 26 ++++++++++++++++++++++---- rye/src/utils/mod.rs | 11 +++++++++++ rye/src/uv.rs | 7 +++++++ 5 files changed, 44 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b604114bf..371864c620 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ that were not yet released. _Unreleased_ +- Use uv in `rye build` when uv is enabled. #978 + ## 0.33.0 diff --git a/rye/src/bootstrap.rs b/rye/src/bootstrap.rs index 79675a4c0b..7efed5d2f2 100644 --- a/rye/src/bootstrap.rs +++ b/rye/src/bootstrap.rs @@ -33,10 +33,10 @@ pub const SELF_PYTHON_TARGET_VERSION: PythonVersionRequest = PythonVersionReques suffix: None, }; -const SELF_VERSION: u64 = 17; +const SELF_VERSION: u64 = 18; const SELF_REQUIREMENTS: &str = r#" -build==1.1.1 +build==1.2.1 certifi==2024.2.2 charset-normalizer==3.3.2 click==8.1.7 diff --git a/rye/src/cli/build.rs b/rye/src/cli/build.rs index e944ffd0d1..6e94f76e25 100644 --- a/rye/src/cli/build.rs +++ b/rye/src/cli/build.rs @@ -2,13 +2,15 @@ use std::fs; use std::path::PathBuf; use std::process::{Command, Stdio}; -use anyhow::{bail, Error}; +use anyhow::{anyhow, bail, Error}; use clap::Parser; use console::style; use crate::bootstrap::ensure_self_venv; +use crate::config::Config; use crate::pyproject::{locate_projects, PyProject}; -use crate::utils::{get_venv_python_bin, CommandOutput, IoPathContext}; +use crate::utils::{get_venv_python_bin, prepend_path_to_path_env, CommandOutput, IoPathContext}; +use crate::uv::UvBuilder; /// Builds a package for distribution. #[derive(Parser, Debug)] @@ -44,7 +46,7 @@ pub struct Args { pub fn execute(cmd: Args) -> Result<(), Error> { let output = CommandOutput::from_quiet_and_verbose(cmd.quiet, cmd.verbose); - let venv = ensure_self_venv(output)?; + let self_venv = ensure_self_venv(output)?; let project = PyProject::load_or_discover(cmd.pyproject.as_deref())?; let out = match cmd.out { @@ -61,6 +63,7 @@ pub fn execute(cmd: Args) -> Result<(), Error> { } } + let use_uv = Config::current().use_uv(); let projects = locate_projects(project, cmd.all, &cmd.package[..])?; for project in projects { @@ -75,7 +78,7 @@ pub fn execute(cmd: Args) -> Result<(), Error> { style(project.normalized_name()?).cyan() ); - let mut build_cmd = Command::new(get_venv_python_bin(&venv)); + let mut build_cmd = Command::new(get_venv_python_bin(&self_venv)); build_cmd .arg("-mbuild") .env("NO_COLOR", "1") @@ -83,6 +86,17 @@ pub fn execute(cmd: Args) -> Result<(), Error> { .arg(&out) .arg(&*project.root_path()); + if use_uv { + // we need to ensure uv is available to use without installing it into self_venv + let uv = UvBuilder::new().with_output(output).ensure_exists()?; + let uv_dir = uv + .uv_bin() + .parent() + .ok_or_else(|| anyhow!("Could not find uv binary in self venv: empty path"))?; + build_cmd.env("PATH", prepend_path_to_path_env(uv_dir)?); + build_cmd.arg("--installer=uv"); + } + if cmd.wheel { build_cmd.arg("--wheel"); } @@ -90,6 +104,10 @@ pub fn execute(cmd: Args) -> Result<(), Error> { build_cmd.arg("--sdist"); } + if output == CommandOutput::Verbose { + build_cmd.arg("--verbose"); + } + if output == CommandOutput::Quiet { build_cmd.stdout(Stdio::null()); build_cmd.stderr(Stdio::null()); diff --git a/rye/src/utils/mod.rs b/rye/src/utils/mod.rs index a236229004..c1121d1c5e 100644 --- a/rye/src/utils/mod.rs +++ b/rye/src/utils/mod.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::convert::Infallible; +use std::ffi::OsString; use std::io::{Cursor, Read}; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus, Stdio}; @@ -234,6 +235,16 @@ where ENV_VAR_RE.replace_all(string, |m: &Captures| f(&m[1]).unwrap_or_default()) } +/// Prepend the given path to the current value of the $PATH environment variable +pub fn prepend_path_to_path_env(path: &Path) -> Result { + let mut paths = Vec::new(); + paths.push(path.to_owned()); + if let Some(existing_path) = std::env::var_os("PATH") { + paths.extend(std::env::split_paths(&existing_path)); + } + Ok(std::env::join_paths(paths)?) +} + #[derive(Copy, Clone, Debug)] enum ArchiveFormat { TarGz, diff --git a/rye/src/uv.rs b/rye/src/uv.rs index 76bda81e83..da9ed10e91 100644 --- a/rye/src/uv.rs +++ b/rye/src/uv.rs @@ -272,6 +272,13 @@ impl Uv { } } + /// Get uv binary path + /// + /// Warning: Always use self.cmd() when at all possible + pub fn uv_bin(&self) -> &Path { + &self.uv_bin + } + fn create_venv( &self, venv_dir: &Path,