Changes from Version 1 of 5MinuteExamples

Show
Ignore:
Author:
skvidal (IP: 24.211.246.61)
Timestamp:
11/14/08 18:04:28 (9 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • 5MinuteExamples

    v0 v1  
     1= Programming with Yum in 5 minutes, or so = 
     2 
     3There are a lot of lines of code in yum, and it can be somewhat intimidating at first glace. However a significant amount of effort has been made to make simple things easy, and the hard things not so hard. The start of any code using yum, will almost certainly have these four lines (and always the first and last one :). 
     4{{{ 
     5    1 #! /usr/bin/python -tt 
     6    2  
     7    3 import os 
     8    4 import sys 
     9    5 import yum 
     10}}} 
     11 
     12Those lines just tell python, you'd you'd like to be able to use the yum code, and some stuff for the OS. Next the first bit of real code, and something which is also in almost every piece of code using yum: 
     13 
     14{{{ 
     15    7 yb = yum.YumBase() 
     16}}} 
     17 
     18This creates a yum instance, that you can work with. Then one more piece, that is very useful: 
     19{{{ 
     20    9 yb.conf.cache = os.geteuid() != 0 
     21}}} 
     22 
     23This just tells the yum instance not to try and update any of it's data, as the caller of the script probably hasn't got the permissions to do so. 
     24 
     25Now we have a real yum object that we can do things with, the three most useful parts to access are pkgSack, rpmdb and repos. The first two basically act the same, but rpmdb performs queries based on the installed packages on the local machine and pkgSack performs them against all the enabled (normally remote) repositories. The repos attribute is almost always used for one of three things, calling repos.enableRepo(), repos.disableRepo() and less often repos.listEnabled(). The latter for if you need to set/override some specific configuration for the repos. 
     26 
     27The pkgSack and rpmdb attributes have a fairly large number of functions you can call, most of which return "package objects" these are the main things you work with most in yum code. Probably the most useful functions to get those package objects are: searchNevra(), returnPackages() and searchPrimaryFields(). There are also some optimized varients like, searchNames() and returnNewestByNameArch(). Some examples would be: 
     28Simple version of "yum list" command 
     29{{{ 
     30   11 # Get the repository package objects matching the passed arguments 
     31   12 pkgs = yb.pkgSack.returnNewestByNameArch(patterns=sys.argv[1:]) 
     32   13  
     33   14 for pkg in pkgs: 
     34   15     print "%s: %s" % (pkg, pkg.summary) 
     35}}} 
     36Simple stats. gathering from installed packages 
     37{{{ 
     38   17 # Find the ten biggest installed packages 
     39   18 pkgs = yb.rpmdb.returnPackages() 
     40   19 pkgs.sort(key=lambda x: x.size, reverse=True) 
     41   20 print "Top ten installed packages:" 
     42   21 done = set() 
     43   22 for pkg in pkgs: 
     44   23     if pkg.name in done: 
     45   24         continue 
     46   25     done.add(pkg.name) 
     47   26     print "%s: %sMB" % (pkg, pkg.size / (1024 * 1024)) 
     48   27     if len(done) >= 10: 
     49   28         break 
     50 
     51}}} 
     52 
     53Slightly more advanced topics 
     54 
     55After playing with yum code for a little bit, you'll probably experience a function which you might think would return a "package object" but doesn't returning a tuple of data instead. The two common tuples within yum are the "package tuple" and the "dependency tuple" which are: 
     56 
     57{{{ 
     58   30 # Pacakge tuple: 
     59   31 (pkg.name, pkg.arch, pkg.epoch, pkg.version, pkg.release) 
     60   32 # Dependency (or the Provides/Requires/Conflicts/Obsoletes (PRCO)) tuple: 
     61   33 (pkg.name, 'EQ', (pkg.epoch, pkg.version, pkg.release)) 
     62}}} 
     63 
     64After that you'll probably start playing with the "transaction info" (yb.tsInfo), and the "install", "update" and "remove" functions of YumBase. So you can change the system as well as query it. Then you'll want to present your information in a way that looks as good as a normal yum command (using the "internal" output module), although that is less unsupported. A somewhat useful example might be: 
     65"Clever" way to manually update almost all the metadata for any usable repos. installed 
     66{{{ 
     67    1 #! /usr/bin/python -tt 
     68    2  
     69    3 import os 
     70    4 import sys 
     71    5 import yum 
     72    6  
     73    7 yb = yum.YumBase() 
     74    8  
     75    9 yb.conf.cache = os.geteuid() != 0 
     76   10  
     77   11 from urlgrabber.progress import TextMeter 
     78   12  
     79   13 # Use the "internal" output mode of yum's cli 
     80   14 sys.path.insert(0, '/usr/share/yum-cli') 
     81   15 import output 
     82   16  
     83   17 # Try not to be annoying if run from cron etc. 
     84   18 if sys.stdout.isatty(): 
     85   19     yb.repos.setProgressBar(TextMeter(fo=sys.stdout)) 
     86   20     yb.repos.callback = output.CacheProgressCallback() 
     87   21     yumout = output.YumOutput() 
     88   22     freport = ( yumout.failureReport, (), {} ) 
     89   23     yb.repos.setFailureCallback( freport ) 
     90   24  
     91   25 # Enable all the repos. a user might want to use and sync. the metadata. 
     92   26 # Note this needs to be done before the repositories are used. 
     93   27 for name in ('updates-testing', 'rawhide', 'livna', 'adobe-linux-i386', 
     94   28              'brew', 'rhts', 'koji-static'): 
     95   29     yb.repos.enableRepo(name + ',') 
     96   30 for repo in yb.repos.listEnabled(): 
     97   31     yb.repos.enableRepo(repo.id + '-source'    + ',') 
     98   32     yb.repos.enableRepo(repo.id + '-debuginfo' + ',') 
     99   33 yb.repos.doSetup() 
     100   34 for repo in yb.repos.listEnabled(): 
     101   35     repo.mdpolicy        = 'group:main' 
     102   36     repo.metadata_expire = 0 
     103   37     repo.repoXML 
     104   38 # This is somehwat "magic", it unpacks the metadata making it usable. 
     105   39 yb.repos.populateSack(mdtype='metadata', cacheonly=1) 
     106   40 yb.repos.populateSack(mdtype='filelists', cacheonly=1) 
     107}}} 
     108 
     109Hopefully that will go some way to giving you an overview of how you can use the yum API to perform queries or tasks that would otherwise be very difficult. For further information you can use the help feature of ipython to look at docstrings for the variuos components, and even use the TAB complete feature of ipython to see all the available attributes of packages, repos, pkgSack or the YumBase itself.