-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add basic "install from lock file" operation #3340
Conversation
crates/uv-resolver/src/lock.rs
Outdated
/// Returns the distribution with the given name. If there are multiple | ||
/// matching distributions, then an error is returned. If there are no | ||
/// matching distributions, then `Ok(None)` is returned. | ||
fn find_by_name(&self, name: &str) -> Result<Option<&Distribution>, String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this use LockError
rather than String
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's only an internal helper for right now, and its only use asserts that is succeeds. I don't know that this belongs in LockError
, and right now, it's only used to find the "root" package. And I expect all of that to change.
@@ -1308,6 +1308,9 @@ pub(crate) struct PipInstallArgs { | |||
/// print the resulting plan. | |||
#[arg(long)] | |||
pub(crate) dry_run: bool, | |||
|
|||
#[arg(long, hide = true)] | |||
pub(crate) unstable_uv_lock_file: Option<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can we call this unstable_lock_file
(omitting uv
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It matches the name I added in: https://github.com/astral-sh/uv/pull/3314/files#diff-ae55eef503096c43098e973865bd5ed612871dcd1d3d335631a8027deb3828d3R605
This flag is hidden, undocumented and intended to be temporary. Its only purpose is to expose "install from uv.lock
" on the CLI so that we can interact with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mostly just have a strong dislike for using uv
in things (outside of crate names, since it's roughly a namespace), like structs or arguments. But not a big deal if it's temporary.
eprint!("{report:?}"); | ||
return Ok(ExitStatus::Failure); | ||
let resolution = if let Some(ref root) = uv_lock { | ||
let encoded = fs::tokio::read_to_string("uv.lock").await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this assumes that it's in the current working directory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. It's the simplest thing to do I think. I expect this code to be eventually deleted. (Like, I don't expect uv pip install
should ever read a uv.lock
file.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok agreed.
root_name: &str, | ||
) -> Resolution { | ||
let root = self | ||
.find_by_name(root_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could / should this just be a special package named root
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that privileging the notion of "root" in the lock file makes sense, particularly given that we want to have workspace support. Cargo went in the same direction:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok agreed. This makes more sense now that I see that this isn't ever intended to be part of pip install
, but rather, something that stems from a known project root.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little confused about the root concept, and why we need to pass anyio
as an argument to --unstable-lock
. What's the eventual vision there?
Separately, what are the expected semantics for |
Hmm, so I added this as a TODO comment in the source: // TODO: In the future, we should derive the root distribution
// from the pyproject.toml, but I don't think the infrastructure
// for that is in place yet. For now, we ask the caller to specify
// the root package name explicitly, and we assume here that it is
// correct. The basic idea here is that the lock file should contain an entry for each package in the current
I'm not sure there are any expected semantics for |
This commit adds a routine for converting a `Lock` to a `Resolution`, where a `Resolution` is a map of package names pinned to a specific version. I'm not sure that a `Resolution` is ultimately what we want here (we might need more stuff), but this was the quickest route I could find to plug a `Lock` into the existing `pip install` infrastructure. This commit also does a little refactoring of the `Lock` types. The main thing is to permit extra state on some of the types (like a `by_id` map on `Lock` for quick lookups of distributions) that aren't included in the serialization format of a `Lock`. We achieve this by defining separate `Wire` types that are automatically converted to-and-from via `serde`. Note like with the lock file format types themselves, we leave a few `todo!()` expressions around. The main idea is to get something minimally working without spending too much effort here. (A fair bit of refactoring will be required to generate a lock file, and it's not clear how much this code will wind up needing to change anyway.) In particular, we only handle the case of installing wheels from a registry.
Like the similar flag on `uv pip compile`, this is meant to be a temporary toggle to expose "install from lock file" on the CLI. We expect to remove this eventually. The larger diff for `pip_install.rs` is mostly just due to moving some pieces together that we specifically don't want to run (like resolution) when installing from a lock file.
e9c69d0
to
498c709
Compare
This PR principally adds a routine for converting a
Lock
to aResolution
, where aResolution
is a map of package names pinned toa specific version.
I'm not sure that a
Resolution
is ultimately what we want here (wemight need more stuff), but this was the quickest route I could find to
plug a
Lock
into our existinguv pip install
infrastructure.This commit also does a little refactoring of the
Lock
types. Themain thing is to permit extra state on some of the types (like a
by_id
map onLock
for quick lookups of distributions) that aren'tincluded in the serialization format of a
Lock
. We achieve thisby defining separate
Wire
types that are automatically convertedto-and-from via
serde
.Note that like with the lock file format types themselves, we leave a
few
todo!()
expressions around. The main idea is to get somethingminimally working without spending too much effort here. (A fair bit
of refactoring will be required to generate a lock file, and it's
not clear how much this code will wind up needing to change anyway.)
In particular, we only handle the case of installing wheels from a
registry.
A demonstration of the full flow:
In order to install from a lock file, we start from the root and do a
breadth first traversal over its dependencies. We aren't yet filtering
on marker expressions (since they aren't in the lock file yet), but we
should be able to add that in the future. In so doing, the traversal
should select only the subset of distributions relevant for the current
platform.