Package bodhi :: Module metadata
[hide private]
[frames] | no frames]

Source Code for Module bodhi.metadata

  1  # $Id: metadata.py,v 1.1 2006/12/31 09:10:14 lmacken Exp $ 
  2  # This program is free software; you can redistribute it and/or modify 
  3  # it under the terms of the GNU General Public License as published by 
  4  # the Free Software Foundation; version 2 of the License. 
  5  # 
  6  # This program is distributed in the hope that it will be useful, 
  7  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  8  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  9  # GNU Library General Public License for more details. 
 10  # 
 11  # You should have received a copy of the GNU General Public License 
 12  # along with this program; if not, write to the Free Software 
 13  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 14   
 15  __version__ = '1.4' 
 16   
 17  import os 
 18  import rpm 
 19  import gzip 
 20  import logging 
 21  import commands 
 22   
 23  from xml.dom import minidom 
 24  from os.path import join, basename, exists, isdir 
 25  from sqlobject import SQLObjectNotFound 
 26  from turbogears import config 
 27   
 28  from bodhi.util import get_repo_tag 
 29  from bodhi.model import PackageBuild 
 30  from bodhi.buildsys import get_session 
 31  from bodhi.modifyrepo import RepoMetadata 
 32  from bodhi.exceptions import RepositoryNotFound 
 33   
 34  log = logging.getLogger(__name__) 
 35   
36 -class ExtendedMetadata:
37
38 - def __init__(self, repo):
39 self.tag = get_repo_tag(repo) 40 self.repo = repo 41 self.doc = None 42 self.updates = set() 43 self.builds = {} 44 self.checksums = {} # { pkg-ver-rel : { arch : checksum, ... }, ... } 45 self.koji = get_session() 46 self._create_document() 47 self._fetch_updates() 48 self._fetch_checksums() 49 log.debug("Generating XML update metadata for updates") 50 map(self.add_update, self.updates)
51
52 - def _fetch_updates(self):
53 """ 54 Based on our given koji tag, populate a list of PackageUpdates. 55 """ 56 log.debug("Fetching builds tagged with '%s'" % self.tag) 57 kojiBuilds = self.koji.listTagged(self.tag, latest=True) 58 log.debug("%d builds found" % len(kojiBuilds)) 59 for build in kojiBuilds: 60 self.builds[build['nvr']] = build 61 try: 62 b = PackageBuild.byNvr(build['nvr']) 63 map(self.updates.add, b.updates) 64 except SQLObjectNotFound, e: 65 log.warning(e)
66
67 - def _create_document(self):
68 log.debug("Creating new updateinfo Document for %s" % self.tag) 69 self.doc = minidom.Document() 70 updates = self.doc.createElement('updates') 71 self.doc.appendChild(updates)
72
73 - def _insert(self, parent, name, attrs={}, text=None):
74 """ Helper function to trivialize inserting an element into the doc """ 75 child = self.doc.createElement(name) 76 for item in attrs.items(): 77 child.setAttribute(item[0], str(item[1])) 78 if text: 79 txtnode = self.doc.createTextNode(str(text)) 80 child.appendChild(txtnode) 81 parent.appendChild(child) 82 return child
83
84 - def _get_notice(self, update):
85 for elem in self.doc.getElementsByTagName('update'): 86 for child in elem.childNodes: 87 if child.nodeName == 'id' and child.firstChild and \ 88 child.firstChild.nodeValue == update.update_id: 89 return elem 90 return None
91
92 - def _fetch_checksums(self):
93 """ 94 Pull a list of 'name-version-release sha1' from our repodata and store 95 it in self.checksums = { n-v-r : { arch : sha1sum } } 96 """ 97 log.debug("Fetching checksums from repodata") 98 for arch in os.listdir(self.repo): 99 archrepo = join(self.repo, arch) 100 if not isdir(archrepo): continue 101 cmd = 'repoquery --repofrompath=foo,%s --repofrompath=bar,%s -a --qf "%%{name}-%%{version}-%%{release} %%{id}" --repoid=foo --repoid=bar' % (archrepo, join(archrepo, 'debug')) 102 log.debug("Running `%s`" % cmd) 103 out = commands.getoutput(cmd) 104 try: 105 for line in out.split('\n')[2:]: 106 pkg, csum = line.split() 107 if not self.checksums.has_key(pkg): 108 self.checksums[pkg] = {} 109 self.checksums[pkg][arch] = csum 110 except Exception, e: 111 log.error("Unable to parse repoquery output: %s" % e)
112 113 #def remove_update(self, update): 114 # elem = self._get_notice(update) 115 # if elem: 116 # log.debug("Removing %s from updateinfo.xml" % update.title) 117 # self.doc.firstChild.removeChild(elem) 118 # return True 119 # return False 120
121 - def add_update(self, update):
122 """ 123 Generate the extended metadata for a given update 124 """ 125 ## Make sure this update doesn't already exist 126 if self._get_notice(update): 127 log.debug("Update %s already in updateinfo" % update.title) 128 return 129 130 log.debug("Generating extended metadata for %s" % update.title) 131 132 root = self._insert(self.doc.firstChild, 'update', attrs={ 133 'type' : update.type, 134 'status' : update.status, 135 'version' : __version__, 136 'from' : config.get('release_team_address') 137 }) 138 139 self._insert(root, 'id', text=update.update_id) 140 self._insert(root, 'title', text=update.title) 141 self._insert(root, 'release', text=update.release.long_name) 142 self._insert(root, 'issued', attrs={ 'date' : update.date_pushed }) 143 144 ## Build the references 145 refs = self.doc.createElement('references') 146 for cve in update.cves: 147 self._insert(refs, 'reference', attrs={ 148 'type' : 'cve', 149 'href' : cve.get_url(), 150 'id' : cve.cve_id 151 }) 152 for bug in update.bugs: 153 self._insert(refs, 'reference', attrs={ 154 'type' : 'bugzilla', 155 'href' : bug.get_url(), 156 'id' : bug.bz_id, 157 'title': bug.title 158 }) 159 root.appendChild(refs) 160 161 ## Errata description 162 self._insert(root, 'description', text=update.notes) 163 164 ## The package list 165 pkglist = self.doc.createElement('pkglist') 166 collection = self.doc.createElement('collection') 167 collection.setAttribute('short', update.release.name) 168 self._insert(collection, 'name', text=update.release.long_name) 169 170 for build in update.builds: 171 log.debug("Generating package list for %s" % build.nvr) 172 kojiBuild = self.builds[build.nvr] 173 rpms = self.koji.listBuildRPMs(kojiBuild['id']) 174 for rpm in rpms: 175 filename = "%s.%s.rpm" % (rpm['nvr'], rpm['arch']) 176 if rpm['arch'] == 'src': 177 arch = 'SRPMS' 178 elif rpm['arch'] == 'noarch': 179 arch = 'i386' 180 else: 181 arch = rpm['arch'] 182 urlpath = join(config.get('file_url'), 183 update.status == 'testing' and 'testing' or '', 184 update.release.name[-1], arch, filename) 185 pkg = self._insert(collection, 'package', attrs={ 186 'name' : rpm['name'], 187 'version' : rpm['version'], 188 'release' : rpm['release'], 189 'arch' : rpm['arch'], 190 'src' : urlpath 191 }) 192 self._insert(pkg, 'filename', text=filename) 193 try: 194 self._insert(pkg, 'sum', attrs={ 'text' : 'sha1' }, 195 text=self.checksums[rpm['nvr']][arch]) 196 except KeyError: 197 log.error("Unable to find checksum for %s" % rpm['nvr']) 198 199 if build.package.suggest_reboot: 200 self._insert(pkg, 'reboot_suggested', text='True') 201 202 collection.appendChild(pkg) 203 204 pkglist.appendChild(collection) 205 root.appendChild(pkglist) 206 log.debug("Metadata generation successful")
207
208 - def insert_updateinfo(self):
209 for arch in os.listdir(self.repo): 210 try: 211 repomd = RepoMetadata(join(self.repo, arch, 'repodata')) 212 log.debug("Inserting updateinfo.xml.gz into %s" % self.repo) 213 repomd.add(self.doc) 214 except RepositoryNotFound: 215 log.error("Cannot find repomd.xml in %s" % self.repo)
216