Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index


On Wed, 2012-04-25 at 15:51 +0200, Tomáš Chvátal wrote:
What I think we could do:
Provide some simple wiki page with links to latest versions + git.

I guess its worth a shot, e.g. you setting up the wiki page, fill it
with links to the "best" upstreams of various linguistic stuff, and
script something that tries to scrape out the latest versions of those
when they're bumped and/or someone adds something new to the page and
generate snapshot extensions or whatever out of the ones that don't come
in exactly the right format.

FWIW, here's my "is fedora up to date with the packages I maintain"
script which does some lunacy to try and make sensible upgradeable
name-version-revisions out of all the various upstream systems, lots of
the hunspell/hyphen/thesaurus stuff is listed there and their upstream
locations as best as I could figure out.

C.
#!/bin/env python
# vim: set fileencoding=utf-8 :
import re, socket, os, sys
from ftplib import FTP
from httplib import HTTPConnection
from HTMLParser import HTMLParser
from datetime import datetime
from time import strptime, strftime, localtime
import makenvr

fedoramirrors = []
#http://download.fedora.redhat.com/pub/fedora/linux/development/rawhide/source/SRPMS/
#fedoramirrors.append(('download.fedora.redhat.com', 
'/pub/fedora/linux/development/rawhide/source/SRPMS/'))
fedoramirrors.append(('ftp.heanet.ie', '/pub/fedora/linux/development/rawhide/source/SRPMS/'))
fedoramirrors.append(('ftp.fi.muni.cz', 
'/pub/linux/fedora/linux/development/rawhide/source/SRPMS/'))
fedoramirrors.append(('sunsite.mff.cuni.cz', 
'MIRRORS/fedora.redhat.com/linux/development/rawhide/source/SRPMS/'))

debug = 0

class MyHTMLParser(HTMLParser):
        def __init__(self):
                HTMLParser.__init__(self)
                self.data = ''
        def handle_data(self, data):
                self.data = self.data + data

def isreleaseid(number):
        bits = number.split('.')
        try:
                for bit in bits:
                        int(bit)
        except:
                return False
        return True
def getminor(key):
        bits = key.split('.')
        minor = int(bits[1])
        return minor
def sortbyurl(a, b):
        if a.host == b.host:
                return a.dir < b.dir
        return a.host < b.host
def sortkeys(a, b):
        return makenvr.compare_vr(a[0].lower(), b[0].lower(), a[1].lower(), b[1].lower())
class package:
        def __init__(self, style, srpmname, upstreamprjname='', upstreampkgname='', host='', 
dir='', pattern='', monthsdiff=0, datestring='', ispost=-1, fixrule=None):
                self.style = style
                self.name = srpmname
                if upstreamprjname == '':
                        self.upstreamprjname = srpmname
                else:
                        self.upstreamprjname = upstreamprjname
                if upstreampkgname == '':
                        self.upstreampkgname = self.upstreamprjname
                else:
                        self.upstreampkgname = upstreampkgname
                self.host = host
                self.dir = dir
                self.pattern = pattern
                self.monthsdiff = monthsdiff
                self.datestring = datestring
                self.ispost = ispost
                self.fixrule = fixrule

droppedlist = []

firstcol = 37
secondcol = 29

def alignit(name, count):
    for i in range(len(name), count):
        name = name + ' '
    print name, ':',

ftplist = []

def collector(line = ''):
    global ftplist
    if debug: print 'ftpline is', line 
    ftplist.append(line)

class packagemanager:
        def __init__(self, packagelist):
                self.keys = {}
                for package in packagelist:
                        if not self.keys.has_key(package.style):
                                self.keys[package.style] = []
                        self.keys[package.style].append(package)

                for key in self.keys:
                        packages = self.keys[key]
                        packages.sort(sortbyurl)
                        self.keys[key] = packages

                for mirror in fedoramirrors:
                        try:
                                self.ftp = FTP(mirror[0])
                                self.ftp.login()
                                self.srpmlist = []

                                print "collecting srpms", 
#use koji -q latest-pkg rawhide foo bar baz
                                sys.stdout.flush()
                                for letter in range(ord('a'), ord('z')):
                                        print chr(letter),
                                        sys.stdout.flush()
                                        self.ftp.cwd(mirror[1]+chr(letter))
                                        self.srpmlist = self.srpmlist + self.ftp.nlst()
                                print
                                print "Fedora Mirror:", mirror[0]
                                sys.stdout.flush()
                                break
                        except:
                                print "Skipping:", mirror[0], "because", sys.exc_info()[1]
                                pass
        def latestsrpm(self, pack):
                releases = []
                for entry in self.srpmlist:
                        nameprefix = pack.name + '-'
                        prefix = nameprefix
                        if entry[:len(prefix)] == prefix:
                                        rpmname, rpmversion, rpmrelease = makenvr.get_nvr(entry, 
pack.ispost)
                                        if rpmname == pack.name:
                                                rpmrelease = makenvr.scrub_disttag(rpmrelease)
                                                rpmrelease = makenvr.undo_prerelease(rpmrelease)
                                                releases.append((rpmversion, rpmrelease))
                keys = self.cleanandsort(releases)
                if len(keys):
                        return keys[0]
                return None
        def fetch(self):
                for key in self.keys:
                        try:
                                if key == 'gnome':
#                                       self.ftp = FTP('ftp.acc.umu.se')
                                        self.ftp = FTP('ftp.heanet.ie')
                                        self.ftp.login()
                                        for package in self.keys[key]:
                                                try:
                                                        latest = self.latestsrpm(package)
                                                        if latest:
                                                                
alignit(package.name+'-'+latest[0]+'-'+latest[1], firstcol)
                                                                self.getgnomelatest(package, latest)
                                                        else:
                                                                droppedlist.append(package.name);
                                                except:
                                                        print 'ERROR fetching:', package.name, 
'from'
                                                        print '  
ftp://ftp.heanet.ie'+'/mirrors/ftp.gnome.org/sources/' +\
                                                                pack.upstreampkgname
                                                        print '  error is:', sys.exc_info()[0], 
sys.exc_info()[1]
                                elif key == 'sourceforge':
#                                       self.ftp = FTP('ftp.heanet.ie')
                                        self.ftp = FTP('www.mirrorservice.org')
                                        self.ftp.login()
                                        for package in self.keys[key]:
                                                try:
                                                        latest = self.latestsrpm(package)
                                                        if latest:
                                                                
alignit(package.name+'-'+latest[0]+'-'+latest[1], firstcol)
                                                                self.getsourceforgelatest(package, 
latest)
                                                        else:
                                                                droppedlist.append(package.name);
                                                except:
                                                        print 'ERROR fetching:', package.name, 
'from'
                                                        print '  
ftp://www.mirrorservice.org'+self.getsourceforgedir(package)
                                                        print '  error is:', sys.exc_info()[0], 
sys.exc_info()[1]
                                elif key == 'ftp':
                                        lasthost = ''
                                        for package in self.keys[key]:
                                                try:
                                                        if package.host != lasthost:
                                                                self.ftp = FTP(package.host)
                                                                self.ftp.login()
                                                                lasthost = package.host

                                                        self.ftp.cwd(package.dir)
        
                                                        dirlist = self.ftp.nlst()
                                                        dirlist = self.dofixrule(dirlist, package)
        
                                                        #print dirlist
        
                                                        latest = self.latestsrpm(package)
                                                        if latest:
                                                                
alignit(package.name+'-'+latest[0]+'-'+latest[1], firstcol)
                                                                
self.getsimplelatest(package.upstreampkgname, latest, dirlist, package.ispost, False)
                                                        else:
                                                                droppedlist.append(package.name);
                                                except:
                                                        print 'ERROR fetching:', package.name, 
'from'
                                                        print '  ftp://'+package.host+package.dir
                                                        print '  error is:', sys.exc_info()[0], 
sys.exc_info()[1]
                                elif key == 'http-regexp':
                                        lasthost = ''
                                        lastdir = ''
                                        conn = None
                                        for package in self.keys[key]:
                                                try:
                                                        if debug: print package.host, package.dir

                                                        if package.host != lasthost:
                                                                conn = HTTPConnection(package.host)

                                                        if package.host != lasthost or package.dir 
!= lastdir:
                                                                headers = {"User-Agent": 
"latestpackages/1.0.0"}
                                                                conn.request("GET", package.dir, 
headers=headers)
                                                                response = conn.getresponse()
                                                                data = response.read().splitlines()

                                                        lasthost = package.host
                                                        lastdir = package.dir

                                                        if debug: print data

                                                        p = re.compile(package.pattern)

                                                        dirlist = []
                                                        for line in data:
                                                                try:
                                                                        for m in re.finditer(p, 
line):
                                                                                if debug: print 
'MATCH', line
                                                                                result = m.group(1)
                                                                                if 
len(package.datestring):
                                                                                        dttm = 
datetime(*strptime(result, package.datestring)[0:6])
                                                                                        if 
dttm.year == 1900:
                                                                                                
dttm = datetime(datetime.today().year, \
                                                                                                    
    dttm.month, dttm.day)
                                                                                        result = 
dttm.strftime("%Y%m%d")
                                                                                                
                                                                                
dirlist.append(package.upstreampkgname+'-'+result+'.tar.gz')
                                                                except:
                                                                        pass

                                                        dirlist = self.dofixrule(dirlist, package)
                                                        if debug: print dirlist

                                                        latest = self.latestsrpm(package)
                                                        if latest:
                                                                
alignit(package.name+'-'+latest[0]+'-'+latest[1], firstcol)
                                                                
self.getsimplelatest(package.upstreampkgname, latest, dirlist, \
                                                                        package.ispost, False, 
package.monthsdiff)
                                                        else:
                                                                droppedlist.append(package.name);
                                                except:
                                                        print 'ERROR fetching:', package.name, 
'from'
                                                        print '  http://'+package.host+package.dir
                                                        print '  error is:', sys.exc_info()[0], 
sys.exc_info()[1]
                                elif key == 'http-last-modified':
#                                       lasthost = ''
                                        conn = None
                                        for package in self.keys[key]:
                                                try:
                                                        if debug: print package.dir

#                                                       if package.host != lasthost:
                                                        conn = HTTPConnection(package.host)
#                                                               lasthost = package.host

                                                        headers = {"User-Agent": 
"latestpackages/1.0.0"}
                                                        conn.request("GET", package.dir, 
headers=headers)
                                                        response = conn.getresponse()

                                                        s = response.getheader('last-modified')
                                                
                                                        if debug: print s

                                                        dirlist = []

                                                        result = datetime(*strptime(s, "%a, %d %b 
%Y %H:%M:%S %Z")[0:6])
                                                        datestring = result.strftime("%Y%m%d")
                                                        
dirlist.append(package.upstreampkgname+'-'+datestring+'.tar.gz')

                                                        latest = self.latestsrpm(package)
                                                        if latest:
                                                                
alignit(package.name+'-'+latest[0]+'-'+latest[1], firstcol)
                                                                
self.getsimplelatest(package.upstreampkgname, latest, dirlist, \
                                                                        package.ispost, False, 
package.monthsdiff)
                                                        else:
                                                                droppedlist.append(package.name);
                                                except:
                                                        print 'ERROR fetching:', package.name, 
'from'
                                                        print '  http://'+package.host+package.dir
                                                        print '  error is:', sys.exc_info()[0], 
sys.exc_info()[1]
                                elif key == 'ftp-last-modified':
                                        global ftplist
                                        lasthost = ''
                                        for package in self.keys[key]:
                                                try:
                                                        if package.host != lasthost:
                                                                self.ftp = FTP(package.host)
                                                                self.ftp.login()
                                                                lasthost = package.host

                                                        dirlist = []

                                                        pattern = r'.*?(... .\d  \d\d\d\d)'
                                                        p = re.compile(pattern)

                                                        pattern2 = r'.*? (... .\d )'
                                                        p2 = re.compile(pattern2)


                                                        ftplist = []
                                                        self.ftp.dir(package.dir, collector)

                                                        for line in ftplist:
                                                                m = p.match(line)
                                                                if m:
                                                                        result = 
datetime(*strptime(m.group(1), "%b %d  %Y")[0:6])
                                                                        datestring = 
result.strftime("%Y%m%d")
                                                                        
dirlist.append(package.upstreampkgname+'-'+datestring+'.tar.gz')
                                                                else:
                                                                        m = p2.match(line)
                                                                        if m:
                                                                                try:
                                                                                        result = 
datetime(*strptime(m.group(1), "%b %d ")[0:6])
                                                                                        result = 
datetime(datetime.today().year, \
                                                                                                
result.month, result.day)
                                                                                        datestring 
= result.strftime("%Y%m%d")
                                                                                        
dirlist.append(package.upstreampkgname+'-'+datestring+'.tar.gz')
                                                                                except:
                                                                                        pass

                                                        if debug: print 'dirlist is now', dirlist

                                                        latest = self.latestsrpm(package)
                                                        if latest:
                                                                
alignit(package.name+'-'+latest[0]+'-'+latest[1], firstcol)
                                                                
self.getsimplelatest(package.upstreampkgname, latest, dirlist, package.ispost, False)
                                                        else:
                                                                droppedlist.append(package.name);
                                                except:
                                                        print 'ERROR fetching:', package.name, 
'from'
                                                        print '  ftp://'+package.host+package.dir
                                                        print '  error is:', sys.exc_info()[0], 
sys.exc_info()[1]
                                elif key == 'svn-propget-date':
                                        for package in self.keys[key]:
                                                try:
                                                        #print package.dir

                                                        if package.dir[-1] == '/':
                                                                cmd = 'svn propget --revprop -rHEAD 
svn:date https://' + package.host + \
                                                                        package.dir
                                                                fd = os.popen(cmd, "r")
                                                                s = fd.readline()[:-1]
                                                        else:
                                                                cmd = 'svn ls --xml --depth empty 
https://' + package.host + \
                                                                        package.dir + '|grep 
date|sed -e "s/<date>//g"|sed -e "s/<\/date>//g"'
                                                                fd = os.popen(cmd, "r")
                                                                s = fd.readline()[:-1]

                                                        dirlist = []

                                                        s = s.split('.')[0]
                                                        result = datetime(*strptime(s, 
"%Y-%m-%dT%H:%M:%S")[0:6])
                                                        datestring = result.strftime("%Y%m%d")

                                                        if package.dir[-1] == '/': #temp hack
                                                            
dirlist.append(package.upstreampkgname+'-'+datestring+'.tar.gz')
                                                        else:
                                                                
dirlist.append(package.upstreampkgname+'-'+datestring+'svn.tar.gz')

                                                        latest = self.latestsrpm(package)
                                                        if latest:
                                                                
alignit(package.name+'-'+latest[0]+'-'+latest[1], firstcol)
                                                                
self.getsimplelatest(package.upstreampkgname, latest, dirlist, \
                                                                        package.ispost, False, 
package.monthsdiff)
                                                        else:
                                                                droppedlist.append(package.name);
                                                except:
                                                        print 'ERROR fetching:', package.name, 
'from'
                                                        print '  http://'+package.host+package.dir
                                                        print '  error is:', sys.exc_info()[0], 
sys.exc_info()[1]

                        except socket.error:
                                for package in self.keys[key]:
                                        print 'TIMEOUT fetching', package.name
                        except:
                                print 'Oops!', sys.exc_info()[0]
                                for package in self.keys[key]:
                                        print 'ERROR fetching', package.name

        def cleanandsort(self, keys):
                if debug: print 'candidate keys are', keys
                keys.sort(sortkeys)
                keys.reverse()
                return keys
        def getgnomelatest(self, pack, latest):
                self.ftp.cwd('/mirrors/ftp.gnome.org/sources/' + pack.upstreampkgname)
#               self.ftp.cwd('/pub/GNOME/sources/' + pack.upstreampkgname)
                dirlist = self.ftp.nlst()
                vrs = []
                for entry in dirlist:
                        vrs.append((entry,'1'))
                keys = self.cleanandsort(vrs)
                result = 'Upstream '
                for key in keys:
                        minor = getminor(key[0])
                        self.ftp.cwd(key[0])
                        dirlist = self.ftp.nlst()
                        dirlist = self.dofixrule(dirlist, pack)
                        ret = "NONE!"
                        for file in dirlist:
                                if len(file) > 10 and file[0:10] == 'LATEST-IS-':
                                        ret = file[10:]
                                        break
                        if not minor % 2:
                                result = result + str(ret)+'-1'
                                alignit(result, secondcol)
                                if sortkeys(latest, (ret,'1')) < 0:
                                        print 'NOT UPTODATE'
                                else:
                                        print 'UpToDate'
                                break
                        self.ftp.cwd('..')
        def latestkey(self, keys, latestsrpm, monthsdiff=0):
                if len(keys) == 0:
                        alignit('MISSING', secondcol)
                        print
                else:
                        result = 'Upstream '
                        for key in keys:
                                result = result + key[0]+'-'+key[1]
                                old = False
                                alignit(result, secondcol)
                                if sortkeys(latestsrpm, key) < 0:
                                        old = True
                                        if monthsdiff != 0:
                                                srpmvr = latestsrpm[0]+'-'+latestsrpm[1]
                                                upstreamvr = key[0]+'-'+key[1]
                                                pattern = r'.*?(\d\d\d\d\d\d\d\d)'
                                                p = re.compile(pattern)
                                                m = p.match(srpmvr)
                                                if m:
                                                        srpmdate = m.group(1)
                                                m = p.match(upstreamvr)
                                                if m:
                                                        upstreamdate = m.group(1)

                                                latestyear = int(srpmdate[-8:-4])
                                                latestmonth = int(srpmdate[-4:-2])
                                                for i in range(0, monthsdiff):
                                                        if latestmonth == 12:
                                                                latestyear = latestyear + 1 
                                                                latestmonth = 1
                                                        else:
                                                                latestmonth = latestmonth + 1 

                                                theday = int(srpmdate[-2:])
                                                while (1):
                                                        try:
                                                                srpmvaliduntil = 
datetime(latestyear, latestmonth, \
                                                                        theday)
                                                                break
                                                        except ValueError:
                                                                theday = theday - 1
                                                                pass

                                                upstreamdt = datetime(int(upstreamdate[-8:-4]), 
int(upstreamdate[-4:-2]), \
                                                        int(upstreamdate[-2:]))

                                                if debug: print 'allowing difference of', 
monthsdiff, 'month between', \
                                                        srpmvaliduntil, 'and', upstreamdt

                                                if upstreamdt < srpmvaliduntil:
                                                        old = False
                                if old:
                                        print 'NOT UPTODATE'
                                else:
                                        print 'UpToDate'
                                break
        def getsimplelatest(self, name, latest, dirlist, ispost, strict = True, monthsdiff=0):
                blacklistwords = ['win32', 'MinGW', 'Darwin', 'MSVC', 'hunspell_UNO', 'cs.net', 
'or.newer', 'or_newer']
                releases = []
                for sep in ['-', '_', '.']:
                        for entry in dirlist:
                                nameprefix = name + sep
                                prefix = nameprefix

                                if debug: print 'entry is', entry
                                if debug: print 'prefix is', prefix

                                if entry[:len(prefix)] == prefix:
                                        skip = False
                                        for word in blacklistwords:
                                                if entry.find(word) != -1:
                                                        skip = True
                                                        break
                                        if skip:
                                                continue
                                        try:
                                                dummyname, version, release = 
makenvr.make_nvr(entry, '', ispost)
                                                releases.append((version, release))
                                        except makenvr.NVRException:
                                                pass


                keys = self.cleanandsort(releases)
                self.latestkey(keys, latest, monthsdiff)
        def getsourceforgedir(self, pack):
                return '/sites/download.sourceforge.net/pub/sourceforge/' + pack.upstreamprjname[0] 
+ '/project/' + \
                        pack.upstreamprjname[0:2] + '/' + pack.upstreamprjname + '/' + 
pack.upstreampkgname + '/'
        def dofixrule(self, dirlist, pack):
                if not pack.fixrule:
                        return dirlist
                newdirlist = []
                for e in dirlist:
                        newdirlist.append(re.sub(pack.fixrule[0], pack.fixrule[1], e))
                return newdirlist
        def getsourceforgelatest(self, pack, latest):
                self.ftp.cwd(self.getsourceforgedir(pack))

                dirlist = self.ftp.nlst()
                dirlist = self.dofixrule(dirlist, pack)
                vrs = []
                for entry in dirlist:
                        for sep in ['-', '_', '.']:
                                prefix = pack.upstreampkgname + sep
                                if entry[:len(prefix)] == prefix:
                                        entry = entry[len(prefix):]
                                        break

                        dummyname, version, release = makenvr.make_nvr(prefix+'-'+entry+'.tar.gz', 
'', pack.ispost)
                        vrs.append((version, release))
                keys = self.cleanandsort(vrs)


                result = 'Upstream '
                self.latestkey(keys, latest)

#               for key in keys:
#                       self.ftp.cwd(key[0])
#                       dirlist = self.ftp.nlst()
#                       dirlist = self.dofixrule(dirlist, pack)
#                       ret = "NONE!"
#                       result = result + str(ret)+'-1'
#                       alignit(result, secondcol)
#                       if sortkeys(latest, (ret,'1')) < 0:
#                               print 'NOT UPTODATE'
#                       else:
#                               print 'UpToDate'
#                       break
#                       self.ftp.cwd('..')
#
#
#               dirlist = self.ftp.nlst()
#               if debug: print 'dirlist is', dirlist
#               dirlist = self.dofixrule(dirlist, pack)
#               self.getsimplelatest(pack.upstreampkgname, latest, dirlist, pack.ispost, False)

packagelist = []
#http regexp
packagelist.append(package('http-regexp', 'hunspell-wa', 'aspell-wa', \
    'aspell-wa', 'chanae.walon.org', '/walon/aspell.php', \
    r'.*?href="aspell-wa-(.*?).tar.bz2">'))
packagelist.append(package('http-regexp', 'hunspell-uz', 'uzbek-wordlist', \
    'uzbek-wordlist', 'www-user.uni-bremen.de', '/~kmashrab/uzbek-word-list/', \
    r'.*?href="uzbek-wordlist-(.*?).tar.bz2">'))
packagelist.append(package('http-regexp', 'hunspell-sq', 'myspell-sq_AL', \
    'myspell-sq_AL', 'www.shkenca.org', '/k6i/albanian_dictionary_for_myspell_en.html', \
    r'.*?href="http://www.shkenca.org/shkarkime/myspell-sq_AL-(.*?).zip">'))
packagelist.append(package('http-regexp', 'hunspell-mi', 'hunspell-mi', \
    'hunspell-mi', 'packages.papakupu.maori.nz', '/hunspell/', \
    r'.*?href="hunspell-mi-(.*?).tar.gz">'))
packagelist.append(package('http-regexp', 'hyphen-mi', 'hyphen-mi', \
    'hyphen-mi', 'packages.papakupu.maori.nz', '/hunspell-hyphen/', \
    r'.*?href="hunspell-hyphen-mi-(.*?).tar.gz">'))
packagelist.append(package('http-regexp', 'mythes-mi', 'mythes-mi', \
    'mythes-mi', 'packages.papakupu.maori.nz', '/mythes/', \
    r'.*?href="mythes-mi-(.*?).tar.gz">'))
packagelist.append(package('http-regexp', 'mythes-ne', 'mythes-ne', \
    'mythes-ne', 'hg.services.openoffice.org', 
'/hg/DEV300/raw-file/tip/dictionaries/ne_NP/README_th_ne_NP_v2.txt', \
    r'.*?Release (.*?) '))
packagelist.append(package('http-regexp', 'hunspell-fur', 'myspell-fur', \
    'myspell-fur', 'digilander.libero.it', '/paganf/coretors/dizionaris.html', \
    r'.*?href="myspell-fur-(.*?).zip">'))
packagelist.append(package('http-regexp', 'fribidi', 'fribidi', \
    'fribidi', 'fribidi.org', '/download/', \
    r'.*?href="fribidi-(.*?).tar.gz">'))
packagelist.append(package('http-regexp', 'libexttextcat', 'libexttextcat', \
    'libexttextcat', 'dev-www.libreoffice.org', '/src/libexttextcat/', \
    r'.*?href="libexttextcat-(.*?).tar.gz">'))
packagelist.append(package('http-regexp', 'libvisio', 'libvisio', \
    'libvisio', 'dev-www.libreoffice.org', '/src/', \
    r'.*?href="libvisio-(.*?).tar.bz2">'))
packagelist.append(package('http-regexp', 'sac', 'sac', \
    'sac', 'www.w3.org', '/Style/CSS/SAC/', \
    r'.*?sacjava-(.*?).zip'))
packagelist.append(package('http-regexp', 'agg', 'agg', \
    'agg', 'www.antigrain.com', '/download/', \
    r'.*?http://www.antigrain.com/agg-(.*?).tar.gz'))
packagelist.append(package('http-regexp', 'icu', 'icu', \
    'icu', 'site.icu-project.org', '/download/', \
    r'.*?#ICU4C".*?>(.*?)<'))
packagelist.append(package('http-regexp', 'hunspell-ga', 'ispell-gaeilge', \
    'ispell-gaeilge', 'borel.slu.edu', '/ispell/sios.html', \
     r'.*?ispell-gaeilge-(.*?).tar.gz'))
packagelist.append(package('http-regexp', 'hunspell-sk', 'hunspell-sk', \
    'hunspell-sk', 'www.sk-spell.sk.cx', '/hunspell-sk', \
     r'.*?hunspell-sk-(\d\d\d\d\d\d\d\d).zip'))
packagelist.append(package('http-regexp', 'hunspell-da', 'myspell-da', \
    'myspell-da', 'da.speling.org', '/filer/', \
     r'.*?a href="myspell-da-(.*?).tar.gz">'))
packagelist.append(package('http-regexp', 'hunspell-fo', 'myspell-fo', \
    'myspell-fo', 'fo.speling.org', '/filer/', \
     r'.*?a href="myspell-fo-(.*?).tar.gz">'))
packagelist.append(package('http-regexp', 'hyphen-hu', 'huhyphn', \
    'huhyphn', 'www.tipogral.hu', '/', \
     r'.*?hungarian hyphenation patterns v(.*?)</tt>'))
packagelist.append(package('http-regexp', 'hunspell-ur', 'UrduDictionary', \
    'UrduDictionary', 'urdudictionary.codeplex.com', '/', \
     r'.*?>Release (.*?)<'))
packagelist.append(package('http-regexp', 'hunspell-af', 'dict_af', \
    'dict_af', 'extensions.services.openoffice.org', '/project/dict_af', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-nr', 'dict-nr', \
    'dict-nr', 'extensions.services.openoffice.org', '/project/dict-nr', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-ss', 'dict-ss', \
    'dict-ss', 'extensions.services.openoffice.org', '/project/dict-ss', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-st', 'dict-st', \
    'dict-st', 'extensions.services.openoffice.org', '/project/dict-st', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-ts', 'dict-ts', \
    'dict-ts', 'extensions.services.openoffice.org', '/project/dict-ts', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-tn', 'dict-tn', \
    'dict-tn', 'extensions.services.openoffice.org', '/project/dict-tn', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-ve', 'dict-ve', \
    'dict-ve', 'extensions.services.openoffice.org', '/project/dict-ve', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-xh', 'dict-xh', \
    'dict-xh', 'extensions.services.openoffice.org', '/project/dict-xh', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-nso', 'dict-ns_ZA', \
    'dict-ns_ZA', 'extensions.services.openoffice.org', '/project/dict-nso', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-zu', 'dict-zu', \
    'dict-zu', 'extensions.services.openoffice.org', '/project/dict-zu', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-de', 'igerman98', \
    'igerman98', 'www.j3e.de', '/ispell/igerman98/dict/', \
     r'.*?<a href="igerman98-(.*?).tar'))
packagelist.append(package('http-regexp', 'hunspell-nl', 'opentaal', \
    'opentaal', 'www.opentaal.org', '/bestanden', \
     r'.*?Woordenlijst v (.*?) '))
packagelist.append(package('http-regexp', 'mythes-en', 'WordNet', \
    'WordNet', 'wordnet.princeton.edu', '/download/', \
     r'.*?WordNet-(.*?).tar.bz2'))
packagelist.append(package('http-regexp', 'hunspell-sv', 'dsso', \
    'dsso', 'dsso.se', '/download.html', \
     r'.*?>dsso-(.*?).txt<'))
packagelist.append(package('http-regexp', 'mythes-sk', 'mythes-sk', \
    'mythes-sk', 'www.sk-spell.sk.cx', '/thesaurus/faq.php', \
     r'.*?OpenOffice.org 2.x.*?generovan.*?(\d\d\d\d-\d\d-\d\d)', 1))
packagelist.append(package('http-regexp', 'mythes-de', 'mythes-de', \
    'mythes-de', 'www.openthesaurus.de', '/about/download', \
     r'.*?(\d\d\d\d-\d\d-\d\d)', 1))
packagelist.append(package('http-regexp', 'mythes-es', 'mythes-es', \
    'mythes-es', 'openthes-es.berlios.de', '/index.php', \
     r'.*?(\d\d\d\d-\d\d-\d\d)\)', 1))
packagelist.append(package('http-regexp', 'mythes-sl', 'mythes-sl', \
    'mythes-sl', '193.2.66.133:85', '/index.php', \
     r'.*?(\d\d\d\d-\d\d-\d\d)\)', 1))
packagelist.append(package('http-regexp', 'mythes-nl', 'mythes-nl', \
    'mythes-nl', 'data.opentaal.org', '/opentaalbank/thesaurus/', \
     r'.*?(\d\d\d\d-\d\d-\d\d)\)', 1))
packagelist.append(package('http-regexp', 'hunspell-et', 'ispell-et', \
    'ispell-et', 'www.meso.ee', '/~jjpp/speller/', \
     r'.*?ispell-et_(\d\d\d\d\d\d\d\d).*'))
packagelist.append(package('http-regexp', 'hunspell-el', 'ispell-gr', \
    'ispell-gr', 'ispell.math.upatras.gr', '/?section=oofficespell&subsection=howto', \
     r'.*?OpenOffice Greek Dictionary v(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-pl', 'sjp-myspell-pl', \
    'sjp-myspell-pl', 'www.sjp.pl', '/slownik/en/', \
     r'.*?a href="http://sjp.pl/slownik/ort/sjp-myspell-pl-(\d\d\d\d\d\d\d\d).zip"', 1))
#packagelist.append(package('http-regexp', 'hunspell-km', 'khmersbbic', \
#    'khmersbbic', 'extensions.services.openoffice.org', '/project/khmersbbic', \
#     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)
packagelist.append(package('http-regexp', 'hunspell-pt', 'pt_BR', \
    'pt_BR', 'www.broffice.org', '/verortografico/baixar/', \
     r'.*?files/pt_BR-(\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-pt', 'pt_PT', \
    'pt_PT', 'natura.di.uminho.pt', '/download/sources/Dictionaries/hunspell/', \
     r'.*?hunspell-pt_PT-(\d\d\d\d\d\d\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-vi', 'hunspell-spellcheck-vi', \
    'hunspell-spellcheck-vi', 'code.google.com', \
    '/p/hunspell-spellcheck-vi/downloads/detail?name=vi_VN.zip', \
     r'.*?<span class="date" .*?>(.*?)</span>', False, "%b %d, %Y"))
packagelist.append(package('http-regexp', 'hunspell-en', 'en_GB', \
    'en_GB', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?en_GB.zip" rel="nofollow">English \(United Kingdom\)</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-rw', 'rw_RW', \
    'rw_RW', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?rw_RW.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-mg', 'mg_MG', \
    'mg_MG', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?mg_MG.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-id', 'id_ID', \
    'id_ID', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?id_ID.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-th', 'th_TH', \
    'th_TH', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?th_TH.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-sl', 'sl_SI', \
    'sl_SI', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?sl_SI.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-cy', 'cy_GB', \
    'cy_GB', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?cy_GB.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-ms', 'ms_MY', \
    'ms_MY', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?ms_MY.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-no', 'nb_NO', \
    'spell-norwegian', 'alioth.debian.org', '/frs/?group_id=30577', \
     r'.*?spell-norwegian-(.*?).tar.gz'))
packagelist.append(package('http-regexp', 'hunspell-mk', 'mk_MK', \
    'mk_MK', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?mk_MK.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-tl', 'tl_PH', \
    'tl_PH', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?tl_PH.zip" rel="nofollow">Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'mythes-cs', 'thes_cs_CZ_v2', \
    'thes_cs_CZ_v2', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?thes_cs_CZ_v2.zip" rel="nofollow">Thesaurus</a> .*? (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-sv', 'hyph_sv_SE', \
    'hyph_sv_SE', 'extensions.services.openoffice.org', '/node/1968', \
     r'.*?>Swedish hyphenation (.*?)</a>'))
packagelist.append(package('http-regexp', 'mythes-sv', 'SweThes', \
    'SweThes', 'extensions.services.openoffice.org', '/project/SweThes', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hyphen-ga', 'hyph_ga_IE', \
    'hyph_ga_IE', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_ga_IE.zip" rel="nofollow">Hyphenation</a> \(version .*?\) (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'mythes-ga', 'thes_ga_IE', \
    'thes_ga_IE', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?thes_ga_IE_v2.zip" rel="nofollow">Thesaurus</a> \(version .*?\) (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'mythes-el', 'thes_el_GR', \
    'thes_el_GR', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?th_el.zip" rel="nofollow">Thesaurus</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'mythes-ru', 'thes_ru_RU', \
    'thes_ru_RU', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?thes_ru_RU_v2.zip" rel="nofollow">Thesaurus</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-ru', 'hyph_ru_RU', \
    'hyph_ru_RU', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_ru_RU.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-pl', 'hyph_pl_PL', \
    'hyph_pl_PL', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_pl_PL.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-nl', 'hyph_nl_NL', \
    'hyph_nl_NL', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_nl_NL.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-de', 'hyph_de_DE', \
    'hyph_de_DE', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_de_DE.zip" rel="nofollow">German \(Germany\)</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-da', 'hyph_da_DK', \
    'hyph_da_DK', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_da_DK.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-it', 'hyph_it_IT', \
    'hyph_it_IT', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_it_IT.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-sl', 'hyph_sl_SI', \
    'hyph_sl_SI', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_sl_SI.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-sk', 'hyph_sk_SK', \
    'hyph_sk_SK', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_sk_SK.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-el', 'hyph_el_GR', \
    'hyph_el_GR', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_el_GR.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-es', 'hyph_es_ES', \
    'hyph_es_ES', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_es_ES.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-is', 'hyph_is_IS', \
    'hyph_is_IS', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_is_IS.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-id', 'hyph_id_ID', \
    'hyph_id_ID', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_id_ID.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-uk', 'hyph_uk_UA', \
    'hyph_uk_UA', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_uk_UA.zip" rel="nofollow">Hyphenation</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hyphen-pt', 'hyph_pt_PT', \
    'hyph_pt_PT', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?hyph_pt_PT.zip" rel="nofollow">.*? (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-ber', 'hunspell-am', \
    'hunspell-am', 'ayaspell.sourceforge.net', '/am.html', \
     r'.*?(\d\d\d\d-\d\d-\d\d) <a href="http'))
packagelist.append(package('http-regexp', 'hunspell-sc', 'dict-sc', \
    'dict-sc', 'extensions.services.openoffice.org', '/project/Dict_sc', \
     r'.*?Download.*?a href=.*?>(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-mn', 'mnSpell', \
    'mnSpell', 'extensions.services.openoffice.org', '/project/mnSpell', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-la', 'dict-la', \
    'dict-la', 'extensions.services.openoffice.org', '/project/dict-la', \
     r'.*?Download.*?a href=.*?>(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-sw', 'sw_TZ', \
    'sw_TZ', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?sw_TZ.*?Spelling</a> .*? (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-cop', 'copt_dict', \
    'copt_dict', 'extensions.services.openoffice.org', '/project/copt_dict', \
     r'.*?/node/4579">(.*?)</a>'))
packagelist.append(package('http-regexp', 'mythes-ca', 'thesaurus-ca', \
    'thesaurus-ca', 'extensions.services.openoffice.org', '/project/thesaurus-ca', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'mythes-da', 'danske_synonymer', \
    'danske_synonymer', 'extensions.services.openoffice.org', '/project/danske_synonymer', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-kk', 'dict-kk', \
    'dict-kk', 'extensions.services.openoffice.org', '/node/1172/release', \
     r'.*?This (.*?) release'))
packagelist.append(package('http-regexp', 'hunspell-tet', 'tet_ID', \
    'tet_ID', 'wiki.services.openoffice.org', '/wiki/Dictionaries', \
     r'.*?tet_ID.*?Spelling</a> (\d\d\d\d-\d\d-\d\d)'))
packagelist.append(package('http-regexp', 'hunspell-so', 'Alif-Higgaad-saxe', \
    'Alif-Higgaad-saxe', 'extensions.services.openoffice.org', '/project/Alif-Higgaad-saxe', \
    r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-sr', 'dict-sr', \
    'dict-sr', 'extensions.services.openoffice.org', '/project/dict-sr', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hyphen-ku', 'kitandin', \
    'kitandin', 'extensions.services.openoffice.org', '/project/kitandin', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-be', 'dict-be-official', \
    'dict-be-official', 'extensions.services.openoffice.org', '/project/dict-be-official', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hyphen-gl', 'hyphenation-gl', \
#    'hyphenation-gl', 'extensions.services.openoffice.org', 
'/project/Extension_Guionizador_galego_OOo', \
    'hyphenation-gl', 'extensions.services.openoffice.org', '/en/node/2014', \
#     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
     r'.*?<font color="black">(.*?) </font>'))
packagelist.append(package('http-regexp', 'hunspell-gd', 'gd_GB', \
    'gd_GB', 'extensions.services.openoffice.org', '/project/faclair-afb', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-br', 'Dict-br_Drouizig', \
    'Dict-br_Drouizig', 'extensions.services.openoffice.org', '/project/Dict-br_Drouizig', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-is', 'dict-is', \
    'dict-is', 'extensions.services.openoffice.org', '/project/dict-is', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hyphen-ca', 'ca_hyph', \
    'ca_hyph', 'extensions.services.openoffice.org', '/project/ca_hyph', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'mythes-hu', 'hu_dicts', \
    'hu_dicts', 'extensions.services.openoffice.org', '/project/hu_dicts', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-grc', 'grc', \
    'grc', 'extensions.services.openoffice.org', '/project/ancientgreekspellchecker', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-dsb', 'lower_sorbian_spelling_dictionary', \
    'lower_sorbian_spelling_dictionary', 'extensions.services.openoffice.org', 
'/project/HunSpellDic_dsb_DE', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-qu', 'qu_EC', \
    'qu_EC', 'extensions.services.openoffice.org', '/project/KichwaSpellchecker', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-ht', 'kok', \
    'kok', 'extensions.services.openoffice.org', '/project/kok', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-eo', 'literumilo', \
    'literumilo', 'extensions.services.openoffice.org', '/project/literumilo', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-ast', 'asturianu', \
    'asturianu', 'extensions.services.openoffice.org', '/project/asturianu', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-ny', 'chicspell', \
    'chicspell', 'extensions.services.openoffice.org', '/project/chicspell', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'writer2latex', 'writer2latex', \
    'writer2latex', 'extensions.services.openoffice.org', '/en/project/writer2latex', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-tpi', 'tok-pisin-spell-checker', \
    'tok-pisin-spell-checker', 'extensions.services.openoffice.org', 
'/en/project/tok-pisin-spell-checker', \
     r'.*?Download extension.*?<a href="/en/node/.*?">(.*?)</a>'))
packagelist.append(package('http-regexp', 'hunspell-cv', 'hunspell-cv', \
    'hunspell-cv', 'hunspell.chv.su', '/download.shtml', \
     r'.*?>dict-cv-(.*?).oxt</a>', fixrule=('-u','')))
packagelist.append(package('http-regexp', 'mythes-pt', 'thes_pt_PT_v2', \
    'thes_pt_PT_v2', 'openthesaurus.caixamagica.pt', '/', \
     r'.*?(\d\d\d\d-\d\d-\d\d)\)', 1))
packagelist.append(package('http-regexp', 'hyphen-tk', 'hyph-tk', \
    'hyph-tk', 'tug.org',
    '/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-tk.tex?view=log', \
    r'.*?<em>(.*) UTC</em>', datestring="%a %b %d %H:%M:%S %Y"))
packagelist.append(package('http-regexp', 'hyphen-mn', 'hyph-mn-cyrl', \
    'hyph-mn-cyrl', 'tug.org',
    '/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-mn-cyrl.tex?view=log', \
    r'.*?<em>(.*) UTC</em>', datestring="%a %b %d %H:%M:%S %Y"))
packagelist.append(package('http-regexp', 'hyphen-hsb', 'hyph-hsb', \
    'hyph-hsb', 'tug.org',
    '/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-hsb.tex?view=log', \
    r'.*?<em>(.*) UTC</em>', datestring="%a %b %d %H:%M:%S %Y"))
packagelist.append(package('http-regexp', 'hyphen-sa', 'hyph-sa', \
    'hyph-sa', 'tug.org',
    '/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-sa.tex?view=log', \
    r'.*?<em>(.*) UTC</em>', datestring="%a %b %d %H:%M:%S %Y"))
packagelist.append(package('http-regexp', 'hyphen-eu', 'hyph-eu', \
    'hyph-eu', 'tug.org',
    '/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-eu.tex?view=log', \
    r'.*?<em>(.*) UTC</em>', datestring="%a %b %d %H:%M:%S %Y"))
packagelist.append(package('http-regexp', 'hyphen-cy', 'hyph-cy', \
    'hyph-cy', 'tug.org',
    '/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-cy.tex?view=log', \
    r'.*?<em>(.*) UTC</em>', datestring="%a %b %d %H:%M:%S %Y"))
packagelist.append(package('http-regexp', 'hyphen-grc', 'hyph-grc', \
    'hyph-grc', 'tug.org',
    '/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-grc.tex?view=log', \
    r'.*?<em>(.*) UTC</em>', datestring="%a %b %d %H:%M:%S %Y"))
packagelist.append(package('http-regexp', 'hyphen-lt', 'hyph-lt', \
    'hyph-lt', 'tug.org',
    '/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-lt.tex?view=log', \
    r'.*?<em>(.*) UTC</em>', datestring="%a %b %d %H:%M:%S %Y"))
packagelist.append(package('http-regexp', 'hyphen-fa', 'fahyph', \
    'fahyph', 'ftp.heanet.ie', '/pub/CTAN/tex/language/hyphenation/', \
    r'.*?<a href="fahyph.zip">fahyph.zip</a>.*?(\d\d-...-\d\d\d\d)', datestring="%d-%b-%Y"))
packagelist.append(package('http-regexp', 'hyphen-ia', 'iahyphen', \
    'iahyphen', 'ftp.heanet.ie', '/pub/CTAN/tex/language/hyphenation/', \
    r'.*?<a href="iahyphen.tex">iahyphen.tex</a>.*?(\d\d-...-\d\d\d\d)', datestring="%d-%b-%Y"))
packagelist.append(package('http-regexp', 'hunspell-shs', 'hunspell-shs', \
    'hunspell', 'secpewt.sd73.bc.ca', '/hunspell/', \
    r'.*?hunspell-shs-ca.tar.gz.*?(\d\d-...-\d\d\d\d)', datestring="%d-%b-%Y"))
packagelist.append(package('http-regexp', 'hunspell-fr', 'hunspell_fr', \
    'hunspell_fr', 'www.dicollecte.org', '/download.php?prj=fr', \
     r'.*?hunspell.fr.classique.reforme1990-v(.*?).zip'))
packagelist.append(package('http-regexp', 'openoffice-lv', 'dict_lv_LV', \
    'dict_lv_LV', 'dict.dv.lv', '/download.php?prj=lv', \
     r'.*?lv_LV(.*?).oxt'))
packagelist.append(package('http-regexp', 'hyphen-fr', 'hyph_fr_FR', \
    'hyph_fr_FR', 'www.dicollecte.org', '/download.php?prj=fr', \
     r'.*?hyph_fr_(.*?).zip'))
packagelist.append(package('http-regexp', 'mythes-fr', 'thesaurus', \
    'thesaurus', 'www.dicollecte.org', '/download.php?prj=fr', \
     r'.*?thesaurus-v(.*?).zip'))
packagelist.append(package('http-regexp', 'hunspell-se', 'hunspell-se', \
    'hunspell-se', 'www.divvun.no', '/index.html', \
     r'.*\s+(.*?):.*?<a href="static_files/hunspell-se.tar.gz"'))
packagelist.append(package('http-regexp', 'hunspell-smj', 'hunspell-smj', \
    'hunspell-smj', 'www.divvun.no', '/index.html', \
     r'.*\s+(.*?):.*?<a href="static_files/hunspell-smj.tar.gz"'))
packagelist.append(package('http-regexp', 'hunspell-ko', 'hunspell-ko', \
    'hunspell-dict-ko', 'code.google.com', '/p/spellcheck-ko/downloads/list', \
     r'.*?hunspell-dict-ko-(.*?).tar.gz'))
packagelist.append(package('http-regexp', 'hyphen-fo', 'hyph_fo_FO', \
    'hyph_fo_FO', 'fo.speling.org', '/filer/', \
     r'.*?hyph_fo_FO-(\d\d\d\d\d\d\d\d).*zip'))
packagelist.append(package('http-regexp', 'hunspell-hil', 'hunspell-hil', \
    'hunspell-hil', 'borel.slu.edu', '/obair/', \
     r'.*?hunspell-hil-(.*?).oxt'))
packagelist.append(package('http-regexp', 'hunspell-om', 'om_ET', \
    'om_ET', 'borel.slu.edu', '/obair/', \
     r'.*?hunspell-om-(.*?).oxt'))
packagelist.append(package('http-regexp', 'hunspell-ca', 'hunspell-ca', \
    'hunspell-ca', 'www.softcatala.org', 
"/wiki/Rebost:Corrector_ortogràfic_de_català_(general)_per_a_l'OpenOffice.org", \
     r'.*?\(versió (.*?)\)'))
#ftp dirs of sane packages
packagelist.append(package('ftp', 'hunspell-ak', 'akan_ns__mfuaasekyer', \
    'akan_ns__mfuaasekyer', 'ftp.heanet.ie', \
    '/mirrors/ftp.mozilla.org/pub/mozilla.org/addons/9978/'))
packagelist.append(package('ftp', 'hunspell-oc', 'occitan-languedocien', \
    'occitan-languedocien', 'ftp.heanet.ie', \
    '/mirrors/ftp.mozilla.org/pub/mozilla.org/addons/8235/'))
packagelist.append(package('ftp', 'hunspell-fy', 'frysk_wurdboek', \
    'frysk_wurdboek', 'ftp.heanet.ie', \
    '/mirrors/ftp.mozilla.org/pub/mozilla.org/addons/5679/'))
packagelist.append(package('ftp', 'hunspell-hsb', 'upper_sorbian_spelling_dictionary', \
    'upper_sorbian_spelling_dictionary', 'ftp.heanet.ie', \
    '/mirrors/ftp.mozilla.org/pub/mozilla.org/addons/3956/'))
packagelist.append(package('ftp', 'hunspell-tk', 'turkmen_spell_checker', \
    'turkmen_spell_checker', 'ftp.heanet.ie', \
    '/mirrors/ftp.mozilla.org/pub/mozilla.org/addons/204314/'))
#packagelist.append(package('http-last-modified', 'hunspell-fj', 'fj_FJ', \
#    'fj_FJ', 'www.foss.usp.ac.fj', '/OOo_fj/OOo_fj_FJ.zip'))
packagelist.append(package('ftp', 'hunspell-fj', 'fijian_spelling_dictionary', \
    'fijian_spelling_dictionary', 'ftp.heanet.ie', \
    '/mirrors/ftp.mozilla.org/pub/mozilla.org/addons/12115/'))
packagelist.append(package('ftp', 'hunspell-haw', 'hawaiian_spell_checker', \
    'hawaiian_spell_checker', 'ftp.heanet.ie', \
    '/mirrors/ftp.mozilla.org/pub/mozilla.org/addons/204309/'))
packagelist.append(package('ftp', 'hunspell-ru', 'rus-ispell', \
    'rus-ispell', 'scon155.phys.msu.ru', '/pub/russian/ispell/'))
packagelist.append(package('ftp', 'hunspell-lt', 'lt_LT', \
    'lt_LT', 'ftp.akl.lt', '/ispell-lt/'))
#horrific unversioned direct http links, off last-modified time
packagelist.append(package('http-last-modified', 'hunspell-es', 'es_ANY', \
    'es_ANY', 'es.openoffice.org', '/files/documents/73/3001/es_ANY.zip'))
packagelist.append(package('http-last-modified', 'hunspell-gl', 'gl_ES-pack', \
    'gl_ES-pack', 'openoffice.mancomun.org', '/libreeengalego/Corrector/gl_ES-pack.zip'))
packagelist.append(package('http-last-modified', 'hunspell-hr', 'hr_HR', \
    'hr_HR', 'cvs.linux.hr', '/spell/myspell/hr_HR.zip'))
packagelist.append(package('http-last-modified', 'hunspell-eu', 'eu-ES-hunspell', \
    'eu-ES-hunspell', 'www.euskara.euskadi.net',\
    
'/r59-20660/eu/contenidos/informacion/euskarazko_softwarea/eu_9567/adjuntos/eu-ES-hunspell.tar.gz'))
packagelist.append(package('http-last-modified', 'hunspell-mt', 'spellcheck-mt', \
    'spellcheck-mt', 'linux.org.mt', '/downloads/spellcheck-mt-0.3.tar.gz'))
#packagelist.append(package('http-last-modified', 'hunspell-ia', 'ia_myspell', \
#    'ia_myspell', 'download.savannah.gnu.org', '/releases/interlingua/ia_myspell.zip'))
packagelist.append(package('http-last-modified', 'hunspell-ia', 'ia_myspell', \
    'ia_myspell', 'nongnu.uib.no', '/interlingua/ia_myspell.zip'))
packagelist.append(package('http-last-modified', 'hunspell-quh', 'quh_BO-pack', \
    'quh_BO-pack', 'www.runasimipi.org', '/quh_BO-pack.zip'))
packagelist.append(package('http-last-modified', 'hunspell-am', 'am_ET', \
    'am_ET', 'www.cs.ru.nl', '/~biniam/geez/dict/am_ET.zip'))
packagelist.append(package('http-last-modified', 'hunspell-ti', 'ti_ER', \
    'ti_ER', 'www.cs.ru.nl', '/~biniam/geez/dict/ti_ER.zip'))
packagelist.append(package('http-last-modified', 'hunspell-mos', 'mos_BF', \
    'mos_BF', 'abcburkina.net', '/ancien/documents/lingu/DicoMoore.zip'))
#horrific unversioned direct ftp dirs, off last-modified time
packagelist.append(package('ftp-last-modified', 'hunspell-az', 'aspell-az', \
    'aspell-az', 'ftp.gnu.org', '/gnu/aspell/dict/az/'))
packagelist.append(package('ftp-last-modified', 'hunspell-csb', 'aspell-csb', \
    'aspell-csb', 'ftp.gnu.org', '/gnu/aspell/dict/csb/'))
packagelist.append(package('ftp-last-modified', 'hunspell-fa', 'aspell-fa', \
    'aspell-fa', 'ftp.gnu.org', '/gnu/aspell/dict/fa/'))
packagelist.append(package('ftp-last-modified', 'hunspell-gv', 'aspell-gv', \
    'aspell-gv', 'ftp.gnu.org', '/gnu/aspell/dict/gv/'))
packagelist.append(package('ftp-last-modified', 'hunspell-ky', 'aspell-ky', \
    'aspell-ky', 'ftp.gnu.org', '/gnu/aspell/dict/ky/'))
#horrific unversioned svn, off svn propget svn:date --revprop -rHEAD
packagelist.append(package('svn-propget-date', 'hunspell-en', 'en_US', \
    'en_US', 'wordlist.svn.sourceforge.net', '/svnroot/wordlist/trunk/'))
packagelist.append(package('svn-propget-date', 'zaf', 'hyph_af_ZA', \
    'hyph_af_ZA', 'zaf.svn.sourceforge.net', '/svnroot/zaf/trunk/dict/af/hyph/hyph_af_ZA.dic', 
ispost=0))
packagelist.append(package('svn-propget-date', 'zaf', 'hyph_zu_ZA', \
    'hyph_zu_ZA', 'zaf.svn.sourceforge.net', '/svnroot/zaf/trunk/dict/zu/hyph/hyph_zu_ZA.dic', 
ispost=0))
#sane gnome packages
packagelist.append(package('gnome', 'libgsf'))
packagelist.append(package('gnome', 'planner'))
#sane sourceforge packages
packagelist.append(package('sourceforge', 'hunspell', 'hunspell', 'Hunspell'))
packagelist.append(package('sourceforge', 'libcmis', 'libcmis', 'libcmis'))
packagelist.append(package('sourceforge', 'hyphen', 'hunspell', 'Hyphen'))
packagelist.append(package('sourceforge', 'mythes', 'hunspell', 'MyThes'))
packagelist.append(package('sourceforge', 'libwpd'))
packagelist.append(package('sourceforge', 'libwmf', 'wvware', 'libwmf'))
packagelist.append(package('sourceforge', 'mythes-pl', 'synonimy', 'synonimy'))
packagelist.append(package('sourceforge', 'hunspell-bg', 'bgoffice', 'OpenOffice.org Spell BG'))
packagelist.append(package('sourceforge', 'hyphen-bg', 'bgoffice', 'OpenOffice.org Hyphenation BG'))
packagelist.append(package('sourceforge', 'mythes-bg', 'bgoffice', 'OpenOffice.org Thesaurus BG'))
packagelist.append(package('sourceforge', 'hunspell-hu', 'magyarispell', 'Magyar Ispell'))
packagelist.append(package('sourceforge', 'hunspell-it', 'linguistico', 'Dizionario italiano per 
OOo', ispost=0))
packagelist.append(package('sourceforge', 'mythes-it', 'linguistico', 'Thesaurus OOo 2.x.x', 
ispost=1, fixrule=('02_0','02_0_')))
packagelist.append(package('sourceforge', 'hunspell-uk', 'ispell-uk', 'spell-uk'))
packagelist.append(package('sourceforge', 'mythes-uk', 'ispell-uk', 'spell-uk'))
packagelist.append(package('sourceforge', 'hunspell-ro', 'rospell', 'Romanian dictionaries'))
packagelist.append(package('sourceforge', 'hyphen-ro', 'rospell', 'Romanian dictionaries'))
packagelist.append(package('sourceforge', 'mythes-ro', 'rospell', 'Romanian dictionaries'))
packagelist.append(package('sourceforge', 'hunspell-ku', 'myspellkurdish', 'MySpell'))
packagelist.append(package('sourceforge', 'hunspell-hy', 'armspell', 'myspell-hy'))
packagelist.append(package('sourceforge', 'hunspell-nds', 'aspell-nds', 'hunspell-nds'))
packagelist.append(package('sourceforge', 'hunspell-ln', 'lingala', 'hunspell-ln'))
packagelist.append(package('sourceforge', 'jcommon', 'jfreechart', '3. JCommon', fixrule=('Version 
','')))
packagelist.append(package('sourceforge', 'lpsolve'))
packagelist.append(package('sourceforge', 'silgraphite'))
packagelist.append(package('http-regexp', 'libbase', 'jfreereport', \
    'libbase', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/02.%20Libraries/1.1.2-stable/',
 \
    r'.*?>libbase-(.*?).zip<'))
packagelist.append(package('http-regexp', 'libserializer', 'jfreereport', \
    'libserializer', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/02.%20Libraries/1.1.2-stable/',
 \
    r'.*?>libserializer-(.*?).zip<'))
packagelist.append(package('http-regexp', 'libloader', 'jfreereport', \
    'libloader', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/02.%20Libraries/1.1.2-stable/',
 \
    r'.*?>libloader-(.*?).zip<'))
packagelist.append(package('http-regexp', 'pentaho-libxml', 'jfreereport', \
    'libxml', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/02.%20Libraries/1.1.2-stable/',
 \
    r'.*?>libxml-(.*?).zip<'))
packagelist.append(package('http-regexp', 'libfonts', 'jfreereport', \
    'libfonts', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/02.%20Libraries/1.1.2-stable/',
 \
    r'.*?>libfonts-(.*?).zip<'))
packagelist.append(package('http-regexp', 'libformula', 'jfreereport', \
    'libformula', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/02.%20Libraries/1.1.2-stable/',
 \
    r'.*?>libformula-(.*?).zip<'))
packagelist.append(package('http-regexp', 'librepository', 'jfreereport', \
    'librepository', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/02.%20Libraries/1.1.2-stable/',
 \
    r'.*?>librepository-(.*?).zip<'))
packagelist.append(package('http-regexp', 'flute', 'jfreereport', \
    'flute', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/30.%20OpenOffice%20Branches/OOo31/',
 \
    r'.*?>flute-(.*?).zip<', ispost=1))
packagelist.append(package('http-regexp', 'liblayout', 'jfreereport', \
    'liblayout', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/30.%20OpenOffice%20Branches/OOo31/',
 \
    r'.*?>liblayout-(.*?).zip<', ispost=1))
packagelist.append(package('http-regexp', 'pentaho-reporting-flow-engine', 'jfreereport', \
    'flow-engine', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/30.%20OpenOffice%20Branches/OOo31/',
 \
    r'.*?>flow-engine-(.*?).zip<', ispost=1))
packagelist.append(package('http-regexp', 'jcommon-serializer', 'jfreereport', \
    'jcommon-serializer', 'www.mirrorservice.org',
    
'/sites/download.sourceforge.net/pub/sourceforge/j/project/jf/jfreereport/99.%20Archive/07.%20JCommon-Serializer/',
 \
    r'.*/sites/download.*?">(.*)</A></TD>', fixrule=('-GA','')))
packagelist.append(package('http-regexp', 'hunspell-lb', 'SpellcheckerLu', \
    'SpellcheckerLu', 'spellchecker.lu', '/download/openoffice/', \
    r'.*?Leschten Update: <strong>(.*)</strong>'))

#packagelist = []
#packagelist.append(package('http-regexp', 'mythes-de', 'mythes-de', \
#    'mythes-de', 'www.openthesaurus.de', '/about/download', \
#     r'.*?(\d\d\d\d-\d\d-\d\d)', 1))

socket.setdefaulttimeout(120) # timeout in seconds

task = packagemanager(packagelist)
task.fetch()

if len(droppedlist):
        print "No SRPMS seen for", 
        for dropped in droppedlist:
                print dropped,
        print
#!/bin/env python
import sys, re, string

seps = ['-', '_', '.']

debug = 0

#define the split between name and version
#as where the first occurance of a
#-, or _, or . is followed by a number
def is_name_version_split_loc(tarball, i):
        return tarball[i] in seps and tarball[i+1].isdigit()

def strip_trailing_sep(text):
        while len(text) and text[-1] in seps:
                text = text[:-1]
        return text

def is_simple_pre_nonnumeric(nonnumeric):
        nonnumeric = nonnumeric.lower()
        if nonnumeric == 'rc':
                return True 
        if nonnumeric == 'beta':
                return True 
        if nonnumeric == 'alpha':
                return True 
        if nonnumeric == 'dev':
                return True 
        return False


def is_pre_nonnumeric(nonnumeric):
        nonnumeric = nonnumeric.lower()
        if is_simple_pre_nonnumeric(nonnumeric):
                return True

        for pre in 'rc', 'alpha', 'beta', 'test', 'pre', 'd0', 'dev':
                if nonnumeric[0:len(pre)] == pre:
                        try:
                                num = int(nonnumeric[len(pre):])
                                return True
                        except:
                                pass

        return False

def normalize_known_nonnumerics(nonnumeric):
        newnonnumeric = nonnumeric.lower()
        if newnonnumeric == 'alpha':
                return newnonnumeric
        if newnonnumeric == 'beta':
                return newnonnumeric
        if newnonnumeric == '+cvs' or newnonnumeric == 'cvs':
                return 'cvs'
        if newnonnumeric == '+svn' or newnonnumeric == 'svn':
                return 'svn'
        return nonnumeric

def is_okver_nonnumeric(nonnumeric):
        nonnumerics=0
        for a in nonnumeric:
                if not a.isdigit():
                        nonnumerics = nonnumerics + 1
        if nonnumerics == 1:
                return True 
        return False

def is_post_nonnumeric(nonnumeric):
        nonnumeric = nonnumeric.lower()
        if nonnumeric == '+cvs':
                return True
        if nonnumeric == '+svn':
                return True
        return False

def has_ambiguous_nonnumeric(chunks):
        ret = False
        for chunk in chunks:
                if chunk[1] == 0:
                        if is_okver_nonnumeric(chunk[0]):
                                continue
                        if is_post_nonnumeric(chunk[0]):
                                continue
                        if is_pre_nonnumeric(chunk[0]):
                                continue
                        ret = True
                        break
        return ret

def easydateable(version):
        return len(version) == 0 or version == "0" or version == "0.0"

def isrunawayprelease(version, date, nonnumeric):
        return (version == '0.1' or version == '0') and nonnumeric and nonnumeric.lower() == 'beta' 
and date

class NVRException(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

class PrePostError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

def is_pre_vr(vr):
        return (vr == '0' or vr == '0.0' or vr == '0.1')

def has_date(chunks):
        ret = False
        for chunk in chunks:
                if chunk[1] == 2:
                        ret = True
                        break
        return ret

def ishexdigit(char):
        return char in string.hexdigits

#allow 1.1f but enforce 1.1.foo
#don't allow d01/d02
def issimplehexstring(strng):
        if len(strng) > 2:
                return 0
        return filter(ishexdigit, strng) == strng

def first_nonsimple_index(chunks, ispost=-1):
        chunkcount = len(chunks)
        lastchunk = 0
        for i in range(0, chunkcount):
                if chunks[i][1] == 2:
                        break
#               if chunks[i][1] == 0 and (len(chunks[i][0]) > 1 or ispost != -1):
                if chunks[i][1] == 0 and ((not issimplehexstring(chunks[i][0])) or ispost == 0):
                        break
                lastchunk = i+1
        return lastchunk

def fix_broken_ver(vr):
        if len(vr) == 0:
                vr = '0'
        elif len(vr) > 1 and vr[0] == '0':
                pos = vr.find('.')
                if pos == -1:
                        vr = vr[0] + '.' + vr[1:]
                elif pos != 1:
                        vr = vr[1:]
        return vr

def generate_fedora_vr(chunks, ispost=-1):
        vr = ''
        lastchunk = first_nonsimple_index(chunks, ispost)
        if debug: print 'pre/post status is', ispost, 'lastchunk is', lastchunk
        for i in range(0, lastchunk):
                if len(vr) > 0:
                        #allow 1.1f but enforce 1.1.foo
                        if not (i > 0 and chunks[i][1] == 0 and (len(chunks[i][0]) == 1 or 
issimplehexstring(chunks[i][0])) and chunks[i-1][1] == 1):
                                vr = vr + '.'
                vr = vr + chunks[i][0]

        vr = fix_broken_ver(vr)

        if debug: print 'base vr is', vr
        if debug: print 'lastchunk is', lastchunk

        if ispost == -1 and is_pre_vr(vr) and has_date(chunks):
                newchunks = []
                for chunk in chunks:
                        if chunk[1] == 0 and is_simple_pre_nonnumeric(chunk[0]):
                                continue
                        newchunks.append(chunk)
                chunks = newchunks
                lastchunk = first_nonsimple_index(chunks, ispost)
                vr = '0'

        for chunk in chunks:
                if chunk[1] == 0:
                        if is_pre_nonnumeric(chunk[0]):
                                ispost = 0
                        elif is_post_nonnumeric(chunk[0]):
                                ispost = 1

        if debug: print 'pre/post status is', ispost

        if has_ambiguous_nonnumeric(chunks) and ispost not in [1, 0]:
                raise PrePostError("Can't guess if pre/post due to nonnumeric text in" + 
str(chunks))
        if has_date(chunks) and ispost not in [1, 0] and not is_pre_vr(vr):
                raise PrePostError("Can't guess if pre/post due to a date")

        if ispost == 0 and len(chunks) > lastchunk:
                vr = vr + '-' + '0.1'
        elif ispost == 1:
                vr = vr + '-' + '1'

        if debug: print 'vr is now', vr

        for i in range(lastchunk, len(chunks)):
                if i > lastchunk and chunks[i][1] == 2 and chunks[i-1][1] == 0:
                        tempchunk = chunks[i]
                        chunks[i] = chunks[i-1]
                        chunks[i-1] = tempchunk

        for i in range(lastchunk, len(chunks)):
                if len(vr) > 0 and not (chunks[i-1][1] == 2 and chunks[i][1] == 0):
                        vr = vr + '.'
                vr = vr + normalize_known_nonnumerics(chunks[i][0])

        if debug: print 'and vr is now', vr

        if vr.find('-') == -1:
                vr = vr + '-1'

        if debug: print 'vr is finally', vr

        return vr

#       if has_ambiguous_nonnumeric(chunks) and ispost not in [1, 0]:
#               raise PrePostError("Can't guess if pre/post due to " + chunks)
#       if date and ispost not in [1, 0] and not (easydateable(version) or nonnumeric):
#               raise PrePostError("Can't guess if pre/post due to " + date)
#       if len(version) == 0:
#               version = "0"
#
#       if (nonnumeric or date) and ispost not in [1, 0]:
#               if nonnumeric:
#                       if isrunawayprelease(version, date, nonnumeric):
#                               ispost = -1
#                               nonnumeric = None
#                               version = "0"
#                       elif is_pre_nonnumeric(nonnumeric):
#                               ispost = 0
#                       elif is_post_nonnumeric(nonnumeric):
#                               ispost = 1
#
#       if len(version) > 1 and version[0] == '0' and version[1].isdigit():
#               version = version[0] + '.' + version[1:]
#
#       if nonnumeric or date:
#               if ispost == 1:
#                       version = version + '-' + '1.'
#               elif ispost == 0:
#                       version = version + '-' + '0.1.'
#
 #       version = version.replace('%{X}', '1')
#
#       if date:
#               if version[-1].isdigit():
#                       version = version + '.' + date
#               else:
#                       version = version + date
#
#       if nonnumeric:
#               if version[-1] != '.' and not date and not is_okver_nonnumeric(nonnumeric):
#                       version = version + '.'
#               version = version + normalize_known_nonnumerics(nonnumeric)
#
#       if version.find('-') == -1:
#               version = version + '-1'
#
#       return version

def determine_type(chunk, isnumber):
        number = int(isnumber)
        if len(chunk) == 8 and chunk.isdigit():
                #make an effort to fix a reversed date
                if int(chunk[0:4]) < 1900 and int(chunk[4:8]) > 1900:
                        chunk = chunk[4:8]+chunk[2:4]+chunk[0:2]
                number = 2
        else:
                chunk = chunk.strip()
        return chunk, number

def split_version_date_nonnumeric(version):
        date = None

        version = version.replace('-', '.').replace('_', '.')

        pattern = r'.*?(\d\d\d\d[-_\.]\d\d[-_\.]\d)[^\d]'
        p = re.compile(pattern)
        m = p.match(version)
        if m:
                date = m.group(1)
                version = version[:m.start(1)] + \
                        m.group(1)[0:-1] + '0' + m.group(1)[-1] + \
                        version[m.end(1):]

        pattern = r'.*?(\d\d\d\d[-_\.]?\d\d[-_\.]?\d\d)'
        p = re.compile(pattern)
        m = p.match(version)
        if m:
                date = m.group(1)
                for sep in seps:
                        date = date.replace(sep, '')
                pre = version[:m.start(1)]
                if len(pre) > 1 and pre[-1] != '.':
                        pre = pre + '.'
                post = version[m.end(1):]
                if len(post) > 1 and post[0] != '.':
                        post = '.' + post
                version = pre + date + post

        chunks = []
        chunk = ''
        isnumber = True
        for c in version:
                if chunk == '':
                        isnumber = c.isdigit()
                if isnumber and c.isdigit():
                        chunk = chunk + c
                elif not isnumber and c != '.':
                        chunk = chunk + c
                elif c == '.':
                        chunks.append(determine_type(chunk, isnumber))
                        chunk = ''
                else:
                        chunks.append(determine_type(chunk, isnumber))
                        chunk = c
                        isnumber = c.isdigit()
        chunks.append(determine_type(chunk, isnumber))
        if debug: print chunks

        return chunks

def split_name_version(tarball, prefix):
        version = None
        name = None
        suffixes = [
                        '_source.tar.bz2', '_source.tar.gz', '_source.tar.zip',
                        '_src.bz2', '_src.gz', '_src.zip',
                        '.tar.bz2', '.tar.gz', '.tgz', '-pack.zip', '.zip',
                        '-fx+tb+sm.xpi', '-fx+zm+tb.xpi', '-fx+tb.xpi',
                        '-tb+fx+sm.xpi', '-fx.xpi', '.xpi', '.oxt' ]
        if tarball[:len(prefix)] == prefix:
                for suffix in suffixes:
                        if tarball[-len(suffix):] == suffix:
                                name = prefix
                                for i in range(len(prefix),len(tarball)-len(suffix)):
                                        if is_name_version_split_loc(tarball, i):
                                                break
                                        name = name + tarball[i]
                                version=tarball[len(name)+1:len(tarball)-len(suffix)]
                                break
        return name, version

def make_nvr(origname, prefix='', ispost=-1):
        if debug: print 'origname is', origname
        name, version = split_name_version(origname, prefix)
        if debug: print 'name', 'version', name, version
        if name == None or version == None:
                raise NVRException('Unrecognized format for ' + origname)
        chunks = split_version_date_nonnumeric(version)
        if debug: print 'chunks', chunks
        ret = generate_fedora_vr(chunks, ispost)
        vr = ret.split('-')
        if debug: print 'nvr', vr
        return name, vr[0], vr[1]

def get_nvr(srcrpm, ispost=-1):
        suffix = '.src.rpm'
        if srcrpm[-len(suffix):] == suffix:
                suf = -len(suffix)
                rel = suf
                while srcrpm[rel] != '-':
                        rel = rel - 1
                release = srcrpm[rel+1:suf]
                if ispost == 1:
                        postbit = release.find('.')
                        release = '1' + release[postbit:]
                ver = rel-1
                while srcrpm[ver] != '-':
                        ver = ver - 1
                version = srcrpm[ver+1:rel]
                name = srcrpm[0:ver]
                if debug: print 'making', name, version, release, 'from', srcrpm
                return name, version, release

        return None 

def scrub_disttag(release):
        knowntags =[ '.fc7', '.fc8', '.fc9', '.fc10', '.fc11', '.fc12', '.fc13', '.fc14', '.fc15', 
'.fc16', '.fc17' ]
        for tag in knowntags:
                release = release.replace(tag, '')
        return release

def undo_prerelease(release):
        chunks = release.split('.')
        if chunks > 2 and chunks[0] == '0':
                try:
                        anum = int(chunks[1])
                except:
                        pass
                release = chunks[0] + '.1'
                for chunk in chunks[2:]:
                        release = release + '.' + chunk
        return release

def rpmsplit(instr):
        chunks = []
        chunk = ''

        for c in instr:
                if chunk == '':
                        mode = c.isdigit()
                if not c.isalnum():
                        chunks.append(chunk)
                        chunk = ''
                elif mode == c.isdigit():
                        chunk = chunk + c
                else:
                        chunks.append(chunk)
                        chunk = c
                        mode = c.isdigit()
        chunks.append(chunk)

        return chunks

def compare_key(a, b):
        abits = rpmsplit(a)
        bbits = rpmsplit(b)
        min = len(abits)
        if min > len(bbits):
                min = len(bbits)
        for i in range(0, min):
                aisnum = True
                bisnum = True
                try:
                        anum = int(abits[i])
                except:
                        aisnum = False
                        pass
                try:
                        bnum = int(bbits[i])
                except:
                        bisnum = False
                        pass
                if aisnum and bisnum:
                        if anum > bnum:
                                return 1
                        elif anum < bnum:
                                return -1
                elif not aisnum and not bisnum:
                        if abits[i] > bbits[i]:
                                return 1
                        elif bbits[i] > abits[i]:
                                return -1
                else:
                        if aisnum > bisnum:
                                return 1
                        elif aisnum < bisnum:
                                return -1
        if len(abits) > len(bbits):
                return 1
        elif len(bbits) > len(abits):
                return -1
        return 0

def compare_vr(aver, bver, arel, brel):
        ret = compare_key(aver, bver)
        if ret == 0:
                ret = compare_key(arel, brel)
        return ret

if __name__ == "__main__":
        upstreamnames = [
        'hunspell-1.1.tar.gz',
        'italiano_2_4_2007_09_01.zip',
        'upper_sorbian_spelling_dictionary-0.0.20060327.2-fx+tb+sm.xpi',
        'foo-1.1-beta1.zip',
        'foo-2009.10.10-beta-1.oxt'
        ]
        #'th_ro_RO.3.3-test3.zip'
        for origname in upstreamnames:
                try:
                        name, version, release = make_nvr(origname)
                        print name, version, release
                except PrePostError:
                        pass
        srcrpms = [
        'hunspell-it-2.4-0.99.20070901.fc8.src.rpm',
        ]
        for rpm in srcrpms:
                rpmname, rpmversion, rpmrelease = get_nvr(rpm)
                rpmrelease = scrub_disttag(rpmrelease)
                rpmrelease = undo_prerelease(rpmrelease)
                print rpmname, rpmversion, rpmrelease
                print compare_vr(rpmversion, version, rpmrelease, release)

Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.