-
Notifications
You must be signed in to change notification settings - Fork 130
Use a correct EVR sort #4136
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
Use a correct EVR sort #4136
Conversation
53934f7 to
5b6a3be
Compare
pulp_rpm/app/tasks/prune.py
Outdated
| curr_vers.get_content(Package.objects) | ||
| .order_by( | ||
| "name", "epoch", "version", "release", "arch" | ||
| ) # why sort by all of these values? lexicographical sort is not "accurate" |
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 have been doing experiments with the "CREATE COLLATION" feature in postgresql.
I think it could be tailored to define a proper "lexicographical" order for these version components.
related pr: pulp/pulp_deb#1335
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.
RPM versioning has a special ~ and ^ character behavior - is collation flexible enough to handle that?
see:
https://slashterix.wordpress.com/2016/08/06/rpm-version-comparison/
https://github.com/pulp/pulp_rpm/blob/main/pulp_rpm/app/rpm_version.py
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 have been doing experiments with the "CREATE COLLATION" feature in postgresql. I think it could be tailored to define a proper "lexicographical" order for these version components.
related pr: pulp/pulp_deb#1335
Isn't that also dependent on pgres-16?
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 is pg 16 and for the special ~ handling (sorting even before the end of the segment) i needed to trick a little.
I'd love to do a little less of that. But i found no way to either add a custom normalize function to the collation or a way to provide a search_key function to a text field.
2486a36 to
cb6241a
Compare
9c5de07 to
ef509ef
Compare
ef509ef to
2b656f4
Compare
8899d12 to
561b378
Compare
561b378 to
6056f17
Compare
75788be to
5f13c10
Compare
| return "pulp_evr_t" | ||
|
|
||
|
|
||
| class PackageManager(ContentManager): |
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.
The rationale for getting rid of this is that different implementations of with_age() are not stable when applying additional filters to the queryset. You want the annotation to be the very last thing you do post-filtering to guarantee correctness.
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.
Also I recall running into issues because we didn't inherit from the Pulpcore-overridden content manager properly. Easier to avoid conflicts this way.
|
|
||
| when_clauses = [When(pk=pk, then=age) for pk, age in age_mapping.items()] | ||
|
|
||
| return qs.annotate(age=Case(*when_clauses, output_field=IntegerField())) |
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.
As mentioned previously I don't really love this, but it should be "fine" and hopefully it's just a temporary implementation
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.
Remind us again why this is a temporary implementation?
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.
Because ideally we have a fix in the database layer that can be shared with Katello. But that's not backportable.
| self.assertEqual(packages[2].release, "1.el8") # age=3 | ||
| self.assertEqual(packages[2].age, 3) | ||
|
|
||
| @skip("The implementation of package age is broken w/r/t '^' and '~' characters") |
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.
This test passes now
| self.assertIn("4_0", remaining_versions) | ||
| self.assertIn("4+0", remaining_versions) | ||
|
|
||
| @skip("Non-ASCII character handling do not work correctly with current implementation") |
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.
This test passes now
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.
Pull Request Overview
This PR fixes a bug in RPM package version comparison by replacing PostgreSQL's built-in EVR (Epoch-Version-Release) sorting with a proper Python-based implementation using the RpmVersion class.
- Removes the PostgreSQL window function approach from
PackageManager.with_age() - Implements a new
annotate_with_age()function inshared_utils.pythat uses proper RPM version sorting - Updates all code locations to use the new annotation function instead of the manager method
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pulp_rpm/app/shared_utils.py | Adds new annotate_with_age() function with proper EVR sorting using RpmVersion |
| pulp_rpm/app/models/package.py | Removes the broken PackageManager.with_age() method and custom manager |
| pulp_rpm/tests/unit/test_package_age.py | Updates all test calls to use new annotation function and removes skip decorators |
| pulp_rpm/app/tasks/prune.py | Updates to use new annotation function |
| pulp_rpm/app/tasks/copy.py | Updates to use new annotation function |
| pulp_rpm/app/models/repository.py | Updates to use new annotation function |
| CHANGES/4124.bugfix | Adds changelog entry describing the bug fix |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
pulp_rpm/app/shared_utils.py
Outdated
| newest age=2, and so on. | ||
| A second partition by architecture is important because there can be packages with | ||
| the same name and verison numbers but they are not interchangeable because they have |
Copilot
AI
Oct 8, 2025
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.
Corrected spelling of 'verison' to 'version'.
| the same name and verison numbers but they are not interchangeable because they have | |
| the same name and version numbers but they are not interchangeable because they have |
ggainey
left a comment
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.
Looks like this should address the issue(s) - great work!
Backport to 3.26: 💔 cherry-picking failed — conflicts found❌ Failed to cleanly apply c7bbe48 on top of patchback/backports/3.26/c7bbe48ba247518fe0cd5e840ec2357811fe49bb/pr-4136 Backporting merged PR #4136 into main
🤖 @patchback |
Backport to 3.29: 💚 backport PR created✅ Backport PR branch: Backported as #4166 🤖 @patchback |
Backport to 3.27: 💚 backport PR created✅ Backport PR branch: Backported as #4167 🤖 @patchback |
Backport to 3.32: 💚 backport PR created✅ Backport PR branch: Backported as #4168 🤖 @patchback |
No description provided.