diff --git a/crates/uv-installer/src/editable.rs b/crates/uv-installer/src/editable.rs index f0a3ce71f..c0915a0d7 100644 --- a/crates/uv-installer/src/editable.rs +++ b/crates/uv-installer/src/editable.rs @@ -1,10 +1,10 @@ use serde::Deserialize; +use std::path::Path; use distribution_types::{ CachedDist, InstalledDist, InstalledMetadata, InstalledVersion, LocalEditable, Name, }; use pypi_types::Metadata23; -use requirements_txt::EditableRequirement; use uv_normalize::PackageName; @@ -112,10 +112,10 @@ impl std::fmt::Display for ResolvedEditable { } } -/// Returns `true` if the [`EditableRequirement`] contains dynamic metadata. -pub fn is_dynamic(editable: &EditableRequirement) -> bool { +/// Returns `true` if the source tree at the given path contains dynamic metadata. +pub fn is_dynamic(path: &Path) -> bool { // If there's no `pyproject.toml`, we assume it's dynamic. - let Ok(contents) = fs_err::read_to_string(editable.path.join("pyproject.toml")) else { + let Ok(contents) = fs_err::read_to_string(path.join("pyproject.toml")) else { return true; }; let Ok(pyproject_toml) = toml::from_str::(&contents) else { diff --git a/crates/uv-installer/src/site_packages.rs b/crates/uv-installer/src/site_packages.rs index 0e910e9dd..d33edfbcd 100644 --- a/crates/uv-installer/src/site_packages.rs +++ b/crates/uv-installer/src/site_packages.rs @@ -322,7 +322,7 @@ impl SitePackages { } // Does the editable have dynamic metadata? - if is_dynamic(requirement) { + if is_dynamic(&requirement.path) { return Ok(SatisfiesResult::Unsatisfied(requirement.to_string())); } diff --git a/crates/uv/src/commands/pip/install.rs b/crates/uv/src/commands/pip/install.rs index d660ee204..3e4555e06 100644 --- a/crates/uv/src/commands/pip/install.rs +++ b/crates/uv/src/commands/pip/install.rs @@ -342,7 +342,9 @@ pub(crate) async fn pip_install( // Build all editable distributions. The editables are shared between resolution and // installation, and should live for the duration of the command. let editables = ResolvedEditables::resolve( - editables, + editables + .into_iter() + .map(ResolvedEditables::from_requirement), &site_packages, &reinstall, &hasher, diff --git a/crates/uv/src/commands/pip/sync.rs b/crates/uv/src/commands/pip/sync.rs index ae99971ef..eb338b290 100644 --- a/crates/uv/src/commands/pip/sync.rs +++ b/crates/uv/src/commands/pip/sync.rs @@ -297,7 +297,9 @@ pub(crate) async fn pip_sync( // Resolve any editables. let editables = ResolvedEditables::resolve( - editables, + editables + .into_iter() + .map(ResolvedEditables::from_requirement), &site_packages, reinstall, &hasher, diff --git a/crates/uv/src/commands/project/lock.rs b/crates/uv/src/commands/project/lock.rs index 200df55b6..23b92b97d 100644 --- a/crates/uv/src/commands/project/lock.rs +++ b/crates/uv/src/commands/project/lock.rs @@ -108,7 +108,10 @@ pub(crate) async fn lock( // Build all editable distributions. The editables are shared between resolution and // installation, and should live for the duration of the command. let editables = ResolvedEditables::resolve( - spec.editables.clone(), + spec.editables + .iter() + .cloned() + .map(ResolvedEditables::from_requirement), &EmptyInstalledPackages, &reinstall, &hasher, diff --git a/crates/uv/src/commands/project/mod.rs b/crates/uv/src/commands/project/mod.rs index 8817a946e..c25f17933 100644 --- a/crates/uv/src/commands/project/mod.rs +++ b/crates/uv/src/commands/project/mod.rs @@ -574,7 +574,10 @@ pub(crate) async fn update_environment( // Build all editable distributions. The editables are shared between resolution and // installation, and should live for the duration of the command. let editables = ResolvedEditables::resolve( - spec.editables.clone(), + spec.editables + .iter() + .cloned() + .map(ResolvedEditables::from_requirement), &site_packages, &reinstall, &hasher, diff --git a/crates/uv/src/editables.rs b/crates/uv/src/editables.rs index f549abf55..c0dfd31fa 100644 --- a/crates/uv/src/editables.rs +++ b/crates/uv/src/editables.rs @@ -46,7 +46,7 @@ impl ResolvedEditables { /// Resolve the set of editables that need to be installed. #[allow(clippy::too_many_arguments)] pub(crate) async fn resolve( - editables: Vec, + editables: impl IntoIterator, installed_packages: &impl InstalledPackagesProvider, reinstall: &Reinstall, hasher: &HashStrategy, @@ -59,8 +59,8 @@ impl ResolvedEditables { printer: Printer, ) -> Result { // Partition the editables into those that are already installed, and those that must be built. - let mut installed = Vec::with_capacity(editables.len()); - let mut builds = Vec::with_capacity(editables.len()); + let mut installed = Vec::new(); + let mut builds = Vec::new(); for editable in editables { match reinstall { Reinstall::None => { @@ -107,20 +107,7 @@ impl ResolvedEditables { ) .with_reporter(DownloadReporter::from(printer).with_length(builds.len() as u64)); - let editables = LocalEditables::from_editables(builds.iter().map(|editable| { - let EditableRequirement { - url, - path, - extras, - marker: _, - origin: _, - } = editable; - LocalEditable { - url: url.clone(), - path: path.clone(), - extras: extras.clone(), - } - })); + let editables = LocalEditables::from_editables(builds.into_iter()); let temp_dir = tempfile::tempdir_in(cache.root())?; @@ -193,21 +180,27 @@ impl ResolvedEditables { }) .collect() } + + /// Convert an [`EditableRequirement`] into a [`LocalEditable`]. + pub(crate) fn from_requirement(editable: EditableRequirement) -> LocalEditable { + LocalEditable { + url: editable.url, + path: editable.path, + extras: editable.extras, + } + } } /// Returns the [`InstalledEditable`] if the installed distribution is up-to-date for the given /// requirement. -fn up_to_date( - editable: &EditableRequirement, - dist: &InstalledDist, -) -> Result> { +fn up_to_date(editable: &LocalEditable, dist: &InstalledDist) -> Result> { // If the editable isn't up-to-date, don't reuse it. if !ArchiveTimestamp::up_to_date_with(&editable.path, ArchiveTarget::Install(dist))? { return Ok(None); }; // If the editable is dynamic, don't reuse it. - if is_dynamic(editable) { + if is_dynamic(&editable.path) { return Ok(None); }; @@ -217,11 +210,7 @@ fn up_to_date( }; Ok(Some(InstalledEditable { - editable: LocalEditable { - url: editable.url.clone(), - path: editable.path.clone(), - extras: editable.extras.clone(), - }, + editable: editable.clone(), wheel: (*dist).clone(), metadata, }))