Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Python RPM modules

59 views
Skip to first unread message

Kohli, Ranjan

unread,
Aug 14, 2000, 3:00:00 AM8/14/00
to
All,
I have looking all over for documentation/examples of how I can use
Python to install apps that are packed in a RPM. I find bits and pieces
and passing references to a rpm module in rpmlint/anaconda/up2date, but
am having a hard time finding what the API looks like. I would
appreciate it if some one could point me in the right direction. The
actual module would be perfect.

Thanks, I appreciate it.

Ranjan

_______________________________________________
Rpm-list mailing list
Rpm-...@redhat.com
https://listman.redhat.com/mailman/listinfo/rpm-list

Jeff Johnson

unread,
Aug 15, 2000, 3:00:00 AM8/15/00
to
On Mon, Aug 14, 2000 at 01:07:02PM -0400, Kohli, Ranjan wrote:
> All,
> I have looking all over for documentation/examples of how I can use
> Python to install apps that are packed in a RPM. I find bits and pieces
> and passing references to a rpm module in rpmlint/anaconda/up2date, but
> am having a hard time finding what the API looks like. I would
> appreciate it if some one could point me in the right direction. The
> actual module would be perfect.
>

The "actual module" is in the rpm source tree, see the python sub-directory for
sources or the rpm-python binary package for the python bindings.

73 de Jeff

--
Jeff Johnson ARS N3NPQ
j...@jbj.org (j...@redhat.com)
Chapel Hill, NC

Adrian Likins

unread,
Aug 15, 2000, 3:00:00 AM8/15/00
to
On Mon, Aug 14, 2000 at 01:07:02PM -0400, Kohli, Ranjan wrote:
> All,
> I have looking all over for documentation/examples of how I can use
> Python to install apps that are packed in a RPM. I find bits and pieces
> and passing references to a rpm module in rpmlint/anaconda/up2date, but
> am having a hard time finding what the API looks like. I would
> appreciate it if some one could point me in the right direction. The
> actual module would be perfect.

The module is in the rpm source file, and in the rpm source rpm.
Unfortunately, without a decent knowledge of librpm, it can be
a bit difficult to dive into. About the only docs is the "testit"
file include, and its not all that useful.

The module is all c actually. Looking though the anaconda source
code is probabaly about the best place to look for hints on how
to use it.


Adrian

Kohli, Ranjan

unread,
Aug 17, 2000, 3:00:00 AM8/17/00
to
Jeff,
Thanks for taking the time to reply. I did make some headway by looking
through the rmpmodule source code. What I have not been able to find is
exactly where/how in the anaconda python modules are the rpm packages
actually installed. I have looked at the todo.py, text.py, gui.py etc and
can't locate it. Any clues as to where the call is actually made i.e. rpm -i
to install a package would be appreciated.

Thanks once again.

Ranjan


-----Original Message-----
From: Jeff Johnson [mailto:j...@JBJ.ORG]
Sent: Monday, August 14, 2000 5:12 PM
To: rpm-...@redhat.com
Subject: Re: Python RPM modules


On Mon, Aug 14, 2000 at 01:07:02PM -0400, Kohli, Ranjan wrote:
> All,
> I have looking all over for documentation/examples of how I can use
> Python to install apps that are packed in a RPM. I find bits and pieces
> and passing references to a rpm module in rpmlint/anaconda/up2date, but
> am having a hard time finding what the API looks like. I would
> appreciate it if some one could point me in the right direction. The
> actual module would be perfect.
>

The "actual module" is in the rpm source tree, see the python sub-directory


for
sources or the rpm-python binary package for the python bindings.

73 de Jeff

--
Jeff Johnson ARS N3NPQ
j...@jbj.org (j...@redhat.com)
Chapel Hill, NC

_______________________________________________

Matt Wilson

unread,
Aug 18, 2000, 3:00:00 AM8/18/00
to
Here's the start, it's not quite finised, though. :| There's still
some important stuff missing.

Matt

RPM binding for Python
-----------------------

The RPM bindings for Python present an object oriented approach to
using the RPM Package Manager. The main object types are:

Class "header" - represents a RPM package header

All RPM packages have headers that provide metadata for the package.
Header objects can be returned by database queries or loaded from a
binary package on disk.

The headerFromPackage function loads the package header from a
package on disk. It returns a tuple of a "isSource" flag and the
header object. The "isSource" flag is set to 1 if the package
header was read from a source rpm or to 0 if the package header was
read from a binary rpm. For example:

import os, rpm

fd = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
(isSource, header) = rpm.headerFromPackage(fd)
fd.close()

The Python interface to the header data is quite elegant. It
presents the data in a dictionary form. We'll take the header we
just loaded and access the data within it:

print header[rpm.RPMTAG_NAME]
print header[rpm.RPMTAG_VERSION]
print header[rpm.RPMTAG_RELEASE]

in the case of our "foor-1.0-1.i386.rpm" package, this code would
output:

foo
1.0
1

You make also access the header data by string name:

print header['name']

This method of access is a bit slower because the name must be
translated into the tag number dynamically.

Class "rpmdb" - represents a RPM database.
Instances of the rpmdb object provide access to the records of a
RPM database. The records are accessed by index number. To
retrieve the header data in the RPM database, the rpmdb object is
subscripted as you would access members of a list.

The rpmdb class contains the following methods:
firstkey() - returns the index of the first record in the database
(will be deprecated in RPM 4.0)
nextkey(index) - returns the index of the next record after
"index" in the database.
findbyfile(file) - returns a list of the indexes to records that
own file "file".
findbyname(name) - returns a list of the indexes to records for
packages named "name".
findbyprovides(provides) - returns a list of the indexes to records for
packages that provide "provides".

To obtain a rpmdb object, the opendb function in the rpm module
must be called. The opendb function takes two optional arguments.
The first optional argument is a boolean flag that specifies if the
database is to be opened for read/write access or read-only access.
The second argument specifies an alternate root directory for RPM
to use.

An example of opening a database and retrieving the first header in
the database, then printing the name of the package that the header
represents:

import rpm
db = rpm.opendb()
index = db.firstkey()
header = db[index]
print header[rpm.RPMTAG_NAME]

To print all of the packages in the database that match a package
name, the code will look like this:

import rpm
db = rpm.opendb()
indexes = db.findbyname("foo")
for index in indexes:
header = db[index]
print "%s-%s-%s" % (header[rpm.RPMTAG_NAME],
header[rpm.RPMTAG_VERSION],
header[rpm.RPMTAG_RELEASE])

Class rpmtrans - represents a RPM transaction set.

The transaction set is the workhorse of RPM. It performs the
installation and upgrade of packages. The rpmtrans object is
instantiated by the TransactionSet function in the rpm module.

The TransactionSet function takes two optional arguments. The first
argument is the root path, the second is an open database to perform
the transaction set upon.

A rpmtrans object has the following methods:
add(header, data, mode) - adds a binary package to the transaction set
header - the header of the binary package to be added to the
transaction set
data - user data that will be passed to the transaction
callback during transaction execution
mode - optional argument that specifies if this package should
be installed ('i'), upgraded ('u'), or if it is just
available to the transaction when computing
dependencies but no action should be performed with it
('a').

depcheck() - performs a dependency and conflict check on the
transaction set After headers have been added to a
transaction set, a dependency check can be performed
to make sure that all package dependencies are
satisfied. If there are no unresolved dependencies,
None is returned. If there are dependencies, a list
of complex tuples is returned, one tuple per
unresolved dependency.

The format of the dependency tuple is:
((packageName, packageVersion, packageRelease),
(reqName, reqVersion),
needsFlags,
suggestedPackage,
sense)
packageName, packageVersion, packageRelease are the name,
version, and release of the package that has the unresolved
dependency or conflict.

The reqName and reqVersion are the name and version of the
requirement or conflict.

The needsFlags is a bitfield that describes the versioned
nature of a requirement or conflict. The constants
rpm.RPMDEP_SENSE_LESS, rpm.RPMDEP_SENSE_GREATER, and
rpm.RPMDEP_SENSE_EQUAL can be logical ANDed with the needsFlags
to get versioned dependency information.

suggestedPackage is a tuple if the dependency check was aware
of a package that solves this dependency problem when the
dependency check was run. Packages that are added to the
transaction set as "available" are examined during the
dependency check as possible dependency solvers. The tuple
contains two values, (header, suggestedName). These are set to
the header of the suggested package and its name, respectively.
If there is no known package to solve the dependency problem,
suggestedPackage is None.

The constants rpm.RPMDEP_SENSE_CONFLICTS and
rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
requirement or a conflict.

run(flags, problemSetFilter, callback, data) - attempts to execute
transaction set

After the transaction set has been populated with install and
upgrade actions, it can be executed by invoking the run()
method.

Arguments -
flags - modifies the behavior of the transaction set as it is
processed. The following values can be locical ORed
together:
rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
database, change any files, or run
any package scripts
rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
problems encountered when attempting to run this transaction
set
rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
database, do not modify files.
rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
file is marked %config(missingok) and an upgrade is
being performed.
rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
packages.

problemSetFilter - a bitfield that tells the transaction set
engine to ignore classes of problems

rpm.RPMPROB_FILTER_IGNOREOS -
rpm.RPMPROB_FILTER_IGNOREARCH -
rpm.RPMPROB_FILTER_REPLACEPKG -
rpm.RPMPROB_FILTER_FORCERELOCATE -
rpm.RPMPROB_FILTER_REPLACENEWFILES -
rpm.RPMPROB_FILTER_REPLACEOLDFILES -
rpm.RPMPROB_FILTER_OLDPACKAGE -
rpm.RPMPROB_FILTER_DISKSPACE -


On Mon, Aug 14, 2000 at 01:07:02PM -0400, Kohli, Ranjan wrote:
> All,
> I have looking all over for documentation/examples of how I can use
> Python to install apps that are packed in a RPM. I find bits and pieces
> and passing references to a rpm module in rpmlint/anaconda/up2date, but
> am having a hard time finding what the API looks like. I would
> appreciate it if some one could point me in the right direction. The
> actual module would be perfect.
>

> Thanks, I appreciate it.
>
> Ranjan
>
>
>

Matt Wilson

unread,
Aug 18, 2000, 3:00:00 AM8/18/00
to
todo.py, in doInstall. Look for the ts = rpm.transactionSet(),
ts.add(...), and ts.run()

Matt

On Thu, Aug 17, 2000 at 10:31:02AM -0400, Kohli, Ranjan wrote:
> Jeff,
> Thanks for taking the time to reply. I did make some headway by looking
> through the rmpmodule source code. What I have not been able to find is
> exactly where/how in the anaconda python modules are the rpm packages
> actually installed. I have looked at the todo.py, text.py, gui.py etc and
> can't locate it. Any clues as to where the call is actually made i.e. rpm -i
> to install a package would be appreciated.

_______________________________________________

Kohli, Ranjan

unread,
Aug 23, 2000, 3:00:00 AM8/23/00
to
Matt Wilson wrote:

> Here's the start, it's not quite finised, though. :| There's still
> some important stuff missing.

> ......


>
> A rpmtrans object has the following methods:

> ....


> run(flags, problemSetFilter, callback, data) - attempts to execute
> transaction set
>

> .....

Matt,
Could you let me know what the format of the callback and the data
arguments need to be. The callback in todo.py (self.instCallback) is alot
more complicated than what I need to do.

Thanks,

Matt Wilson

unread,
Aug 23, 2000, 3:00:00 AM8/23/00
to
On Wed, Aug 23, 2000 at 10:50:58AM -0400, Kohli, Ranjan wrote:
>
> Matt,
> Could you let me know what the format of the callback and the data
> arguments need to be. The callback in todo.py (self.instCallback) is alot
> more complicated than what I need to do.

Yea, I haven't gotten to that part. I'll try to do it next week..

Matt

Kohli, Ranjan

unread,
Aug 24, 2000, 3:00:00 AM8/24/00
to
All,
I need your assistance with this. I am trying to get to understand
Python-RPM bindings. In order to do that I have written some test code. I
successfully get to the point where I have created a transaction and am ready
to run it. As soon as it gets to ts.run(..) I get a core dump. gdb'ing the
dump and doing a back trace I can see its in the rpm library, so obviously I
am doing something wrong when I call ts.run. I have enclosed the Python module
I have written. If someone can tell me what I am doing wrong I would
appreciate it. Scroll down to the bottom to see the ts.run(...) call.

Thanks all,
Ranjan

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


#!/usr/bin/python

import rpm
import os
import sys

from gtk import *
import GtkExtra

def instCallback(self, what, amount, total, h):
print "In instCallback"

print self, what,amount, total, h, "\n"
if (what == rpm.RPMCALLBACK_TRANS_START):
print "rpm.RPMCALLBACK_TRANS_START"

if (what == rpm.RPMCALLBACK_TRANS_PROGRESS):
print "rpm.RPMCALLBACK_TRANS_PROGRESS"

if (what == rpm.RPMCALLBACK_TRANS_STOP):
print "rpm.RPMCALLBACK_TRANS_STOP"

if (what == rpm.RPMCALLBACK_INST_OPEN_FILE):
print "rpm.RPMCALLBACK_INST_OPEN_FILE"
elif (what == rpm.RPMCALLBACK_INST_PROGRESS):
if total:
print "rpm.RPMCALLBACK_INST_OPEN_FILE"
print amount, total, "\n"
elif (what == rpm.RPMCALLBACK_INST_CLOSE_FILE):
print "rpm.RPMCALLBACK_INST_OPEN_FILE"
else:
pass

def doNothing():
pass


def do_rpm_stuff():
# Here is where I do RPM installs
# In general we take the following steps
# we need to open the rpm database
# db = rpm.opendb()
# Create a transaction set
# ts = rpm.TransactionSet(db)


# First I need to open the database
print "Beginning to do RPM Stuff \n"

# Misc RPM stuff
try:
fd = os.open("tripwire-1.2-5.i386.rpm", os.O_RDONLY)
(header, isSource) = rpm.headerFromPackage(fd)
os.close(fd)
if ( isSource ):
print header[rpm.RPMTAG_NAME], ' is a source package'
else:
print header[rpm.RPMTAG_NAME], ' is a binary package'

print header[rpm.RPMTAG_NAME]
print header[rpm.RPMTAG_VERSION]
print header[rpm.RPMTAG_RELEASE]

except:
sys.stderr.write('error in do_rpm_stuf()!\n')
print 'error!', sys.exc_type, sys.exc_value


# Open the rpm database
db = rpm.opendb()

# Create a transaction set
ts = rpm.TransactionSet()

# Add the rpm to the transaction set
ts.add( header, header, "u" )

# Do a dependency check
deps = ts.depcheck()

rc = []
if deps:
print 'Looking for dependencies'
for ((name, version, release),
(reqname, reqversion),
flags, suggest, sense) in deps:
print deps
if sense == rpm.RPMDEP_SENSE_REQUIRES:
if suggest:
(header, sugname) = suggest
print (header, sugname)
else:
sugname = "no suggestion"
print sugname
if sense == rpm.RPMDEP_SENSE_CONFLICTS:
if suggest:
(header, sugname) = suggest
print (header, sugname), "conflict"
else:
sugname = "no conflict suggestion"
print sugname
if not (name, sugname) in rc:
rc.append ((name, sugname))

print "Done with dependency check"

ts.order()

try:
#problems =
ts.run(rpm.RPMTRANS_FLAG_BUILD_PROBS,~rpm.RPMPROB_FILTER_DISKSPACE,
instCallback, 0)
# at this point I get a core dump...
problems = ts.run(0,~rpm.RPMPROB_FILTER_DISKSPACE, doNothing, 0)
print problems
except:
sys.stderr.write('error in do_rpm_stuf()!\n')
print 'error!', sys.exc_type, sys.exc_value


# Main starts here...

def main():
rc_parse("testgtkrc")
do_rpm_stuff()
#mainloop()

if __name__ == '__main__': main()

0 new messages