-
Notifications
You must be signed in to change notification settings - Fork 36
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
Support for more complex version constraints #86
Comments
Hi @calebzulawski ! thanks for the feedback on this! I'd say that's exactly the same case that the issue with pre-release versions (see discussion and links in issue #80). In the case of pre-release, we want Currently, this is outside the limits of things possible with this crate. It is the major change we want to work on next, after releasing the 0.2.1 version, which will be a perf-improvement only change. As mentioned in #80, a prototype solution for this was started in the range-trait branch and consists in removing the To be honest I've my hands full for at least 2 months before being able to start again work on this. But this is definitely the most requested features (3 persons now) so if any want to have a go at it, it will make a lot of people happy ^^. |
Technically No. But there are some workarounds and some plans for 0.3 that may work. We do want to make this kind of use case possible! And your feedback will be invaluable in getting there! That being said, I am not familiar with the subtleties of PEP 440, so sorry if the links are not quite relevant. If you have a description or a targeted link I'd love to read it. ( also cc @MrGreenTea who has done some python experimentation. ) One form of augmented constraints that has bean discussed is "features", where the constraint tells the package to have some extra functionality and the dependencies required to support it. This can be supported now by adding a synthetic package And in the 30 min it has taken me to wright this up @mpizenberg wright up the other thins I was going to say, so I will stop here! |
Thanks for all of the information! It seems like the range trait is probably the answer to this problem. It would also be nice if that allows more tailored error messages. I may take a look at implementing this if I get a chance--is there anything specific that's incomplete about the range-trait branch? I'll have to take a look at that advanced dependency providers link, virtual packages seem to be used by almost every package manager so I'm sure I will run into that, too. |
@calebzulawski A friend and I started experimenting with a PEP440 implementation for Sadly real life got in the way and I haven't been able to return to it since then, but perhaps it's interesting to you or you might even want to collaborate :) |
What is done: is that it works, and tests pass. What is not done: It is not bean rebased to use all the new perf-improvements. It does not have all needed polish, like finding the best names for the methods, or like requiring But the BIG thing it needs is an example of using it for a real world use case that can not be done with the existing system! Someone saying "I can demonstrate that that will get me unstuck" would be invaluable! cc https://rust-lang.zulipchat.com/#narrow/stream/260232-t-cargo.2FPubGrub/topic/A.20Range.20trate |
@MrGreenTea I'll take a look at that! I plan on at least publishing my PEP 440 parser to crates.io soon, so feel free to work with that once it's up. I'm planning on implementing a @Eh2406 I'll see what I can do about getting it ready for release. Seems like once it's all cleaned up it should be easy enough to proof-of-concept PEP 440 as an example! |
I just rebased and force pushed the branch. So at least the perf improvements should be available. :-P |
Hello @calebzulawski ! Did you push your version in the end? I'm attempting to add some form of prelease handling so that I can use this library with the Hex package manager for Gleam/Elixir/Erlang/etc but I've not managed to figure my way through the Range trait for this. |
Unfortunately I've been pretty busy and haven't gotten a chance--I'm hoping to be able to start this soon |
Thank you |
I've got some time now so taking a look at this |
@mpizenberg @Eh2406 I'm taking a look at the |
They all act like sets in a mathematical sense. But, they don't have user facing syntax for all the things we need. (For example Cargos syntax has no way to say "pre releases without stable releases") So the I can try to make a |
Hmm--let me try to clarify.
So for example, The constraint trait would only have a single function |
A simple way to implement this would be something like: enum Term<C> {
Constraint(C),
Negate(Box<Term>),
Union(Box<Term>, Box<Term>),
Intersection(Box<Term>, Box<Term>),
} |
I would love to see something like that work! The part I have always gotten stuck on with designs like that is |
Ah I understand the problem now. I think the problem I see is that for some constraints, determining if an intersection is disjoint is either extremely difficult or maybe intractable. This is particularly true when considering things like release candidates which can have relatively complicated logic. With simple number ranges it's easy but with more arbitrary versions I can see it being a problem. If it's an optimization maybe it can be handled that way in the trait? trait Constraint {
type Version;
fn satisfies(&self, version: &Self::Version) -> bool;
fn disjoint(&self, other: &Self) -> Option<bool> { None };
} An implementer can attempt to determine if two constraints are disjoint, but if not it will fall back to the |
The algorithm as implemented assumes that all the set operations are exact and reasonably fast, and that every operation returns a canonical representation so Eq can be used for all the checks. Furthermore the |
I've been thinking about this a little more and I'm not so sure it's worth supporting completely arbitrary versioning with how much work it seems to require. For some reason I think I had overcomplicated how hard it would be to implement a "punctured" range--a range that has some versions missing (such as release candidates). I think I see a path forward for implementing PEP 440 that way, and semver should be even easier. This of course would make it difficult to implement completely arbitrary versioning, but I'm pretty sure most standards are based on ranges in some form or another... |
@calebzulawski Fun fact, for my first implementation of PubGrub (in elm), I initially had something like that. But it was so problematic to handle correctly all the cases that it was the source of many bugs and the reason I switched to a normalized list of non-intersecting semi-open segments (cf this commit mpizenberg/elm-pubgrub@6da0c12) |
Anyway, we have finished twiddling with perf optimizations and are about to release 0.2.1. So both @Eh2406 and me will be able to focus our attention on the limits of the current API. I have been reading PEP 440 today and oh boy I feel sorry for you ^^. That's kind of a nightmare of trying to be compatible with all pre-existing practices. Imagining that you can face a version like All that being said, I have few questions after reading this spec.
|
I have a proof of concept implementation of support for the Semver crate, with one of the draft branches for 0.3. It includes the fact that |
@calebzulawski @MrGreenTea oh huh, I went and implemented a python resolver using this crate too, before seeing this thread :-) (Mine's at https://github.com/njsmith/posy/blob/main/src/resolve.rs if you're curious. The resolver code is pretty drafty but the supporting infrastructure is pretty fleshed out. Happy to collaborate if it makes sense!) In particular, as far as this thread goes, this code might be useful as a concrete example of compiling PEP 440's complex version comparison operators down into ranges: https://github.com/njsmith/posy/blob/af665987b61348940f2e44212c23341ce2f6340e/src/vocab/specifier.rs#L76 And I'm technically not quite supporting prereleases according to the PEP, but I think I'm just going to argue that the PEP's semantics don't really make sense for a multi-package resolver -- prereleases are best handled using global context/configuration, not individual specifiers: https://github.com/njsmith/posy#interpretationsdeviations-from-standards Also, regarding what PEP 440 calls "local versions":
I think this is actually a misreading of the PEP. (I also misread it this way for a long time!) You're not allowed to write |
Hey, we just released a new section called "Advanced usage and limitations" in pubgrub's guide. I hope this can be of help to some of you. |
Re: this bit of the new section: https://pubgrub-rs-guide.netlify.app/limitations/continuous_versions.html Would it make sense to define a It might also allow more efficient implementations than currently, e.g. a custom It might also be useful for the "multi-dimensional ranges" in the pre-release section, or for preserving more "natural" high-level representations of version ranges like |
Yeah it totally would. Actually, for the approach discussed in "multi-dimensional ranges", users would implement their own membership and intersection primitives. I am personally wary of letting users implement it on their own because of the so many pitfalls/bugs that can happen doing so (cause we fell in them). And in those cases, the failures that could happen resulting of a tiny bug in version sets implementation, would be similar to the one you experienced with the But the right move is probably keeping the freedom for users, while strongly steering them to one or few implementations of those traits already provided by the crate. It's a very interesting design space, but we are making slow progress since mostly doing that on our free time, and since evaluating those design decisions takes a bit of time. |
Hi all, so support for more flexible version traits have landed in the |
Perhaps this is (understandably) outside the scope of this crate, but I figured I'd ask.
I'm trying to implement a solver for PEP 440, which unfortunately does not quite boil down to simple ranges. The versions do have a total order, but the constraints have some extra requirements. For example,
>1
matches1.1
,2.0
, etc, but it does not match2.0+foo
despite that version being "greater". Is there any way to embed some additional arbitrary constraints into the version selection process?Thanks for any help!
The text was updated successfully, but these errors were encountered: