extras-buildsys/utils/pushscript Config_Extras.py, NONE, 1.1 MultiLib.py, NONE, 1.1 Push.py, NONE, 1.1 RepoBuild.py, NONE, 1.1 RepoManage.py, NONE, 1.1 RepoView.py, NONE, 1.1 Utils.py, NONE, 1.1 extras-push, NONE, 1.1 extras-repobuild, NONE, 1.1 extras-repomanage, NONE, 1.1 extras-repoview, NONE, 1.1

Michael Schwendt (mschwendt) fedora-extras-commits at redhat.com
Fri Sep 29 16:14:17 UTC 2006


Author: mschwendt

Update of /cvs/fedora/extras-buildsys/utils/pushscript
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv24507/pushscript

Added Files:
	Config_Extras.py MultiLib.py Push.py RepoBuild.py 
	RepoManage.py RepoView.py Utils.py extras-push 
	extras-repobuild extras-repomanage extras-repoview 
Log Message:
Time to break some stuff:

* Move all relevant config values into a separate module, which is
loaded dynamically based on a "project" name/id passed to the tools:
E.g.  extras-push -> project "Extras" -> Config_Extras.py
      foo-push -> project "Foo" -> Config_Foo.py

* Push packages "by build job" instead of "by rpm file" -- we now can
ignore (or blacklist) individual build job results.

* Call repobuild/view/manage as module functions (to allow for future
logging and more exception handling).




--- NEW FILE Config_Extras.py ---
#!/usr/bin/python -t
# -*- mode: Python; indent-tabs-mode: nil; -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import os

signersgid = 100581  # signers group
signersumask = 0002
signkeyname = 'extras at fedoraproject.org'

distro = 'fedora'
project = 'extras'

class opts:
    mail = True
    repomanage = True
    repoview = True
    signkeycheck = True
    doublesync = False

top_workdir = '/srv/rpmbuild'

treedir = top_workdir+'/%s/tree/%s' % (project, project)
stagesdir = top_workdir+'/repodir'

# Where we store mails to be sent, our main lockfile, ...
rundir = top_workdir+'/extras-push-rundir'
cachedir = rundir+'/mdcache'

alldists = [ 'development', '5', '4', '3' ] # also the order in build reports

archdict = {'3':['x86_64', 'i386'], 
            '4':['ppc','x86_64', 'i386'],
            '5':['ppc','x86_64', 'i386'],
            'development':['ppc','x86_64','i386'],
            }

multilibdists = [ 'development', '5', '4', '3' ]

# map: dist -> target arch -> list of pkg name regexp patterns
# We don't check virtual package names, unless it's a virtual -devel pkg.
# black-list takes precedence over white-list
blacklists = { 'development' : { 'x86_64' : [] },
               }
whitelists = { 'development' : { 'x86_64' : [ 'wine', 'wine-arts', 'wine-devel' ] },
               # 'development' : { 'x86_64' : [ '.*-devel', 'wine', 'wine-arts', 'wine-devel' ] },
               #'6' : { 'x86_64' : [ 'wine', 'wine-arts', 'wine-devel' ] },
               '5' : { 'x86_64' : [ 'wine', 'wine-arts', 'wine-devel' ] },
               '4' : { 'x86_64' : [ 'wine', 'wine-arts', 'wine-devel' ] },
               '3' : { 'x86_64' : [ 'wine', 'wine-arts', 'wine-devel' ] },
               }

# packages to exclude from being repomanaged: dist => shell quoted path regexp
repomanage_keepdict = {'3': "'/\([^/]\+-\)\?kmod-'",
                       '4': "'/\([^/]\+-\)\?kmod-'",
                       '5': "'/\([^/]\+-\)\?kmod-'",
                       'development': "'/\([^/]\+-\)\?kmod-'",
                       }

sync_cmd = 'extras-sync'

createrepo = '/usr/bin/createrepo'

cr_cachedir = '/tmp/repomd-cache'  # createrepo cachedir

repoview = '/usr/bin/repoview'
#repoview = '/srv/extras-push/work/repoview'

repomanage = '/usr/bin/repomanage'

#post_cmds = []
post_cmds = ['upgradecheck.py -c %s' % os.path.expanduser('~/work/upgradecheck/upgradecheck-core+extras.conf'),
             'nohup rc-run-all.py &'
             ]

# Build report.
smtp_server = ''
project_hr = 'Fedora Extras'
mail_from = 'buildsys at fedoraproject.org'
mail_to = 'fedora-extras-list at redhat.com'
mail_footer = """

For more information about the built packages please see the repository
or the Fedora Info Feed: http://fedoraproject.org/infofeed/

"""


--- NEW FILE MultiLib.py ---
#!/usr/bin/python -t
# -*- mode: Python; indent-tabs-mode: nil; -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import errno, os, sys
import glob, pickle, re
import rpm, rpmUtils.arch, rpmUtils.transaction, rpmUtils.miscutils

import Utils

# TODO
sys.path.insert(0,'/srv/extras-push/work/extras-repoclosure')
import yum, yum.Errors
from yum.packages import YumLocalPackage
try:
    from yum.packageSack import ListPackageSack
except: # yum < 2.9
    from repomd.packageSack import ListPackageSack
from RepoSupport import RepoSupport

DEBUG = False
Utils.setdebug(DEBUG)

# The following dict can be generated with rpmUtils.arch functions.
# target arch -> compatible archs
compatarchdict = { 'x86_64' : ['x86_64', 'athlon', 'i686', 'i586', 'i486', 'i386', 'noarch']
                   }

# map: target arch -> 'debug','rpms' -> list of new multicompat pkgs
# to be installed/linked/copied and resolved later in a second pass
missingdict = {}


def isWantedName(cfg,dist,targetarch,namelist):
    """Check a single package name against black-list and white-list. Since
    a package can have virtual names, this takes a list of names as input.
    Returns: True or False"""
    for n in namelist:
        if cfg.blacklists.has_key(dist) and cfg.blacklists[dist].has_key(targetarch):
            for r in cfg.blacklists[dist][targetarch]:
                if re.compile('^'+r+'$').search(n):
                    return False
        if cfg.whitelists.has_key(dist) and cfg.whitelists[dist].has_key(targetarch):
            for r in cfg.whitelists[dist][targetarch]:
                if re.compile('^'+r+'$').search(n):
                    return True
    return False # reject by default


def evalPackage(cfg,ts,fname,dist, srpmlocdict):
    # Examine the package, see whether we want it for any of the
    # enabled multilib repositories. Then store the package names
    # in a map, which is used in pass 2 (install+resolve deps).
    if dist not in cfg.multilibdists:
        return

    for targetarch in cfg.archdict[dist]:  # list of repo archs
        if not compatarchdict.has_key(targetarch):
            continue

        pkg = YumLocalPackage(ts=ts,filename=fname)
        srcrpm = pkg.tagByName('sourcerpm')
        (n,a,e,v,r) = pkg.returnPackageTuple()
        (sn,sv,sr,se,sa) = rpmUtils.miscutils.splitFilename(srcrpm)
        debugrpm = '%s-debuginfo-%s-%s.%s.rpm' % (sn,sv,sr,a)

        if a == targetarch or a == 'noarch':  # installed by main push script
            continue
        if a not in compatarchdict[targetarch]:  # incompatible pkg arch
            continue

        names = [n]
        if not n.endswith('-devel'):
            # packageObject in yum-2.6.0-1 is broken: no such attr 'prco'
            #for (prov, flag, (prove, provv, provr)) in pkg.returnPrco('provides'):
            hdr = rpmUtils.miscutils.hdrFromPackage(ts,fname)
            for prov in hdr['provides']:
                if prov.endswith('-devel'):
                    names.append(prov)
            
        if not isWantedName(cfg,dist,targetarch,names):
            continue
        
        srpmloc = os.path.join(cfg.treedir,dist,'SRPMS',srcrpm)
        if DEBUG and not os.path.isfile(srpmloc):
            srpmloc = srpmlocdict[srcrpm]

        try:
            hdr = rpmUtils.miscutils.hdrFromPackage(ts,srpmloc)
            excludearch = hdr['excludearch']
        except rpmUtils.RpmUtilsError, e:  # source rpm not there or bad
            print 'ERROR: %s' % e
            print srpmloc
            print 'referenced by: %s' % fname
            # TODO: We don't want such builds! Do something about it.
            # Is this case possible at all? Or only during dep resolving
            # and when running into old pkgs?
            srcrpm = None
            excludearch = []
        
        if not srcrpm:
            continue
        
        if targetarch in excludearch:
            print 'Multi-compat, but ExcludeArch %s' % excludearch
            continue

        # Save base file-names here.
        pkgbasefn = os.path.basename(fname)
        missingdict.setdefault(targetarch,{})
        pkglist = missingdict[targetarch].setdefault('rpms',[])
        if pkgbasefn not in pkglist:
            pkglist.append(pkgbasefn)
            missingdict[targetarch]['rpms'] = pkglist
            print ' +', pkgbasefn
        pkglist = missingdict[targetarch].setdefault('debug',[])
        if debugrpm not in pkglist:
            pkglist.append(debugrpm)
            missingdict[targetarch]['debug'] = pkglist
            print ' +', debugrpm
        
    return


def evalFromTree(cfg,dist):
    ts = rpmUtils.transaction.initReadOnlyTransaction()
    global missingdict
    missingdict = {}
    for srcarch in cfg.archdict[dist]:  # list of repo archs
        srcdir = os.path.join(cfg.treedir,dist,srcarch)
        print 'Scanning for multi-compat packages:', srcdir
        files = glob.glob('%s/*.rpm' % srcdir)
        for f in files:
            evalPackage(cfg,ts,f,dist,{})
    return

# --------------------------------------------------------------------

class Resolver(yum.YumBase):
    def __init__(self, arch = None, config = "/etc/yum.conf"):
        yum.YumBase.__init__(self)

        self.arch = arch
        self.doConfigSetup(fn = config)
        if hasattr(self.repos, 'sqlite'):
            self.repos.sqlite = False
            self.repos._selectSackType()

        self.resolved = {}
        self.seenbefore = []
        self.needed = {}
        self.needed['rpms'] = []
        self.needed['debug'] = []

    def readMetadata(self):
        self.doRepoSetup()
        self.doSackSetup(rpmUtils.arch.getArchList(self.arch))
        for repo in self.repos.listEnabled():
            self.repos.populateSack(which=[repo.id], with='filelists')

    def addNeededPkg(self,pkg):
        (n,a,e,v,r) = pkg.returnPackageTuple()
        file = '%s-%s-%s.%s.rpm' % (n,v,r,a)
        if file not in self.needed['rpms']:
            self.needed['rpms'].append(file)
            print ' +', file

            binarch = a
            srcrpm = pkg.returnSimple('sourcerpm')
            (n,v,r,e,a) = rpmUtils.miscutils.splitFilename(srcrpm)
            debugrpm = '%s-debuginfo-%s-%s.%s.rpm' % (n,v,r,binarch)
            if debugrpm not in self.needed['debug']:
                self.needed['debug'].append(debugrpm)
                print ' +', debugrpm

    def resolveRequires(self,pkg):
        if pkg.returnNevraPrintable() in self.seenbefore:
            #print " ! SEEN BEFORE"
            return
        self.seenbefore.append( pkg.returnNevraPrintable() )

        # yum-2.6.0-1
        #    for (req,flags,(reqe,reqv,reqr)) in pkg.returnPrco('requires'):
        #  File "packageObject.py", line 224, in returnPrco
        #AttributeError: YumLocalPackage instance has no attribute 'prco'

        #for (req,flags,evr) in getRequires( ... ):
        for dep in pkg.requiresList():
            if dep.startswith('rpmlib'):
                continue  # ignore rpmlib deps

            if self.resolved.has_key(dep):
                continue  # resolved before
            
            results = []
            try:
                results = self.returnPackagesByDep(dep)
            except:
                pass
            if len(results) < 1:  # unresolved, most likely in Core
                #print 'UNRESOLVED:', dep
                continue

            self.resolved[dep] = True
            for p in results:
                self.addNeededPkg(p)
                self.resolveRequires(p)

    def log(self, value, msg):
        pass


def resolveMissing(cfg,dist,targetarch):
    if not missingdict.has_key(targetarch):
        return False
    missingdict[targetarch].setdefault('rpms',[])
    missingdict[targetarch].setdefault('debug',[])
    
    rs = RepoSupport()  # TODO
    conf = rs.GenerateConfig([dist])

    repoids = []
    srcarch = rpmUtils.arch.getBaseArch( rpmUtils.arch.multilibArches[targetarch][0] )
    # Only look at basearch repo.
    a = srcarch
    for r in rs.ReleaseRepoDict()[dist]:
        if r.find('extras') < 0:
            continue
        repoid = '%s-%s-%s' % (r,dist,a)
        repoids.append(repoid)
    print repoids

    # Only look at multicompat packages.
    my = Resolver(arch = srcarch, config = conf)
    for repo in my.repos.repos.values():
        if repo.id not in repoids:
            repo.disable()
        else:
            repo.enable()
    my.repos.setCacheDir(cfg.cachedir)
    Utils.fix_mdcache_access(cfg.rundir,cfg.cachedir)
    try:
        print 'Reading metadata...'
        my.readMetadata()
    except yum.Errors.RepoError, e:
        print 'Yum error: %s' % e
        # TODO: This is only bad if it's something a re-run doesn't fix automatically.
    except:
        Utils.fix_mdcache_access(cfg.rundir,cfg.cachedir)
        raise
    print 'done.'
    Utils.fix_mdcache_access(cfg.rundir,cfg.cachedir)

    ts = rpmUtils.transaction.initReadOnlyTransaction()
    compatrepodir = os.path.join(cfg.treedir,dist,srcarch)
    for f in missingdict[targetarch]['rpms']:
        print f
        fpath = os.path.join(compatrepodir,f)
        pkg = YumLocalPackage(ts=ts,filename=fpath)
        my.resolveRequires(pkg)

    changed = False
    print 'Installing needed packages for %s:' % targetarch
    for f in my.needed['rpms']+missingdict[targetarch]['rpms']:
        srcfile = os.path.join(cfg.treedir,dist,srcarch,f)
        destfile = os.path.join(cfg.treedir,dist,targetarch,f)
        if not os.path.exists(destfile):  # silent extra-check
            Utils.install_link_or_copy(srcfile,destfile)
            changed = True
    for f in my.needed['debug']:
        srcfile = os.path.join(cfg.treedir,dist,srcarch,'debug',f)
        destfile = os.path.join(cfg.treedir,dist,targetarch,'debug',f)
        if not os.path.exists(destfile):  # silent extra-check
            Utils.install_link_or_copy(srcfile,destfile)
            changed = True
        
    return changed

# --------------------------------------------------------------------

def main(dists):
    for dist in dists:
        evalFromTree(cfg,dist)
        for arch in cfg.archdict[dist]:  # list of repo archs
            changedagain = resolveMissing(cfg,dist,arch)
            if changedagain:
                Utils.create_arch_repo(cfg,dist,arch)


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print 'Usage: %s <project> <release> [release]...\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)

    cfg = Utils.load_config_module(sys.argv[1])

    Utils.signer_gid_check(cfg.signersgid)
    os.umask(cfg.signersumask)
    main(sys.argv[2:])
    sys.exit(0)


--- NEW FILE Push.py ---
#!/usr/bin/python -t
# -*- mode: Python; indent-tabs-mode: nil; -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import errno
import fcntl, fnmatch
import os, sys
import rpmUtils
import shutil
import string
import tempfile
import time

import Utils, MultiLib
import RepoBuild, RepoManage, RepoView

DEBUG = True
Utils.setdebug(DEBUG)

# Lockfile name supported by plague for mutual exclusion during
# access to needsign repository (i.e. 'stagesdir').
REPO_LOCKFILE_NAME = '.repo-update.lock'

class opts:
    force = False

ts = rpmUtils.transaction.initReadOnlyTransaction()
# Further globals: cfg, srpmlocdict

class LockFile:

    def __init__(self, name, blocking=False):
        self.name = name
        self.mode = fcntl.LOCK_EX
        if not blocking:
            self.mode |= fcntl.LOCK_NB


    def lock(self):
        if DEBUG:
            return
        try:
            self.file = open(self.name,'w')
        except IOError, (err, strerr):
            print "ERROR: opening lockfile %s failed: %s (error %d)" % (self.name, strerr, err)
            sys.exit(err)
        self.rc = fcntl.flock(self.file, self.mode)


    def unlock(self):
        if DEBUG:
            return
        fcntl.flock(self.file, fcntl.LOCK_UN)
        self.file.close()


def getrunfilename(dist):
    runfilename = os.path.join(cfg.rundir, dist)
    if DEBUG:
        runfilename += '.DEBUG'
    return runfilename


def getlinesfromrunfile(dist):
    runfilename = getrunfilename(dist)
    pkglist = []
    try:
        pkglist = file(runfilename).read().splitlines()
    except IOError, (err, strerr):
        if err != 2:  # everything but file_not_found is unexpected
            print 'ERROR: %s: %s' % (strerr,runfilename)
            sys.exit(err)
    return pkglist


def emptyrunfile(dist):
    runfilename = getrunfilename(dist)
    if not os.path.exists(runfilename):
        return
    try:
        os.remove(runfilename)
    except:
        print 'ERROR: Could not remove %s' % runfilename
        pass


# ====================================================================

def get_build_results(path,droppushed=False):
    """returns list of (name,[jobroots]) tuples for available build-results, where every "jobroot" is the path to a build-job results directory"""
    # The needsign repository root contains a directory "name" for
    # every built src.rpm package %{name}.
    d = os.listdir(path)
    try:
        d.remove('repodata')
    except ValueError:
        pass

    rv = []  # return value: list of (name,[jobroots]) tuples
    for name in d:
        pkgroot = os.path.join(path,name)
        if not os.path.isdir(pkgroot):
            continue
        jobroots = []
        # Every built version-release is stored in an own sub-dir of "name".
        # e.g.  ./foo/1.0-1  ./foo/1.0-2
        for pkgrelroot in map(lambda f: os.path.join(pkgroot,f), os.listdir(pkgroot)):
            if os.path.isdir(pkgrelroot):
                if droppushed and os.path.isfile(os.path.join(pkgrelroot,'PUSHED')):
                    continue
                jobroots.append(pkgrelroot)
        rv.append( (name,jobroots) )
    return rv


def find_files(rootpath,pattern='*'):
    """returns list of paths in given tree which point to a file matching the fnmatch pattern"""
    rv = []
    if not os.path.isdir(rootpath):
        return rv
    for root, dirs, files in os.walk(rootpath):
        for f in fnmatch.filter(files,pattern):
            rv.append(os.path.join(root,f))
    return rv


def mark_pkg_pushed(pkgrelroot):
    """create a file named PUSHED in a package build-results root directory"""
    fname = os.path.join(pkgrelroot,'PUSHED')
    if os.path.isfile(fname):
        return
    if DEBUG:
        print 'Creating %s' % fname
        return
    try:
        f = open(fname,'w')
        f.close()
    except IOError, (err, strerr):
        print 'ERROR: %s: %s' % (strerr,fname)
        raise IOError, (err, strerr)


def prune_needsign_tree(needsignroot):
    for (name,pkgrelroots) in get_build_results(needsignroot):
        validbuilds = pkgrelroots
        
        # Delete those builds which are marked as PUSHED and old enough.
        for pkgrelroot in pkgrelroots:
            flagname = os.path.join(pkgrelroot,'PUSHED')
            if not os.path.isfile(flagname):
                continue
            mtime = os.path.getmtime(flagname)
            # Check if there are *.rpm newer than the flag
            # (When exactly is that possible? old-style kernel mods?)
            changed = False
            for root, dirs, files in os.walk(pkgrelroot):
                if changed:
                    break
                for f in fnmatch.filter(files, '*.rpm'):
                    if os.path.getmtime(os.path.join(root, f)) > mtime:
                        changed = True
                        break
            if changed:
                print 'New packages in PUSHED %s, clearing flag' % pkgrelroot
                if not DEBUG:
                    os.remove(flagname)
                continue
            if ( time.time()-mtime > 3600*48 ):
                print 'Removing old %s' % pkgrelroot
                if not DEBUG:
                    shutil.rmtree(pkgrelroot)
                validbuilds.remove(pkgrelroot)

        # Now re-examine the remaining builds and mark unneeded ones as PUSHED.
        # TODO: white-list some packages, such as "kmod-*"?
        pkgrelroots = validbuilds
        pkgroot = os.path.join(needsignroot,name)
        if len(pkgrelroots) < 2: # only one release or empty dir
            # Clean up empty package name directories.
            if not len(pkgrelroots):
                try:
                    Utils.debugprint('Removing empty directory %s' % pkgroot)
                    if not DEBUG:
                        os.rmdir(pkgroot)
                except OSError, e:
                    print e
                    pass
            continue  # with next name
        Utils.debugprint( '%s release(s) for %s: %s' % (len(pkgrelroots),name,' '.join(map(lambda f: os.path.basename(f),pkgrelroots))) )
        # We assume this release to be the newest.
        relroot = pkgrelroots[0]
        # There can be only one src.rpm in this dir, since relroot
        # and src.rpm filename are unique (due to NVR).
        srcrpms = find_files(relroot,'*.src.rpm')
        # Currently, directories can be empty though, unless we clean up
        # the repodir regularly.
        if not len(srcrpms):
            continue
        srcrpm = srcrpms[0]
        (n,a,e,v,r) = naevr(srcrpm)
        # Now compare with the other releases.
        for nextrelroot in pkgrelroots[1:]:
            nextsrcrpms = find_files(nextrelroot,'*.src.rpm')
            if not len(nextsrcrpms):
                continue
            nextsrcrpm = nextsrcrpms[0]
            (nextn,nexta,nexte,nextv,nextr) = naevr(nextsrcrpm)
            # 1 means: e,v,r is higher than nexte,nextv,nextr
            if rpmUtils.miscutils.compareEVR((e,v,r),(nexte,nextv,nextr)) == 1:
                Utils.debugprint('Ignoring: %s' % nextrelroot)
                mark_pkg_pushed(nextrelroot)
            else:
                Utils.debugprint('Ignoring: %s' % relroot)
                mark_pkg_pushed(relroot)
                # Make this the next newest package for ongoing comparison.
                relroot = nextrelroot
                (n,a,e,v,r) = (nextn,nexta,nexte,nextv,nextr)


def naevr(pkg):
    """return nevra from the package srpm"""

    hdr = rpmUtils.miscutils.hdrFromPackage(ts, pkg)
    name = hdr['name']
    ver = hdr['version']
    rel = hdr['release']
    arch = hdr['arch']
    epoch = hdr['epoch']
    if epoch is None:
        epoch = 0
    
    return (name, arch, epoch, ver, rel)


def getexcludearch(pkgpath,reporoot):
    """Returns list of excluded archs for a binary rpm.
    Needs access to the repository root directory where it
    examines the source rpm."""
    
    global ts, srpmlocdict
    hdr = rpmUtils.miscutils.hdrFromPackage(ts,pkgpath)
    source_rpm = hdr['sourcerpm']
    if not DEBUG:
        srpmloc = os.path.join(reporoot, 'SRPMS', source_rpm)
    else:  # in debug mode we cannot access signed/installed rpms
        srpmloc = srpmlocdict[source_rpm]
    hdr = rpmUtils.miscutils.hdrFromPackage(ts,srpmloc)
    return hdr['excludearch']


def sign_pkgs(filelist):
    """gpg sign all the rpms"""
    numfiles = len(filelist)
    if numfiles < 1:
        print "No packages to sign"
        return 0
    if DEBUG:
        return 0

    while numfiles > 0:
        if numfiles > 256:
            files = filelist[:256]
            del filelist[:256]
        else:
            files = filelist
            filelist = []
    
        foo = string.join(files)
        result = os.system('echo %s | xargs rpm --resign' % foo)
        if result != 0:
            return result
        numfiles = len(filelist)

    return 0


class PushWarning(Exception):
    pass


def push(dist,needsignroot,destroot,name,pkgrelroot):
    """push the files found within a single package build-results directory"""
    rollback = []
    try:
        push_with_rollback(rollback,dist,needsignroot,destroot,name,pkgrelroot)
    except:
        print 'ERROR: Rollback:', rollback
        for f in rollback:
            if DEBUG:
                break
            try:
                os.remove(f)
            except:
                pass
        raise


def push_with_rollback(rollback,dist,needsignroot,destroot,name,pkgrelroot):
    print '  %s-%s' % (name,os.path.basename(pkgrelroot))
    
    filedict = {}
    filedict['srpm'] = []
    filedict['rpm'] = []
    filedict['debuginfo'] = []
    filedict['other'] = []
    # Match the build-results files to what list they should be in.
    for file in find_files(pkgrelroot):
        if file.endswith('.rpm'):
            if file.find('debuginfo') != -1:
                which = 'debuginfo' 
            elif file.endswith('.src.rpm'):
                which = 'srpm'
            else:
                which = 'rpm'
        else:
            which = 'other'
        filedict[which].append(file)

    buildreportinfo = None

    # In the run-file we store the package NVR ids for the build report.
    # Content in that file also serves as an indication whether there is
    # a "push" to finish, i.e. whether we need to sync the repository
    # to the public master site.
    runfilename = getrunfilename(dist)
    rundirfile = open(runfilename,'a')

    # go through each package and move it to the right arch location
    # if it is a src.rpm package, move it into the SRPMS location
    # if it is a noarch package, copy2 it to all arch locations
    # if it is a debuginfo package, move it into the 'debug' dir for that arch

    package = filedict['srpm'][0]
    (n,a,e,v,r) = naevr(package)
    pkg_fn = os.path.basename(package)
    global srpmlocdict  # debug only
    srpmlocdict[pkg_fn] = package  # debug only
    destloc = os.path.join(destroot, 'SRPMS', pkg_fn)
    if not os.path.exists(destloc):
        rollback.append(destloc)
        Utils.install_move(package,destloc)
        buildreportinfo = '%s-%s-%s\n' % (n,v,r)
    else:  # src.rpm published before, exclude entire build job
        mark_pkg_pushed( os.path.join(needsignroot,name,os.path.basename(pkgrelroot)) )
        raise PushWarning, 'WARNING: %s published before' % pkg_fn

    for package in filedict['rpm'] + filedict['debuginfo']:
        pkg_fn = pkg_destfn = os.path.basename(package)
        if package in filedict['debuginfo']:
            pkg_destfn = 'debug/' + pkg_fn
        (n,a,e,v,r) = naevr(package)

        if a == 'noarch':
            excludearch = getexcludearch(package,destroot)
            linkloc = None
            for basearch in cfg.archdict[dist]:
                if basearch in excludearch:
                    print 'EXCLUDEARCH: Not releasing %s for %s.' % (pkg_fn,basearch)
                    continue  # with next basearch
                destloc = os.path.join(destroot, basearch, pkg_destfn)
                rollback.append(destloc)
                if linkloc:
                    Utils.install_link_or_copy(linkloc,destloc)
                else:
                    Utils.install_copy(package,destloc)
                    linkloc = destloc
            continue  # with next package

        # rpmUtils.arch.getBaseArch(a)
        elif a in ['i386', 'i486', 'i586', 'i686', 'athlon']:
            basearch = 'i386'
        
        elif a in ['x86_64', 'ia32e', 'amd64']:
            basearch = 'x86_64'
        
        elif a in ['ppc', 'ppc64', 'ppc32']:
            basearch = 'ppc'

        else:
            print 'Unknown arch %s' % a
            continue  # with next package

        destloc = os.path.join(destroot, basearch, pkg_destfn)
        rollback.append(destloc)
        Utils.install_move(package,destloc)

    # Mark successfully signed packages as PUSHED.
    mark_pkg_pushed( os.path.join(needsignroot,name,os.path.basename(pkgrelroot)) )
    rollback = []
    rundirfile.write(buildreportinfo)
    rundirfile.close()
    

def copy_sign_move(dist):
    """Copies, signs and moves packages for the given dist.
    Returns (errcode, changed) where errcode is an error code and changed
    is a boolean indicating whether the target repo was changed."""

    distdir = '%s-%s-%s' % (cfg.distro, dist, cfg.project)
    needsignroot = os.path.join(cfg.stagesdir, distdir)
    destroot = os.path.join(cfg.treedir, dist)
    changed = False
    
    repodirs = [os.path.join(destroot, 'SRPMS')]
    for arch in cfg.archdict[dist]:
        repodirs.append(os.path.join(destroot, arch))
        repodirs.append(os.path.join(destroot, arch, 'debug'))
    for repodir in repodirs:
        # We check for changes already here in case the repo has changed
        # due to external activities such as removing files etc, and will
        # recheck it again later if needed when we're done with this sign
        # batch.
        if not changed:
            changed = Utils.is_repo_changed(repodir)
            if changed:
                print "Dist %s (%s) was externally changed" % (dist, repodir)
        if not DEBUG and not os.path.exists(repodir):
            os.makedirs(repodir)

    repolockname = os.path.join(needsignroot,REPO_LOCKFILE_NAME)
    repolock = LockFile(name=repolockname,blocking=True)
    try:
        print 'Waiting for repository lock on %s:' % distdir,
        sys.stdout.flush()
        repolock.lock()
        print 'OK'
    except IOError, (err, strerr):
        print "ERROR: lockfile %s failure: %s (error %d)" % (repolockname, strerr, err)
        sys.exit(err)
        
    prune_needsign_tree(needsignroot)
    results = get_build_results(needsignroot,droppushed=True)
    # TODO: room for black-list checks.
    print 'Package directories found: %d' % len(results)
    if len(results) == 0:
        return 0, changed
    
    print 'Copying build results to temporary working directory:'
    signtmpdir = tempfile.mkdtemp('','.push',cfg.treedir)
    if signtmpdir == cfg.treedir: # paranoid, should never happen
        sys.exit(errno.EPERM)
    try:
        for (name,pkgrelroots) in results:
            destpkgroot = os.path.join(signtmpdir,name)
            if not os.path.exists(destpkgroot):
                os.makedirs(destpkgroot)
            for pkgrelroot in pkgrelroots:
                vr = os.path.basename(pkgrelroot)
                print '  %s-%s' % (name,vr)
                shutil.copytree(pkgrelroot,os.path.join(destpkgroot,vr))
    except: # everything is fatal
        print 'ERROR: Creating temporary working copy failed.'
        shutil.rmtree(signtmpdir)
        raise

    # Now we have a temporary copy of everything from the needsign repository
    # we want. Build results as  ./foo/1.0-1/  directories in signtmpdir.
    repolock.unlock()

    try:
        print "Signing Packages:"
        rv = sign_pkgs( find_files(signtmpdir,'*.rpm') )
        if rv:
            print "Error signing packages! Please be patient - cleaning up."
            raise Exception

        print "Copying packages into repositories:"
        global srpmlocdict
        srpmlocdict = {} # debug only
        results = get_build_results(signtmpdir)
        for (name,pkgrelroots) in results:
            for pkgrelroot in pkgrelroots:
                try:
                    push(dist,needsignroot,destroot,name,pkgrelroot)
                except PushWarning, e:
                    print e
    except:
        shutil.rmtree(signtmpdir)
        raise

    print('Removing tmp tree: %s' % signtmpdir)
    shutil.rmtree(signtmpdir)

    # All done, now check if something changed unless we already know it did:
    if not changed:
        for repodir in repodirs:
            changed = Utils.is_repo_changed(repodir)
            if changed:
                Utils.debugprint("Dist %s (%s) was changed" % (dist, repodir))
                break

    return 0, changed

# ====================================================================

import datetime
import smtplib
from email.MIMEText import MIMEText

def email_list(distlist):
    """email mailing list with the new package listing"""

    body = ''
    for dist in cfg.alldists:  # we do this for sorting the dists
        if not dist in distlist:
            continue
        uniqued = rpmUtils.miscutils.unique( getlinesfromrunfile(dist) )
        uniqued.sort()
        if not uniqued:
            continue
    
        body += "\nPackages built and released for %s %s: %s \n\n" % (cfg.project_hr, dist, len(uniqued))
        for pkg in uniqued:
            add = '    %s\n' % (pkg)
            body += add
        body += '\n'

    if not body:
        return

    body += cfg.mail_footer
    
    msg = MIMEText(body)
    subject = '%s Package Build Report %s' % (cfg.project_hr,datetime.date.today())
    msg['Subject'] = subject
    msg['From'] = cfg.mail_from
    msg['To'] = cfg.mail_to
    Utils.debugprint( msg.as_string() )
    if not DEBUG:
        s = smtplib.SMTP()
        if cfg.smtp_server:
            s.connect(cfg.smtp_server)
        else:
            s.connect()
        s.sendmail(cfg.mail_from, [cfg.mail_to], msg.as_string())
        s.close()
    
    # Build report has been mailed, we can delete the run-files.
    for dist in distlist:
        emptyrunfile(dist)

# ====================================================================

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print 'Usage: %s <project> <release|all> [release]...\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)

    cfg = Utils.load_config_module(sys.argv[1])

    os.umask(cfg.signersumask)
    Utils.signer_gid_check(cfg.signersgid)
    if cfg.opts.signkeycheck:
        if cfg.signkeyname != os.popen('rpm --eval %_gpg_name','r').read().rstrip():
            print 'ERROR: Configure ~/.rpmmacros for proper GPG signing before running this!'
            sys.exit(errno.EPERM)

    if '-f' in sys.argv[2:]:
        sys.argv.remove('-f')
        opts.force = True
    
    diststopush = []
    for d in sys.argv[2:]:
        if d == 'all':
            diststopush = cfg.alldists
            continue
        if d not in cfg.alldists:
            print "ERROR: No Distribution named '%s' found" % d
            sys.exit(errno.EINVAL)
        if d not in diststopush:
            diststopush.append(d)
    Utils.debugprint(diststopush)

    if not os.path.exists(cfg.rundir):
        os.makedirs(cfg.rundir)
    lockfile = os.path.join(cfg.rundir,'pushscript.lock')
    lock = LockFile(lockfile)
    try:
        lock.lock()
    except IOError:
        print 'ERROR: script locked via lockfile %s - it seems to be running already' % lockfile
        sys.exit(errno.EPERM)

    changed = []      # dists with changes in them
    mustfinish = []   # dists with pending build report
    totalchanges = 0
    for dist in diststopush:
        result, repochanged = copy_sign_move(dist)
        if result:
            sys.exit(result)
        if repochanged:
            changed.append(dist)
        # len(getlinesfromrunfile(dist)) is the number of build jobs
        # per dist which have been pushed.
        buildjobs = len( getlinesfromrunfile(dist) )
        totalchanges += buildjobs
        if buildjobs:
            mustfinish.append(dist)
    print 'Total number of pushed build jobs to report: %d' % totalchanges

    # Option -f re-runs repobuild/repoview for all dists to push,
    # even if no new packages have been pushed for a dist.
    if opts.force:
        changed = diststopush

    for dist in changed:
        if cfg.opts.repomanage:
            RepoManage.main(cfg,dist)
        RepoBuild.main(cfg,dist)

    # TODO: multilib resolver hook
    MultiLib.main(changed)

    if changed:
        if cfg.opts.doublesync:
            Utils.run_and_check(cfg.sync_cmd)

    for dist in changed:
        if cfg.opts.repoview:
            RepoView.main(cfg,dist)

    if changed or mustfinish:
        Utils.run_and_check(cfg.sync_cmd)

        if cfg.opts.mail:
            email_list(diststopush)

        for cmd in cfg.post_cmds:
            Utils.run_and_check(cmd)

    lock.unlock()
    sys.exit(0)


--- NEW FILE RepoBuild.py ---
#!/usr/bin/python -t
# -*- mode: Python; indent-tabs-mode: nil; -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import errno, os, sys
import Utils

def main(cfg,dist):
    if not cfg.archdict.has_key(dist):
        print "No distribution release named '%s' found" % dist
        sys.exit(errno.EINVAL)

    Utils.create_src_repo(cfg,dist)  # source rpms
    for arch in cfg.archdict[dist]:
        Utils.create_arch_repo(cfg,dist,arch)  # binary+debuginfo rpms


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print 'Usage: %s <project> <release>\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)
    
    cfg = Utils.load_config_module(sys.argv[1])

    me = os.getcwd()
    Utils.signer_gid_check(cfg.signersgid)
    os.umask(cfg.signersumask)
    main(cfg,sys.argv[2])
    os.chdir(me)


--- NEW FILE RepoManage.py ---
#!/usr/bin/python -t
# -*- mode: Python; indent-tabs-mode: nil; -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import errno, os, sys
import Utils

def do_repo_stuff(cfg, repodir, keep=2, nomanage=None):
    print 'Processing: %s' % repodir
    print 'cleaning up older packages (keeping %d latest)' % (keep)
    repomanage = '%s -c -k%d -o %s' % (cfg.repomanage, keep, repodir)
    if nomanage:
        cmd = '%s | grep -v %s | xargs rm -f' % (repomanage, nomanage)
    else:
        cmd = '%s | xargs rm -f' % repomanage
    Utils.run_and_check(cmd)
        

def main(cfg,dist):
    if not cfg.archdict.has_key(dist):
        print "No distribution release named '%s' found" % dist
        sys.exit(errno.EINVAL)
	
    destdir = os.path.join(cfg.treedir, dist)
    keep = (dist == 'development') and 1 or 2

    do_repo_stuff(cfg,os.path.join(destdir, 'SRPMS'), keep, cfg.repomanage_keepdict.get(dist))

    # arch repo creation
    for arch in cfg.archdict[dist]:
        repodir = os.path.join(destdir, arch)
        do_repo_stuff(cfg, repodir, keep, cfg.repomanage_keepdict.get(dist))


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print 'Usage: %s <project> <release>\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)
    
    cfg = Utils.load_config_module(sys.argv[1])

    me = os.getcwd()
    Utils.signer_gid_check(cfg.signersgid)
    os.umask(cfg.signersumask)
    main(cfg,sys.argv[2])
    os.chdir(me)


--- NEW FILE RepoView.py ---
#!/usr/bin/python -t
# -*- mode: Python; indent-tabs-mode: nil; -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import errno, os, sys
import Utils

def do_repoview(cfg,repodir):
    print 'Generating repoview in %s' % repodir
    cmd = '%s -q %s' % (cfg.repoview,repodir)
    Utils.run_and_check(cmd)            

    # if there's a debug subdir, make that a repo, too.
    dbg_repodir = os.path.join(repodir, 'debug')
    if os.path.exists(dbg_repodir):
        print 'Generating repoview in %s' % dbg_repodir
        cmd = '%s -q %s' % (cfg.repoview,dbg_repodir)
        Utils.run_and_check(cmd)


def main(cfg,dist):
    if not cfg.archdict.has_key(dist):
        print "No distribution release named '%s' found" % dist
        sys.exit(errno.EINVAL)
    
    destdir = os.path.join(cfg.treedir, dist)
    do_repoview(cfg,os.path.join(destdir, 'SRPMS'))

    # arch repo creation
    for arch in cfg.archdict[dist]:
        repodir = os.path.join(destdir, arch)
        do_repoview(cfg,repodir)


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print 'Usage: %s <project> <release>\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)
    
    cfg = Utils.load_config_module(sys.argv[1])

    me = os.getcwd()
    Utils.signer_gid_check(cfg.signersgid)
    os.umask(cfg.signersumask)
    main(cfg,sys.argv[2])
    os.chdir(me)


--- NEW FILE Utils.py ---
#!/usr/bin/python -t
# -*- mode: Python; indent-tabs-mode: nil; -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import errno
import fnmatch
import os, sys
import shutil
import stat, tempfile

compsname = 'comps.xml'

DEBUG = False

def setdebug(onoff):
    global DEBUG
    DEBUG = onoff
    
def debugprint(msg):
    if DEBUG:
        print msg

def run_and_check(cmd):
    debugprint(cmd)
    if not DEBUG:
        result = os.system(cmd)
        if result != 0:
            print >> sys.stderr, 'Error running command: %s ' % cmd
            if result > 127:
                sys.exit(1)
            sys.exit(result)


def load_config_module(project):
    import imp
    name = 'Config_'+project
    try:
        (fileobj, pathname, description) = imp.find_module(name)
        cfg = imp.load_module(name,fileobj,pathname,description)
        fileobj.close()
        return cfg
    except ImportError, e:
        print e
        sys.exit(errno.EIO)


def signer_gid_check(gid):
    if os.getgid() != gid:
        grpname = '(unknown)'
        try:
            import grp
            grpname = grp.getgrgid(gid)[0]
        except:
            print 'WARNING: Could not get group name for gid %d' % gid
        print 'ERROR: Change into the %s group before running this!  Use "newgrp %s".' % (grpname, grpname)
        sys.exit(errno.EPERM)


def install_copy(src,dest,overwrite=False):
    """shutil.copy2 a file, but by default don't overwrite destination"""
    if not overwrite and os.path.exists(dest):
        print('WARNING: %s already exists, ignoring new one' % dest)
        return
    debugprint('Copying %s to %s' % (src,dest))
    if not DEBUG:
        shutil.copy2(src,dest)


def install_move(src,dest,overwrite=False):
    """shutil.move a file, but by default don't overwrite destination"""
    if not overwrite and os.path.exists(dest):
        print('WARNING: %s already exists, ignoring new one' % dest)
        return
    debugprint('Moving %s to %s' % (src,dest))
    if not DEBUG:
        shutil.move(src,dest)


def install_link(src,dest):
    """os.link a file, but don't overwrite destination"""
    if os.path.exists(dest):
        print('WARNING: %s already exists, ignoring new one' % dest)
        return
    debugprint('Linking %s <- %s' % (src,dest))
    if not DEBUG:
        os.link(src,dest)


def install_link_or_copy(src,dest):
    """try install_link, if it fails, use install_copy"""
    linked = False
    try:
        install_link(src,dest)
        linked = True
    except OSError, e:
        print 'WARNING: Linking failed (%s), trying to copy...' % e
    if not linked:
        install_copy(src,dest)


def create_repository(cfg,repodir):
    """create/update repository metadata for a given directory"""

    print 'Creating repository %s' % repodir
    
    if not os.path.exists(repodir):
        os.makedirs(repodir)
    
    # TODO: Why remove the repodata dir? Isn't that entirely createrepo's
    # work? (also further below for "debug")
    # ? -> https://devel.linux.duke.edu/bugzilla/show_bug.cgi?id=595
    rpdata = os.path.join(repodir, 'repodata')
    debugprint('removing tree %s' % rpdata)
    if os.path.exists(rpdata) and not DEBUG:
        shutil.rmtree(rpdata)
    
    compsarg = ''
    if os.path.exists( os.path.join(repodir,compsname) ):
        compsarg = '-g %s ' % compsname
    excludearg = ''
    if os.path.exists( os.path.join(repodir,'debug') ):
        excludearg = "-x \'*debuginfo*\'"
    cmd = '%s -c %s -q %s %s %s' % (cfg.createrepo, cfg.cr_cachedir, compsarg, excludearg, repodir)
    run_and_check(cmd)


def create_arch_repo(cfg,dist,arch):
    """create/update repository metadata for a given dist+arch pair and
its 'debug' sub-directory, if available"""
    repodir = os.path.join(cfg.treedir, dist, arch)
    create_repository(cfg,repodir)
    # If there's a debug subdir, make that a repo, too.
    dbg_repodir = os.path.join(repodir, 'debug')
    if os.path.exists(dbg_repodir):
        create_repository(cfg,dbg_repodir)


def create_src_repo(cfg,dist):
    """create/update repository metadata for a given dist"""
    create_repository( cfg, os.path.join(cfg.treedir,dist,'SRPMS') )


def is_repo_changed(repodir):
    """Checks if the repository has changed and needs to be reindexed"""
    ref_file = os.path.join(repodir, 'repodata', 'repomd.xml')
    if not os.path.exists(ref_file):
        return True
    ref_mtime = os.path.getmtime(ref_file)
    if os.path.getmtime(repodir) > ref_mtime:
        return True
    ignored_dirs = (
        os.path.join(repodir, 'repodata'),
        os.path.join(repodir, 'debug'),
        )
    for root, dirs, files in os.walk(repodir):
        next = False
        for ignored in ignored_dirs:
            if (root + "/").find(ignored + "/") == 0:
                next = True
        if next:
            continue
        for d in map(lambda x: os.path.join(root, x), dirs):
            if d in ignored_dirs:
                continue
            elif os.path.getmtime(d) > ref_mtime:
                return True
        for f in fnmatch.filter(files, '*.rpm'):
            if os.path.getmtime(os.path.join(root, f)) > ref_mtime:
                return True
    return False


def fix_mdcache_access(workdir,cachedir):
# Work around explicit directory mode 0755 in yum/repos.py (that
# is too restrictive for our extras_signers group) and an utime
# access denied problem in urlgrabber (file ownership is needed,
# group ownership is insufficient).
#
# We copy the mdcache tree to a temporary directory in order to
# become the owner of all files, then remove the copied tree and fix
# up directory modes. For this to work flawlessly, all files must be
# readable by our group.
    try:
        tmpdir = tempfile.mkdtemp('','.mdcache.tmp',workdir)
        if tmpdir == workdir: # paranoid, should never happen
            raise Exception
    except:
        sys.exit(errno.EIO)
    if os.path.isdir(cachedir):
        tmpcachedir = os.path.join(tmpdir,'mdcache')
        try:
            shutil.copytree(src=cachedir,dst=tmpcachedir,symlinks=True)
        except:
            print 'FATAL ERROR: mdcache copytree failed'
            print '%s must be writable\n%s must be readable' % (workdir, cachedir)
            shutil.rmtree(tmpdir)
            sys.exit(1)
        for root, dirs, files in os.walk(tmpcachedir):
            for file in files:
                fullpath = os.path.join(root,file)
                filemode = stat.S_IMODE( os.stat(fullpath).st_mode )
                filemode |= stat.S_IWGRP
                os.chmod(fullpath,filemode)
        shutil.rmtree(cachedir)
        shutil.move(src=tmpcachedir,dst=cachedir)
        shutil.rmtree(tmpdir)




--- NEW FILE extras-push ---
#!/usr/bin/python -t
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

cfg = 'Extras'

if __name__ == '__main__':
    import os, sys, errno
    if len(sys.argv) < 2:
        print 'Usage: %s <release|all> [release]...\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)
    cmd = os.path.join(sys.path[0],'Push.py')
    args = [cmd]+[cfg]+sys.argv[1:]
    os.execvp(cmd,args)


--- NEW FILE extras-repobuild ---
#!/usr/bin/python -t
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

cfg = 'Extras'

if __name__ == '__main__':
    import os, sys, errno
    if len(sys.argv) < 2:
        print 'Usage: %s <release>\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)
    cmd = os.path.join(sys.path[0],'RepoBuild.py')
    args = [cmd]+[cfg]+sys.argv[1:]
    os.execv(cmd,args)


--- NEW FILE extras-repomanage ---
#!/usr/bin/python -t
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

cfg = 'Extras'

if __name__ == '__main__':
    import os, sys, errno
    if len(sys.argv) < 2:
        print 'Usage: %s <release>\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)
    cmd = os.path.join(sys.path[0],'RepoManage.py')
    args = [cmd]+[cfg]+sys.argv[1:]
    os.execvp(cmd,args)


--- NEW FILE extras-repoview ---
#!/usr/bin/python -t
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

cfg = 'Extras'

if __name__ == '__main__':
    import os, sys, errno
    if len(sys.argv) < 2:
        print 'Usage: %s <release>\n' % os.path.basename(sys.argv[0])
        sys.exit(errno.EINVAL)
    cmd = os.path.join(sys.path[0],'RepoView.py')
    args = [cmd]+[cfg]+sys.argv[1:]
    os.execvp(cmd,args)




More information about the fedora-extras-commits mailing list