package: move to compare version instead of timestamp#977
package: move to compare version instead of timestamp#977cgwalters merged 1 commit intocoreos:mainfrom
version instead of timestamp#977Conversation
There was a problem hiding this comment.
Code Review
The code changes introduce the use of the rpm::Evr crate to parse and compare package versions, replacing the previous timestamp-based approach. A critical issue was identified in the package version string parsing logic that could lead to incorrect behavior with certain package name formats. A suggestion to improve code clarity was also provided.
bc9afdc to
8d3aec1
Compare
8d3aec1 to
da4de80
Compare
|
Ready for review now, thank you! |
bdbd4b3 to
a7bdb10
Compare
version instead of timestampversion instead of timestamp
|
Fix CI error and add related unit test if there is new package. |
a7bdb10 to
2690df4
Compare
|
Is there a reason why the |
I think the problem is we need to ignore epoch in our comparison, e.g. |
|
Also tried with "grub2-efi-x64-1:2.12-28.fc42.x86_64" -- epoch should be "1" "shim-x64-15.8-3.x86_64" -- version should be 15.8, release should be 3 "grub2-2.12-28.fc42" -- arch should be "" "shim-15.8-3" -- the result is correct and that we want |
8f99338 to
4a9513a
Compare
|
Update the logic to parse str using |
I'm wondering if this is an issue with how the RPM versions is defined or a bug in the library as epoch/versions should ever start with a number, but I'm not sure. That's likely comes from the parsing in the library: https://docs.rs/rpm/latest/src/rpm/version.rs.html#96 I don't see "must start with a number" constraint in https://rpm.org/docs/4.20.x/manual/spec.html#preamble There apparently isn't: semver/semver#145 (comment) But we can probably push in that direction. Would be good to file an issue in https://github.com/rpm-rs/rpm/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen Conclusion: Manually stripping the name first and then using the evra parser should work best, which looks like what you did. |
Ideally we should not ignore the epoch. It looks like the issue is that the epoch is not used in the path where the grub binaries are stored: https://src.fedoraproject.org/rpms/grub2/pull-request/170#_1__7
|
|
@lsandov1 we should probably change the installation path to include the epoch as well as the version and release. |
SGTM, create issue rpm-rs/rpm#275 |
WDYT about |
4a9513a to
6c79a89
Compare
Use `rpm::Evr` crate to parse and compare `version` when checking for update. Inspired by Timothee's pointer: coreos#938 (comment) Fixes: coreos#933 Additional info: Use rpm `0.16.1` instead of `0.17` as 1.84 does not support feature `edition2024` that is requried by 0.17: ``` error: failed to parse manifest at `/root/.cargo/registry/src/ index.crates.io-6f17d22bba15001f/rpm-0.17.0/Cargo.toml` Caused by: feature `edition2024` is required The package requires the Cargo feature called `edition2024`, but that feature is not stabilized in this version of Cargo (1.84.1 (66221abde 2024-11-19)). ```
6c79a89 to
fdb91fe
Compare
cgwalters
left a comment
There was a problem hiding this comment.
I'm OK with this as is generally.
| ); | ||
| fn parse_evr_map(input: &str) -> BTreeMap<String, Evr> { | ||
| input | ||
| .split(',') |
There was a problem hiding this comment.
It does seem like we can reliably split on this since AFAICS , is illegal in all of RPM, the uapi versions, dpkg, arch etc.
That said if we are moving to make the versions actually parsed, it would probably make sense to also switch to a proper array instead of a single string.
For compatibility though we'd need to do both for a while at least, i.e. have both version (string) and versions (array) in the model/JSON.
There was a problem hiding this comment.
For compatibility though we'd need to do both for a while at least, i.e. have both
version(string) andversions(array) in the model/JSON.
What do you think about like this? Then we do not need to parse the str.
{
"version": "pkg1-1.0,pkg2-2.0", // old single string
"versions": [ // new proper array
{"name": "pkg1", "evr": "1.0"},
{"name": "pkg2", "evr": "2.0"}
]
}
There was a problem hiding this comment.
How about replacing evr with rpm-evr to make explicit what it is? On other operating systems the version might be different.
BTW recently in bootc-dev/bootc@17c03f7 I added the uapi_versions crate to bootc. It would make sense to me to use it here too optionally for systems not using rpm.
But anyways let's start with introducing the parallel versions struct with rpm-evr or so.
| } | ||
|
|
||
| // assume it is like "grub2-efi-x64-1:2.12-28.fc42.x86_64,shim-x64-15.8-3.x86_64" | ||
| let nevra = rpm::Nevra::parse(pkg); |
There was a problem hiding this comment.
Per my earlier comment I think this is OK as is but I'd like to not add new hardcoded RPM dependencies. We can just make this a build-time configuration option in the future.
There was a problem hiding this comment.
Do you mean that we only import rpm if using cargo build --features rpm, else using cargo build without rpm, but we also use cmp() to compare rpm::Evr (see https://docs.rs/rpm/latest/rpm/struct.Evr.html#method.cmp), so we still need rpm, is this right?
There was a problem hiding this comment.
I think it's OK to have an rpm feature and use it.
But we could have a generic version that uses https://docs.rs/uapi-version/latest/uapi_version/ to compare versions and require that package systems map to a compatible version scheme (if it's not compatible).
| for (_, ord) in &diffs { | ||
| match ord { | ||
| Ordering::Less => { | ||
| has_less = true; |
There was a problem hiding this comment.
This can just be return Ordering::less right? No need for the bool.
| // If any package is Ordering::Less, return Ordering::Less, means upgradable, | ||
| // Else if any package is Ordering::Greater, return Ordering::Greater, | ||
| // Else (all equal), return Ordering::Equal. | ||
| pub(crate) fn compare_package_versions(a: &str, b: &str) -> Ordering { |
There was a problem hiding this comment.
I think this is OK but it'd be more idiomatic to create a struct Package that has impl Ord.
And also I think per above we should split on the , outside this function, i.e. we're comparing two slices [Package] - and if everything compares equal then the longer one wins.
There was a problem hiding this comment.
SGTM, thank you for the pointer, update in #983
Inspired by Colin's coreos#977 (comment) Copy the comment: ``` Create a struct Package that has impl Ord. Compare two slices `[Package]` - and if everything compares equal then the longer one wins. ```
This continuous from coreos#977, inspired by Colin's coreos#977 (comment).
This continuous from coreos#977, inspired by Colin's coreos#977 (comment).
This continuous from coreos#977, inspired by Colin's coreos#977 (comment).
This continuous from coreos#977, inspired by Colin's coreos#977 (comment).
Inspired by Colin's comment coreos#977 (comment) We need `versions` to save struct like: ``` "versions": [ {"name": "pkg1", "rpm-evr": "1.0"}, {"name": "pkg2", "rpm-evr": "2.0"} ] ``` Then we read and compare versions, do not need to parse the version in str format. Co-worked by walters@verbum.org
Inspired by Colin's comment coreos#977 (comment) We need `versions` to save struct like: ``` "versions": [ {"name": "pkg1", "rpm-evr": "1.0"}, {"name": "pkg2", "rpm-evr": "2.0"} ] ``` Then we read and compare versions, do not need to parse the version in str format. Co-worked by walters@verbum.org
Inspired by Colin's comment coreos#977 (comment) We need `versions` to save struct like: ``` "versions": [ {"name": "pkg1", "rpm-evr": "1.0"}, {"name": "pkg2", "rpm-evr": "2.0"} ] ``` Then we read and compare versions, do not need to parse the version in str format. Co-worked by walters@verbum.org
Inspired by Colin's comment coreos#977 (comment) We need `versions` to save struct like: ``` "versions": [ {"name": "pkg1", "rpm-evr": "1.0"}, {"name": "pkg2", "rpm-evr": "2.0"} ] ``` Then we read and compare versions, do not need to parse the version in str format. Co-worked by walters@verbum.org
Inspired by Colin's comment coreos#977 (comment) We need `versions` to save struct like: ``` "versions": [ {"name": "pkg1", "rpm-evr": "1.0"}, {"name": "pkg2", "rpm-evr": "2.0"} ] ``` Then we read and compare versions, do not need to parse the version in str format. Co-worked by walters@verbum.org
Inspired by Colin's comment coreos#977 (comment) We need `versions` to save struct like: ``` "versions": [ {"name": "pkg1", "rpm-evr": "1.0"}, {"name": "pkg2", "rpm-evr": "2.0"} ] ``` Then we read and compare versions, do not need to parse the version in str format. Co-worked by walters@verbum.org
Inspired by Colin's comment coreos#977 (comment) We need `versions` to save struct like: ``` "versions": [ {"name": "pkg1", "rpm-evr": "1.0"}, {"name": "pkg2", "rpm-evr": "2.0"} ] ``` Then we read and compare versions, do not need to parse the version in str format. Co-worked by walters@verbum.org
This continuous from coreos#977, inspired by Colin's coreos#977 (comment).
This continuous from coreos#977, inspired by Colin's coreos#977 (comment).
Use
rpm::Evrcrate to parse and compareversionwhen checking for update.Inspired by Timothee's pointer:
#938 (comment)
Fixes: #933
Additional info:
Use rpm
0.16instead of0.17as 1.84 does not supportfeature
edition2024that is requried by 0.17: