Add a page for RPM Python API#55
Add a page for RPM Python API#55FrostyX wants to merge 2 commits intorpm-software-management:masterfrom
Conversation
|
I couldn't figure out how to build the website locally so I am not sure if the render will look pretty. But the markdown is IMHO valid. |
10456db to
bf5da15
Compare
|
Having a separate page of our own for Python and linking to the examples is fine, but showing output of those examples there makes no sense - somebody looking for rpm python API docs isn't interested in example program output but actual API documentation, and its examples. |
|
Thank you for the review @pmatilai,
I agree, that's why my original idea was to put those examples directly into the documentation website. But I only partially agree with the "not being interested in the example program output" ... If I am completely new, I want to know what the API can do and seeing what kinds of information can be printed by the API and how it looks like before diving into reading any code is definitely helpful. Almost all my usages of the RPM Python API went the same way.
Easily finding in the documentation that there is an example Python script, which prints the same information as
But the examples aside, I talked with @xsuchy and we agreed that those web archive links used to be useful back in the day when they were up-to-date. What if took them, fixed any outdated information and put hem into the |
|
Sample output is meaningful when it's next to the actual code, but it doesn't work when linking to some far-away thing. The problem here starts right at the bottom: API documentation needs to be where the code is, otherwise it'll fall out of sync. That's one of the reasons I prefer examples in the codebase itself too. I think what you're making here is more like a tutorial, which is a little different again. What the Python API really needs is
I'm certainly not expecting you to do all that, just thinking out loud as to what sort of structure we'd want/need here. |
a68348d to
80e84f9
Compare
|
I converted the whole "Chapter 16. Programming RPM with Python" from this archive Can you please let me know how to build the rpm.org page locally? I want to make sure the markdown renders as expected. |
|
OK, this is only mentioned in the main RPM repository: https://github.com/rpm-software-management/rpm/tree/master/docs https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/testing-your-github-pages-site-locally-with-jekyll explains how to do that. On Fedora I use |
|
OK; added a README file for this repo. |
|
@ffesti thank you very much. I did not realize that this is a jekyll project. I successfully built it through |
|
Well, it is and it isn't. It's a GitHub pages project. GH pages uses something not completely unlike Jekyll - maybe. |
This is almost unchanged text from the "Programming RPM with Python from Fedora RPM Guide" archive. I only did some formatting changes such as displaying some symbols as code.
At the time of this update, we have F41, Python 3.13, and RPM 4.20
7196b0b to
28c0195
Compare
|
I did my best to modernize the original "Chapter 16. Programming RPM with Python" documentation from It's not perfect but IMHO it is good enough. There are two FIXME entries that I would like to fix before merging but I couldn't figure out how it should be done. Can you please take a look? |
|
|
||
| ## Dependency Comparisons | ||
|
|
||
| FIXME code examples in this chapter are outdated |
There was a problem hiding this comment.
The code uses file_h.dsOfHeader(), I don't know what should be done instead. I know a syntax like rpm.ds(h, rpm.RPMTAG_PROVIDENAME) but it takes an argument, the original example doesn't. I was thinking of rpm.ds(h, rpm.RPMTAG_EVR) but then .EVR() on it returns nothing. So I don't know.
There was a problem hiding this comment.
dsOfHeader() is equivalent to rpm.ds(h, rpm.RPMTAG_NEVR)
And yeah, it's all pretty arbitrary.
| # FIXME | ||
| # if resolved: | ||
| # # ts.addIntall(h, h, 'i') | ||
| # return -1 |
There was a problem hiding this comment.
The original example used this undefined resolved variable. I have no clue how it should be set so that the example makes sense.
There was a problem hiding this comment.
Just delete the example. I don't think anythink has used this interface in 15 years or longer, whether it functions at all is an unknown.
| # FIXME | ||
| # if resolved: | ||
| # # ts.addIntall(h, h, 'i') | ||
| # return -1 |
There was a problem hiding this comment.
This is the same undefined resolved variable but in a full script example
There was a problem hiding this comment.
Just drop, it refers to a long, long dead thing.
|
bump |
|
Uff, sorry this has gone under the radar entirely 😢 |
| file_h = ts.hdrFromFdno(fd) | ||
| file_ds = file_h.dsOfHeader() | ||
| inst_ds = inst_h.dsOfHeader() | ||
| if file_ds.EVR() >= inst_ds.EVR(): |
There was a problem hiding this comment.
Uh, this is just plain wrong. EVR() returns a plain old string, and one can't compare EVR strings with Python's string comparison and expect anything resembling relevant results. You'll need to use rpm.labelCompare() to compare EVRs, and then you don't need a DS to get the EVR of a header. And in fact you don't need to extract the EVR either, you can just use rpm.versionCompare(file_h, inst_h).
Dependency set comparisons are strange beasts that have their uses but I have no nice examples to give, better to leave them out than give wrong examples.
|
|
||
| for inst_h in ts.dbMatch('name', h['name']): | ||
| inst_ds = inst_h.dsOfHeader() | ||
| if pkg_ds.EVR() >= inst_ds.EVR(): |
There was a problem hiding this comment.
Same as above, this is wrong and wont produce meaningful results.
| def read_rpm_header(ts, filename): | ||
| fd = os.open(filename, os.O_RDONLY) | ||
| try: | ||
| h = ts.hdrFromFdno(fd) |
There was a problem hiding this comment.
You also just pass a file name directly to hdrFromFdno():
>>> h = ts.hdrFromFdno('/tmp/setup-2.15.0-8.fc41.noarch.rpm')
>>> h['name']
'setup'
...or a Python file object...
| `rpm.RPMSENSE_GREATER`, and `rpm.RPMSENSE_LESS`. This tells you if the | ||
| dependency is for a version of a package greater than 4.1, for example. | ||
|
|
||
| The `suggestedPackage` names a package that solves the dependency. The |
There was a problem hiding this comment.
Rpm will only suggest packages if there's a suggestion rpmdb available and enabled, which is ... never.
| You can add packages to a transaction set in any order. The `order` method | ||
| reorders the transaction set to ensure that packages get installed or removed in | ||
| the right order. The order method orders by a topological sort using the | ||
| dependencies relations between objects with dependency comparisons. |
There was a problem hiding this comment.
It's not about reordering a transaction, a transaction is unordered before .order() is called and will miserably fail in any non-trivial case. So this needs a bit of emphasis: it's in practise mandatory to call .order() before calling .run().
| | rpm.RPMCALLBACK_UNINST_STOP | Uninstallation stop | | ||
| | rpm.RPMCALLBACK_REPACKAGE_PROGRESS | Repackaging progress | | ||
| | rpm.RPMCALLBACK_REPACKAGE_START | Repackaging start | | ||
| | rpm.RPMCALLBACK_REPACKAGE_STOP | Repackaging stop | |
There was a problem hiding this comment.
Just drop these REPACKAGE items, no rpm in the last 15+ years has supported that.
| | rpm.RPMCALLBACK_REPACKAGE_START | Repackaging start | | ||
| | rpm.RPMCALLBACK_REPACKAGE_STOP | Repackaging stop | | ||
| | rpm.RPMCALLBACK_UNPACK_ERROR | Error unpacking package file | | ||
| | rpm.RPMCALLBACK_CPIO_ERROR | cpio error getting package payload | |
There was a problem hiding this comment.
And OTOH this is missing a lot of newer items:
REGISTER_ENUM(RPMCALLBACK_SCRIPT_ERROR);
REGISTER_ENUM(RPMCALLBACK_SCRIPT_START);
REGISTER_ENUM(RPMCALLBACK_SCRIPT_STOP);
REGISTER_ENUM(RPMCALLBACK_INST_STOP);
REGISTER_ENUM(RPMCALLBACK_ELEM_PROGRESS);
REGISTER_ENUM(RPMCALLBACK_VERIFY_PROGRESS);
REGISTER_ENUM(RPMCALLBACK_VERIFY_START);
REGISTER_ENUM(RPMCALLBACK_VERIFY_STOP);
|
|
||
| ts = rpm.TransactionSet() | ||
|
|
||
| # Set to not verify DSA signatures. |
There was a problem hiding this comment.
This does a whole lot more than just disable DSA - DSA which is no longer used anywhere.
|
Having quickly skimmed through this, I'm more than a little doubtful on the usefulness of these old examples. They are sooooooooooo outdated that it'd really require going through them with a fine comb one by one. |
|
Eh, sorry, didn't intend to close, just comment. The GH button ordering catches me every now and then 🤪 |
Do we have better ones? |
|
There are newer examples in the main rpm repo: https://github.com/rpm-software-management/rpm/tree/master/python/examples A bad example on the official site is worse than a non-existant one because it tells you "this is how its done". And these ancient examples are so outdated to be dangerous. Let's go back to a state without them, and get the body of newer work merged. We can then look at bringing what's still relevant in those old examples in a more curated and gradual manner. We simply do not have the cycles to review the whole pile of those old examples with the care that it requires. |
We agreed that having examples as scripts in the RPM git repository would be ideal (syntax highlighting, the possibility to run them, etc) but for better discoverability, I would like to mention them even from the RPM website. This way they may be easier to find for people searching on Google or the website itself.