Skip to content

Commit

Permalink
Track editable requirements in lockfile (#3725)
Browse files Browse the repository at this point in the history
## Summary

This PR adds editables using a new source type (`editable+...`), and
then extracts the editables from the lockfile in `uv sync`.

Closes #3695.
  • Loading branch information
charliermarsh authored May 22, 2024
1 parent 472ab14 commit e398444
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 7 deletions.
35 changes: 34 additions & 1 deletion crates/distribution-types/src/resolution.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use rustc_hash::FxHashMap;

use pep508_rs::VerbatimUrl;
use uv_normalize::PackageName;

use crate::{BuiltDist, Dist, Name, Requirement, RequirementSource, ResolvedDist, SourceDist};
use crate::{
BuiltDist, DirectorySourceDist, Dist, InstalledDirectUrlDist, InstalledDist, LocalEditable,
Name, Requirement, RequirementSource, ResolvedDist, SourceDist,
};

/// A set of packages pinned at specific versions.
#[derive(Debug, Default, Clone)]
Expand Down Expand Up @@ -68,6 +72,35 @@ impl Resolution {
requirements.sort_unstable_by(|a, b| a.name.cmp(&b.name));
requirements
}

/// Return an iterator over the [`LocalEditable`] entities in this resolution.
pub fn editables(&self) -> impl Iterator<Item = LocalEditable> + '_ {
self.0.values().filter_map(|dist| match dist {
ResolvedDist::Installable(Dist::Source(SourceDist::Directory(
DirectorySourceDist {
path,
url,
editable: true,
..
},
))) => Some(LocalEditable {
url: url.clone(),
path: path.clone(),
extras: vec![],
}),
ResolvedDist::Installed(InstalledDist::Url(InstalledDirectUrlDist {
path,
url,
editable: true,
..
})) => Some(LocalEditable {
url: VerbatimUrl::from_url(url.clone()),
path: path.clone(),
extras: vec![],
}),
_ => None,
})
}
}

impl From<&ResolvedDist> for Requirement {
Expand Down
3 changes: 2 additions & 1 deletion crates/uv-configuration/src/package_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use pep508_rs::PackageName;
use rustc_hash::FxHashSet;

/// Whether to reinstall packages.
#[derive(Debug, Clone)]
#[derive(Debug, Default, Clone)]
pub enum Reinstall {
/// Don't reinstall any packages; respect the existing installation.
#[default]
None,

/// Reinstall all packages in the plan.
Expand Down
27 changes: 25 additions & 2 deletions crates/uv-resolver/src/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ impl Distribution {
SourceKind::Directory => {
unreachable!("Wheels cannot come from directory sources")
}
SourceKind::Editable => {
unreachable!("Wheels cannot come from editable sources")
}
};
}

Expand All @@ -301,6 +304,16 @@ impl Distribution {
let source_dist = distribution_types::SourceDist::Directory(dir_dist);
Dist::Source(source_dist)
}
SourceKind::Editable => {
let dir_dist = DirectorySourceDist {
name: self.id.name.clone(),
url: VerbatimUrl::from_url(self.id.source.url.clone()),
path: self.id.source.url.to_file_path().unwrap(),
editable: true,
};
let source_dist = distribution_types::SourceDist::Directory(dir_dist);
Dist::Source(source_dist)
}
SourceKind::Git(git) => {
// Reconstruct the `GitUrl` from the `GitSource`.
let git_url = uv_git::GitUrl::new(
Expand Down Expand Up @@ -513,7 +526,11 @@ impl Source {

fn from_directory_source_dist(directory_dist: &DirectorySourceDist) -> Source {
Source {
kind: SourceKind::Directory,
kind: if directory_dist.editable {
SourceKind::Editable
} else {
SourceKind::Directory
},
url: directory_dist.url.to_url(),
}
}
Expand Down Expand Up @@ -583,6 +600,10 @@ impl std::str::FromStr for Source {
kind: SourceKind::Directory,
url,
}),
"editable" => Ok(Source {
kind: SourceKind::Editable,
url,
}),
name => Err(SourceParseError::unrecognized_source_name(s, name)),
}
}
Expand Down Expand Up @@ -624,6 +645,7 @@ pub(crate) enum SourceKind {
Direct(DirectSource),
Path,
Directory,
Editable,
}

impl SourceKind {
Expand All @@ -634,6 +656,7 @@ impl SourceKind {
SourceKind::Direct(_) => "direct",
SourceKind::Path => "path",
SourceKind::Directory => "directory",
SourceKind::Editable => "editable",
}
}

Expand All @@ -644,7 +667,7 @@ impl SourceKind {
fn requires_hash(&self) -> bool {
match *self {
SourceKind::Registry | SourceKind::Direct(_) | SourceKind::Path => true,
SourceKind::Git(_) | SourceKind::Directory => false,
SourceKind::Git(_) | SourceKind::Directory | SourceKind::Editable => false,
}
}
}
Expand Down
22 changes: 19 additions & 3 deletions crates/uv/src/commands/project/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use install_wheel_rs::linker::LinkMode;
use uv_cache::Cache;
use uv_client::RegistryClientBuilder;
use uv_configuration::{
Concurrency, ConfigSettings, NoBinary, NoBuild, PreviewMode, SetupPyStrategy,
Concurrency, ConfigSettings, NoBinary, NoBuild, PreviewMode, Reinstall, SetupPyStrategy,
};
use uv_dispatch::BuildDispatch;
use uv_installer::SitePackages;
Expand Down Expand Up @@ -65,6 +65,7 @@ pub(crate) async fn sync(
let no_build = NoBuild::default();
let setup_py = SetupPyStrategy::default();
let concurrency = Concurrency::default();
let reinstall = Reinstall::default();

// Create a build dispatch.
let build_dispatch = BuildDispatch::new(
Expand All @@ -84,8 +85,23 @@ pub(crate) async fn sync(
concurrency,
);

// TODO(konsti): Read editables from lockfile.
let editables = ResolvedEditables::default();
let site_packages = SitePackages::from_executable(&venv)?;

// Build any editables.
let editables = ResolvedEditables::resolve(
resolution.editables(),
&site_packages,
&reinstall,
&hasher,
venv.interpreter(),
tags,
cache,
&client,
&build_dispatch,
concurrency,
printer,
)
.await?;

let site_packages = SitePackages::from_executable(&venv)?;

Expand Down

0 comments on commit e398444

Please sign in to comment.