#!/usr/bin/python -t # -*- mode: Python; indent-tabs-mode: nil; -*- # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Build job results interface ## implemented for local plague-results needsign tree. import errno, os, sys import fnmatch, shutil, time import Utils class BuildSys: def GetBuildResults(self): pass def PruneBuildResults(self): pass class LocalPlague(BuildSys): def __init__(self, needsignroot, createrepo): self.needsignroot = needsignroot self.createrepo = createrepo def GetBuildResults(self): rv = [] for (name,jobroots) in self._ListPlagueResults(True): for path in jobroots: br = BuildResults(name,path) rv.append(br) def sortbyname(a,b): return cmp(a.__str__(),b.__str__()) rv.sort(sortbyname) return rv def _ListPlagueResults(self,droppushed=False): """returns list of (name,[jobroots]) tuples for available build-results, where every "jobroot" is the path to a build-job results directory""" # The needsign repository root contains a directory "name" for # every built src.rpm package %{name}. d = os.listdir(self.needsignroot) try: d.remove('repodata') except ValueError: pass rv = [] # return value: list of (name,[jobroots]) tuples for name in d: pkgroot = os.path.join(self.needsignroot,name) if not os.path.isdir(pkgroot): continue jobroots = [] # Every built version-release is stored in an own sub-dir of "name". # e.g. ./foo/1.0-1 ./foo/1.0-2 for pkgrelroot in map(lambda f: os.path.join(pkgroot,f), os.listdir(pkgroot)): if os.path.isdir(pkgrelroot): if droppushed and os.path.isfile(os.path.join(pkgrelroot,'PUSHED')): continue jobroots.append(pkgrelroot) if jobroots or not droppushed: rv.append( (name,jobroots) ) return rv def _CreateRepo(self): cmd = self.createrepo + " -x \'*.src.rpm\' -x \'*-debuginfo-*.rpm\' %s" % self.needsignroot Utils.run(cmd) def PruneBuildResults(self): repochanged = False for (name,pkgrelroots) in self._ListPlagueResults(): validbuilds = pkgrelroots # Delete those builds which are marked as PUSHED and old enough. for pkgrelroot in pkgrelroots: flagname = os.path.join(pkgrelroot,'PUSHED') if not os.path.isfile(flagname): continue mtime = os.path.getmtime(flagname) # Check if there are *.rpm newer than the flag # (When exactly is that possible? old-style kernel mods?) changed = False for root, dirs, files in os.walk(pkgrelroot): if changed: break for f in fnmatch.filter(files, '*.rpm'): if os.path.getmtime(os.path.join(root, f)) > mtime: changed = True break if changed: print 'New packages in PUSHED %s, clearing flag' % pkgrelroot br = BuildResults(name,pkgrelroot) br.UnmarkPushed() continue if ( time.time()-mtime > 3600*48 ): print 'Removing old %s' % pkgrelroot shutil.rmtree(pkgrelroot) repochanged = True validbuilds.remove(pkgrelroot) # Now re-examine the remaining builds and mark unneeded ones as PUSHED. # TODO: white-list some packages, such as "kmod-*"? pkgrelroots = validbuilds pkgroot = os.path.join(self.needsignroot,name) if len(pkgrelroots) < 2: # only one release or empty dir # Clean up empty package name directories. if not len(pkgrelroots): try: #print('Removing empty directory %s' % pkgroot) os.rmdir(pkgroot) except OSError, e: print e pass continue # with next name #print( '%s release(s) for %s: %s' % (len(pkgrelroots),name,' '.join(map(lambda f: os.path.basename(f),pkgrelroots))) ) # We assume this release to be the newest. relroot = pkgrelroots[0] # There can be only one src.rpm in this dir, since relroot # and src.rpm filename are unique (due to NVR). srcrpms = Utils.find_files(relroot,'*.src.rpm') srcrpms.extend(Utils.find_files(relroot,'*.nosrc.rpm')) # Currently, directories can be empty though, unless we clean up # the repodir regularly. if not len(srcrpms): continue srcrpm = srcrpms[0] (n,a,e,v,r) = Utils.naevr(srcrpm) # Now compare with the other releases. for nextrelroot in pkgrelroots[1:]: nextsrcrpms = Utils.find_files(nextrelroot,'*.src.rpm') nextsrcrpms.extend(Utils.find_files(nextrelroot,'*.nosrc.rpm')) if not len(nextsrcrpms): continue nextsrcrpm = nextsrcrpms[0] (nextn,nexta,nexte,nextv,nextr) = Utils.naevr(nextsrcrpm) # 1 means: e,v,r is higher than nexte,nextv,nextr if Utils.compareEVR((e,v,r),(nexte,nextv,nextr)) == 1: #print('Ignoring: %s' % nextrelroot) br = BuildResults(name,nextrelroot) br.MarkPushed() else: #print('Ignoring: %s' % relroot) br = BuildResults(name,relroot) br.MarkPushed() # Make this the next newest package for ongoing comparison. relroot = nextrelroot (n,a,e,v,r) = (nextn,nexta,nexte,nextv,nextr) if repochanged: self._CreateRepo() class BuildResults: def __init__(self,name,home): self.name = name # src.rpm %{name} self.origin = home # original home self.pkgid = name+'-'+os.path.basename(home) # plague-results style self.SetHome(home) def __str__(self): return self.pkgid def GetName(self): return self.name def GetHome(self): return self.home def SetHome(self,home): self.home = home self.filedict = {} self.filedict['srpm'] = [] self.filedict['rpm'] = [] self.filedict['debuginfo'] = [] self.filedict['other'] = [] # Match the build-results files to what list they should be in. for file in Utils.find_files( self.home ): if file.endswith('.rpm'): if file.find('debuginfo') != -1: which = 'debuginfo' elif file.endswith('.src.rpm') or file.endswith('.nosrc.rpm'): which = 'srpm' else: which = 'rpm' else: which = 'other' self.filedict[which].append(file) def GetSourcePkg(self): if len(self.filedict['srpm']): return self.filedict['srpm'][0] else: return None def MarkPushed(self): if self.origin: Utils.mark_pkg(self.origin,'PUSHED') Utils.unmark_pkg(self.origin,'EXCLUDED') def UnmarkPushed(self): if self.origin: Utils.unmark_pkg(self.origin,'PUSHED') def MarkExcluded(self): if self.origin: Utils.mark_pkg(self.origin,'EXCLUDED')