pkgParsePkts() only parses the PGP armor, the actual pubkey is only
parsed as a part of rpmPubkeyNew() whose return we need to check for
separately. Emit different messages in these cases.
Thanks to @KOLANICH for pointing this out and initial patch.
Add API to get and set callback style, defaulting to the good ole
header first style and add a new style where a transaction element
is passed in place of the header, allowing a much saner interaction.
This is doubly so in Python, where the old style callback is a
braindamaged mess. In the new mode the "key" is not passed as separate
argument at all, it can be just as well retrieved via te.Key() for
the callbacks needing it.
The "key" passed to rpmtsAddInstallEleemnt() and associated with transaction
elements is sometimes mistaken for user data, but it is not, as rpm relies
on it having a very specific meaning and is passed around with that very
assumption.
API users have all sorts of (legit!) needs, lets add a proper application
private user data member to transaction elements.
The Python bindings to this are kinda dangerous if you liberally mix Python
and C as we can't know whether the pointer is an actual Python object or not
so we can only assume it is and hope for the best. Of course nobody in their
right mind should be setting user data from one language and accessing it
from another, really...
The code would only raise an exception if TransactionSetCore.addErase()
returned an error, but the catch is that with many kinds of argument
types we'd silently skip the whole addition because no headers were found.
This looks to be a regression introduced some eleven years ago in
commit 9b20c706a4.
As a special case, a match iterator argument will not raise an exception
if it doesn't actually match anything.
Fixes: #1214
addErase() claimed package not installed for failures, but there could
be other reasons, and for eg. headers coming from match iterators
failure to add cannot be "not installed".
Use a common message format that actually states which operation failed.
Use the newly added version converter function for parsing labelCompare()
arguments, gaining automatic access to all formats that we support
in rpm.ver() constructor. Currently this means (E,V,R) tuples which
labelCompare() always used, plus plain old strings. In future, might
be something more.
Epoch promotion was a thing around and before the turn of the millenium,
we really shouldn't be carrying that cruft around anymore.
Remove all traces that we can without too much guilt about breaking
ABI/API and not bumping soname which we dont want to do for this
stupid old thing: all the symbols are left in place, they just don't
work anymore. Nobody should notice as nobody can have been using this
stuff in the last 15+ years.
Lots of cruft here - the build-aux move related changes from commit
cd6e4eb9e0, and all manner of historical
cruft that hasn't existed in over a decade. While at it, consolidate
it all to the toplevel .gitignore.
Up to now we handled this via Python 3 compatibility defines in
rpmsystem-py.h but now that Python 2 is no longer supported, actually
update the codebase. No functional changes.
Python 2 will be EOL by the time of the next major rpm release,
time to retire the Python 2 bindings. Specifically we require
Python >= 3.1 for surrogateescape-support.
Add rpmdbCookie() public function and matching python bindings.
The returned value is an opaque string which changes any time the rpmdb
is changed (eg packages added or removed, rebuild changes things etc).
A key point is that this is entirely database backend agnostic.
The actual implementation here is an SHA1 hash of RPMDBI_NAME keys and
the corresponding package offsets, but this is an implementation detail
that can be changed anytime and callers must not rely on. The only thing
that matters is whether the string equals an earlier cookie value or not.
A cryptographic hash seems like an overkill, but then it saves us the
headaches of coming up with something that reflects order changes etc.
Closes: #388
Since commit 73a41da965 this doesn't need
to be inline with murky linkage across different modules. With this,
it'd now be possible to add some central control too if we wanted.
Since commit 73a41da965 we don't need
to import rpm or wrap our headers through capsules since its all in
one module. Good riddance, including the capsule wrapping in header
creation which was an anomaly wrt reference counting too.
No functional changes.
The split is causing more and more issues over the years. It simply
doesn't make much sense to split them. When using python-rpm, it doesn't
matter whether it brings some additional tools like gpg because you
already have python installed.
Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
Commit 84920f8983 regressed dnf install
to segfault at the end due to some NULL string passed to strlen().
Check for NULL and return it as None, make it an inline function
to make this saner.
In the almost ten years of rpm sort of supporting Python 3 bindings, quite
obviously nobody has actually tried to use them. There's a major mismatch
between what the header API outputs (bytes) and what all the other APIs
accept (strings), resulting in hysterical TypeErrors all over the place,
including but not limited to labelCompare() (RhBug:1631292). Also a huge
number of other places have been returning strings and silently assuming
utf-8 through use of Py_BuildValue("s", ...), which will just irrevocably
fail when non-utf8 data is encountered.
The politically Python 3-correct solution would be declaring all our data
as bytes with unspecified encoding - that's exactly what it historically is.
However doing so would by definition break every single rpm script people
have developed on Python 2. And when 99% of the rpm content in the world
actually is utf-8 encoded even if it doesn't say so (and in recent times
packages even advertise themselves as utf-8 encoded), the bytes-only route
seems a wee bit too draconian, even to this grumpy old fella.
Instead, route all our string returns through a single helper macro
which on Python 2 just does what we always did, but in Python 3 converts
the data to surrogate-escaped utf-8 strings. This makes stuff "just work"
out of the box pretty much everywhere even with Python 3 (including
our own test-suite!), while still allowing to handle the non-utf8 case.
Handling the non-utf8 case is a bit more uglier but still possible,
which is exactly how you want corner-cases to be. There might be some
uses for retrieving raw byte data from the header, but worrying about
such an API is a case for some other rainy day, for now we mostly only
care that stuff works again.
Also add test-cases for mixed data source labelCompare() and
non-utf8 insert to + retrieve from header.
Older Python versions are long since past their EOL, we don't need to
support them either. Python 2.7 is also the least incompatible version
compared to Python 3, going forward. Nuke the now unnecessary compat
macros.
Introduced in commit c7881d8017 back in 2002,
synthesizing a python object for the callback occurs before retaking
the GIL lock, which is not allowed. Somehow this has managed to stay
latent all these years, and even now requires fairly specific conditions:
when the callback gets called without an associated key, such as erasures
or file trigger script start/stop events (in the case of RhBug:1632488),
when Python 3 is running in PYTHONMALLOC=debug mode,
it crashes with "Python memory allocator called without holding the GIL".
Simply retake the lock before any Python operations take place to fix.
We can't use the existing transaction vsflags for package verification
purposes due to legacy misuses and fundamental differences - vsflags
defaults are very different and change can't really be relied on as
this is all tangled up in legacy issues, misuses and misunderstandings
in 3rd party code and whatnot. I dont see a way to unify them in
foreseeable future, unfortunately. So add another API...
Rename _vsflags_pkgverify to _pkgverify_flags to differentiate it from
the other vsflags (because it is different), add get/set API for it in
transaction sets and use where immediately obvious (but there's
the rpm cli install case left to deal with)
rpmtsVSFlags() doesn't actually control what happens with the package
verification that vslevel/vfylevel relates to, it controls
the verification that happens on header/package read. We actually
need a separate API for controlling the flags that control the
operation that verify level is associated with, so to avoid total
confusion as to what is what... paving way for adding rpmtsVfyFlags(),
but that's not added in this commit - rename only.
Adds a separate package verification phase to rpmtsRun() which runs
as part of normal problem checking and performs package verification
as per configuration. Verification problems are returned in the API as
rpm problem objects.
The verification is done according to the configurable verification level
implemented in commit ac280c42e3, ie if
active, it's an enforcing check that cannot bypassed with previously
available means, you need to specifically filter the new problem class or
change configuration. This is intentional to actually enforce the
verification step on all existing API users regardless of their
default settings (it's common to just disable everything in vsflags etc).
The two big things here are:
- rpm FINALLY supports an enforcing signature policy mode
- if at least digest level is specified, packages with malformed payload
will be detected before any scriptlets run or any files get laid down
Note that this commit does not change the default verification level,
and thus should NOT affect any functionality unless manually enabled.
Also worth noting is that this all will almost surely require further
tweaking to get all the corner cases and upper level depsolver interactions
straight...
Argument parsing condition reversed, doh. Means there's simply no way
anybody could've used these for anything at all... Actual testcases
would not hurt.
AFAICS there are no python interfaces where those two values would be
useful, as rpmcliVerify() and rpmcliQuery() are not exported to python.
The relevant constants are the _RPMVSF_NODIGEST/NOSIGNATURES.
This can be used to differentiate files that are not natural parts of
packages but created as by-products of our processing so they're easy
to filter out of queries.
Possible candidates include build-ids, byte compiled files etc, but this
nothing is automatically marked as artifact in this commit.
These are not transaction members in the traditional sense as they
simply represent a package that is in the rpmdb and cannot actually
be members of a transaction set (at least not currently). But packages
from the rpmdb can and do participate in the transaction in the form of
triggers and file triggers, and abusing TR_REMOVED for the purpose is
just that - abuse.
This is not supposed to actually change any behavior though.
rpmteDBOffset() simply returns zero for non-installed packages, which
is actually useful for determining whether a TR_ADDED package has
already been installed or not, rpm even relies on this. Remove a couple
of other questionable TR_REMOVED comments too.
Simplifies things a bit and also makes "PYTHON=python3 ./configure" work,
whereas it previously barfed on figuring the library names like
"libpython3.6m"
Refactor rpmsign and python bindings to be more similar on both
addsign/delsign operations, and always pass the signing arguments
along. Deletion doesn't actually (yet) use the arguments for anything
but makes things more symmetric (I remember having doubts about
this when adding - reminder to self: if in doubt, add more arguments ;)
Yet another API break, but what the hey... Other than that, behavior is
not supposed to change here.