Add support for cargo version range
@ziadhany please add tests
@ziadhany please add tests I think this pull request needs some changes to make it fit with docs and I will start by adding some tests https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
gentle ping!
@ziadhany I chatted with @keshav-space and here is a suggestion on how to handle the star in versions... this is not tested but this should help you deal with such a thing:
def get_constraints_from_star_version(version):
"""
Return a list of VersionConstraint from a Cargo version with stars.
See https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#wildcard-requirements
for details. We support these constructions:
* := >=0.0.0
1.* := >=1.0.0, <2.0.0
1.2.* := >=1.2.0, <1.3.0
"""
if "*" not in version:
raise TypeError(f"Not a star version: {version}")
## CargoVersion SHOULD be a subclass of univers.versions.SemverVersion
if version == "*":
return [VersionConstraint(comparator="*", version_class=CargoVersion)]
if "*" in version and not version.endswith("*"):
raise TypeError(f"Unsupported star in the middle of a version: it should be a trailing star only: {version}")
segments_count = len(version.split("."))
lower_bound = CargoVersion(version.replace("*", "0"))
upper_bound = None
if segments_count == 2:
# bump minor
upper_bound = lower_bound.next_major()
elif segments_count == 3:
# bump patch
upper_bound = lower_bound.next_minor()
else:
raise TypeError(f"Invalid version: not a semver version: {version}")
return [
VersionConstraint(comparator=">=", version=lower_bound),
VersionConstraint(comparator="<", version=upper_bound)
]
This should get you things more or less this way:
>>> get_constraints_from_star_version("1.2.3")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 12, in get_constraints_from_star_version
TypeError: Not a star version: 1.2.3
>>> get_constraints_from_star_version("1.2.*")
[VersionConstraint(comparator='>=', version=CargoVersion(string='1.2.0')), VersionConstraint(comparator='<', version=SemverVersion(string='1.3.0'))]
>>> get_constraints_from_star_version("1.*")
[VersionConstraint(comparator='>=', version=CargoVersion(string='1.0')), VersionConstraint(comparator='<', version=SemverVersion(string='2.0.0'))]
@pombredanne I thought of the same implementation but what if we have two stars like this https://github.com/dtolnay/semver/blob/master/tests/test_version_req.rs#L371
#[test]
fn test_cargo3202() {
let ref r = req("0.*.*");
assert_to_string(r, "0.*");
assert_match_all(r, &["0.5.0"]);
let ref r = req("0.0.*");
assert_to_string(r, "0.0.*");
}
@pombredanne I thought of the same implementation but what if we have two stars like this https://github.com/dtolnay/semver/blob/master/tests/test_version_req.rs#L371
#[test] fn test_cargo3202() { let ref r = req("0.*.*"); assert_to_string(r, "0.*"); assert_match_all(r, &["0.5.0"]); let ref r = req("0.0.*"); assert_to_string(r, "0.0.*"); }
Use this:
while version.endswith(".*.*"):
version = version.replace(".*.*", ".*")
>>> version = "1.*.*"
>>> while version.endswith(".*.*"):
... version = version.replace(".*.*", ".*")
...
>>> version
'1.*'
@ziadhany gentle ping
@ziadhany, all CIs are passing now.
I stumbled on this which is vaguely related https://github.com/alilleybrinker/semver-explain