summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fever/commons.py85
-rw-r--r--fever/fev.py47
-rw-r--r--fever/fever.py113
3 files changed, 245 insertions, 0 deletions
diff --git a/fever/commons.py b/fever/commons.py
new file mode 100644
index 0000000..c44fcc2
--- /dev/null
+++ b/fever/commons.py
@@ -0,0 +1,85 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+
+# fever - by Michał Bentkowski 2007
+# licensed under GPL
+
+# this file contains a few functions not direct related with fever,
+# but fever can't work without them.
+
+# I decided to split it because the main file would be too inlegible
+
+import re
+import tempfile
+import sys
+import urllib
+
+def unit(number):
+ """Changes bytes unit to more legible one"""
+ mp=1024
+ prefixes="","k","M","G","T" # probably we don't need more ones :-)
+ for (p, i) in zip(prefixes, map(lambda x: mp**x, xrange(len(prefixes)))):
+ x=float(number)/i
+ if x < mp:
+ return "%0.2f %sB" % (x,p)
+
+def download(url,verbose=False):
+ """Downloads specified URL. Returns its content"""
+ block_size=10240
+ temp=tempfile.TemporaryFile()
+ file=urllib.urlopen(url)
+ try:
+ filesize=" of "+unit(long(file.headers["content-length"]))
+ except KeyError:
+ filesize=""
+ block=file.read(block_size)
+ bytes=0
+ while block != "":
+ bytes+=len(block)
+ temp.write(block)
+ if verbose:
+ sys.stdout.write("\rDownloading %s... %s%s" % (file.url[:40], unit(bytes), filesize))
+ sys.stdout.flush()
+ block=file.read(block_size)
+ if verbose: print "\nDownloaded!"
+ temp.seek(0)
+ return temp.read()
+
+def rpmvercmp(a, b):
+ """ Comparing algorithm based on original rpmvercmp """
+ a,b=map(re.split,("[\W_]+|(\d+)",)*2,(str(a),str(b))) # split versions strings according to rpm version
+ # comparing algorithm
+ a,b=map(lambda x: [elem for elem in x if elem not in (None, "")],[a,b]) # and remove empty
+ # elements
+ for elem_a, elem_b in zip(a,b):
+ try:
+ elem_a=int(elem_a)
+ except ValueError:
+ pass
+ try:
+ elem_b=int(elem_b)
+ except ValueError:
+ pass
+ elem_a_type,elem_b_type=map(type,(elem_a,elem_b))
+ if elem_a_type != elem_b_type:
+ if elem_a_type == int:
+ return 1
+ else:
+ return -1
+ elif (elem_a_type, elem_b_type) == (int,)*2:
+ compare=cmp(int(elem_a),int(elem_b))
+ if compare != 0:
+ return compare
+ else:
+ compare=cmp(elem_a, elem_b)
+ if compare != 0:
+ return compare
+ return cmp(len(a),len(b))
+def vercmpsort(List):
+ """Sorting based on an rpmvercmp algorithm"""
+ for indexes in range(len(List)-1, 0, -1):
+ for index in range(indexes):
+ if rpmvercmp(List[index],List[index+1]) == 1:
+ List[index],List[index+1]=List[index+1],List[index]
+ List.reverse()
+ return List \ No newline at end of file
diff --git a/fever/fev.py b/fever/fev.py
new file mode 100644
index 0000000..94b79a0
--- /dev/null
+++ b/fever/fev.py
@@ -0,0 +1,47 @@
+import fever
+import xmlrpclib
+
+statuses=['NEW', 'VERIFIED', 'ASSIGNED', 'REOPENED', 'CLOSED', 'NEEDINFO', 'MODIFIED', 'ON_DEV', 'UNCONFIRMED', 'ON_QA', 'FAILS_QA', 'NEEDINFO_REPORTER', 'RELEASE_PENDING', 'POST']
+
+username="a@b.pl"
+password="adf"
+
+Summary="""%s-%s is available"""
+Comment="""%s-%s is already available. Repo version is %s.
+Please update the package.
+
+If you have any questions or suggestions related to Fever,
+feel free to write them in this bug or have a look at
+http://fedoraproject.org/wiki/PackageMaintainers/FEver
+
+Don't send any messages to fevapp at o2.pl please.
+
+"""
+
+url='http://bugzilla.redhat.com/bugzilla/xmlrpc.cgi'
+
+fev=fever.Fever(2)
+fev.checkAllPackages()
+x=fev.listNotUpToDate()
+notuptodate=[]
+for elem in x:
+ elem=elem.items()
+ notuptodate.append( (elem[0][0],False,elem[0][1]['sitever'],elem[0][1]['kojiver']))
+
+print notuptodate
+
+server=xmlrpclib.Server(url)
+fevbugs=server.bugzilla.runQuery({'emailreporter2': 1, 'email2': username, 'bug_status': statuses})
+descriptions=[elem['short_short_desc'] for elem in fevbugs['bugs']]
+for (name, uptodate, aversion, rversion) in notuptodate:
+ summary=Summary % (name,aversion)
+ if summary in descriptions:
+ print "New version of %s has been already submitted" % name
+ continue
+ comment=Comment % (name, aversion, rversion)
+ res = server.bugzilla.createBug({"comment": comment, "short_desc": summary,
+ 'product': 'Fedora', 'component': name,
+ 'rep_platform':'All', 'bug_severity': "medium",
+ 'version': 'devel','op_sys':'Linux',
+ 'priority': 'normal', 'bug_file_loc': 'http://fedoraproject.org/wiki/Micha%C5%82Bentkowski/FEver' }, username, password)
+ print "Bug %s created!" % res[0]
diff --git a/fever/fever.py b/fever/fever.py
new file mode 100644
index 0000000..5fdd690
--- /dev/null
+++ b/fever/fever.py
@@ -0,0 +1,113 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+
+# Fever - by Michał Bentkowski 2007
+# licensed under GPL
+
+# first, let's do some koji things
+import koji
+session=koji.ClientSession("http://koji.fedoraproject.org/kojihub")
+
+# now, import the other things we need
+
+from commons import download, rpmvercmp, vercmpsort
+import re
+from xml.sax.saxutils import unescape
+
+#set timeout TODO: should be set in config file
+import socket
+socket.setdefaulttimeout(45)
+
+import sys
+
+class Fever:
+ def __init__(self, debug=0,
+ listformat="\* (?P<name>.*?) (?P<regex>.*) (?P<url>.*?)\n",
+ listlocation="http://fedoraproject.org/wiki/PackageMaintainers/FEver"):
+ self.debug=debug
+ #self.listformat=listformat
+ #self.lislocation=listlocation
+ # it's sane to download a site with a list of packages at once
+ site=download(listlocation, debug)
+ # and let's parse it!
+ self.pkglist={} # this var will keep all info of packages
+ for package in re.finditer(listformat, site):
+ dict=package.groupdict() #retrieve dictionary with name regex and url
+ name=dict['name']
+ del dict['name'] # we don't need name in dict anymore
+ # sometimes there are escaped chars like &lt; in regex
+ # so we need to unescape them first
+ dict['regex']=unescape(dict['regex'])
+ self.pkglist[name]=dict
+ self.pkglist[name]['checked']=False
+ if debug >= 2:
+ print "%s parsed. Data: %s" % (name,dict)
+
+ def getPkgSiteVersion(self,pkgname):
+ # download a proper site and get a package version
+ site=download(self.pkglist[pkgname]['url'], self.debug)
+ regex=self.pkglist[pkgname]['regex']
+ versions=vercmpsort( re.findall(regex, site) ) # find all versions and sort'em
+ return versions[0] # we need only the newest one
+
+ def getPkgKojiVersion(self, pkgname):
+ # first, we need koji's package id
+ pkgid=session.getPackageID(pkgname)
+ # now, list all builds
+ builds=session.listBuilds(pkgid)
+ # extract all versions and sort'em
+ versions=vercmpsort( [x['version'] for x in session.listBuilds(pkgid)])
+ return versions[0] # return the newest one
+
+ def getPkgList(self):
+ return self.pkglist
+
+ def getPkgInfo(self, pkgname):
+ return self.pkglist[pkgname]
+
+ def checkPackage(self, pkgname):
+ # this is probably the most important function,
+ # it checks if repo version is newer than the available one.
+ # Returns 0 if versions match or koji version is newer than site version
+ # (it may happen if there's something wrong with regex) and 1 if a package's
+ # owner need to update his package, -1 - if error.
+ if self.debug >= 1:
+ print 'Checking %s...' % pkgname
+ try:
+ sitever=self.getPkgSiteVersion(pkgname)
+ kojiver=self.getPkgKojiVersion(pkgname)
+ except:
+ # if no version were found, we don't need this package anymore
+ if self.debug >= 1:
+ print "%s won't be checked. Error. %s" % (pkgname, str(sys.exc_info()))
+ self.pkglist[pkgname]['checked']=False
+ return -1
+ if self.debug >= 2:
+ print '%s: koji: %s; site: %s' % (pkgname, kojiver, sitever)
+ compare=rpmvercmp(kojiver, sitever)
+ self.pkglist[pkgname]['kojiver']=kojiver
+ self.pkglist[pkgname]['sitever']=sitever
+ self.pkglist[pkgname]['checked']=True
+ if compare == -1: #if a newer version's available
+ self.pkglist[pkgname]['uptodate']=False
+ return 1
+ else: # if isn't
+ self.pkglist[pkgname]['uptodate']=True
+ return 0
+
+ def checkAllPackages(self):
+ # simple loop to check all packages at once.
+ for package in self.pkglist.keys():
+ result=self.checkPackage(package)
+
+ def isPackageUpToDate(self,pkgname):
+ # just check if a given package is up to date
+ return self.pkglist[pkgname]['uptodate']
+
+ def listUpToDate(self):
+ # list all up-to-date packages
+ return [dict([(k,v)]) for k,v in self.pkglist.iteritems() if v['checked']==True and v['uptodate']==True]
+
+ def listNotUpToDate(self):
+ # list all not-up-to-date packages
+ return [dict([(k,v)]) for k,v in self.pkglist.iteritems() if v['checked']==True and v['uptodate']==False]