#!/usr/bin/python
# This file is part of the Falcon repository manager
# Copyright (C) 2005-2008 Dennis Kaarsemaker
# See the file named COPYING in the root of the source tree for license details
#
# falcon-build-local-queue

# Even though f-b-l-q is a standalone app, it can still use the translations if 
# they are available
import gettext
from gettext import gettext as _
gettext.bindtextdomain('falcon','/usr/share/locale')
gettext.textdomain('falcon')

import re, gzip, tarfile, sys, os, subprocess, time, fcntl

class dummy(object): pass
conf = dummy()
conf.origin       = None
conf.incoming     = None
conf.result       = None
conf.buildcommand = None
conf.arch         = subprocess.Popen(['dpkg', '--print-architecture'], stdout=subprocess.PIPE).communicate()[0].strip()
conf.buildlog     = '%(result)s/buildlog_%(origin)s-%(pocket)s-%(arch)s.%(name)s_%(buildresult)s.txt'

# Function based on build.py/build
file_re = re.compile(r'\n [0-9a-f]+ \d+ (\S+)', re.I)
def get_pocket(dsc):
    files = file_re.findall(open(dsc).read())
    found_debchangelog = False 
    # Look for debian/changelog
    for f in files:
        if f.endswith('diff.gz'):
            g = gzip.open(os.path.join(conf.incoming,f))
            while True:
                l = g.readline()
                if not l:
                    break
                l = l.strip()
                if l.startswith('+++') and l.endswith('/debian/changelog'):
                    found_debchangelog = True
                elif found_debchangelog and 'urgency' in l:
                    return l[l.find(')')+1:l.find(';')].strip()
            break
    if not found_debchangelog:
        tf = None
        for f in files:
            if f.endswith('tar.gz'):
                tf = tarfile.open(name=os.path.join(conf.incoming, f), mode='r:gz')
            elif f.name.endswith('tar.bz2'):
                tf = tarfile.open(name=os.path.join(conf.incoming, f), mode='r:bz2')
            if tf:
                for n in tf.getnames():
                    if n.endswith('debian/changelog'):
                        found_debchangelog = True
                        l = tf.extractfile(n).readline()
                        return l[l.find(')')+1:l.find(';')].strip()
    print _("E: Can't find debian/changelog for %s" % dsc)
    sys.exit(1)

# Main
if not os.path.exists(os.path.join(os.getenv('HOME'), '.falcon')):
    os.mkdir(os.path.exists(os.path.join(os.getenv('HOME'), '.falcon')))
lockfd = open(os.path.join(os.getenv('HOME'), '.falcon', 'buildlock'),'a')
try:
    fcntl.flock(lockfd,fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    print _("E: Repository is locked by another process")
    sys.exit(1)

cf = os.path.join(os.getenv('HOME'), '.falcon', 'buildconf')
if not os.path.exists(cf):
    print _('E: configfile %s not found' % cf)
    
for l in open(cf):
    l = l.strip()
    if not l or l.startswith('#'):
        continue
    if '=' not in l:
        print _('E: Malformed line in configfile')
    key, val  = l.split('=', 1)
    setattr(conf, key.strip(), val.strip())
# Step one: clean up everything older than 24 hours
# Uncomment this if you don't want to run tmpreaper
#max = 86400
#now = time.time()
#for f in os.listdir(conf.incoming):
#    mtime = os.path.getmtime(os.path.join(conf.incoming, f))
#    if now - mtime > max:
#        os.unlink(os.path.join(conf.incoming, f))
#for f in os.listdir(conf.result):
#    mtime = os.path.getmtime(os.path.join(conf.result, f))
#    if now - mtime > max:
#        os.unlink(os.path.join(conf.result, f))

# Step two: built packages that haven't been built yet
for f in os.listdir(conf.incoming):
    if not f.endswith('.dsc'):
        continue
    name = f.replace('.dsc','')
    # Has it been built?
    if os.path.exists(os.path.join(conf.result, '%s_%s.changes' % (name, conf.arch))):
        continue
    # Or has it failed?
    pocket = get_pocket(os.path.join(conf.incoming, f))
    ctx = {'result': conf.result, 'origin': conf.origin, 'arch': conf.arch, 'pocket': pocket, 'name': name, 'buildresult': 'FULLYBUILT'}
    if os.path.exists((conf.buildlog % ctx) + '.gz'):
        continue
    ctx.update(buildresult='FAILEDTOBUILD')
    if os.path.exists((conf.buildlog % ctx) + '.gz'):
        continue
    ctx.update(buildresult='BUILDING')
    if os.path.exists((conf.buildlog % ctx) + '.gz'):
        continue


    # Ok, this is the first attempt. Build it!
    log = conf.buildlog % ctx
    logfd = open(log,'w')
    ctx.update(dsc=os.path.join(conf.incoming, f))
    print _("* Building %s, log will be written to %s") % (f, log)
    proc = subprocess.Popen((conf.buildcommand % ctx).split(),
                            stdout  = logfd,
                            stderr  = subprocess.STDOUT,
                            bufsize = 1)
    ret = proc.wait()
    # Rename the log
    if ret:
        ctx.update(buildresult='FAILEDTOBUILD')
    else:
        ctx.update(buildresult='FULLYBUILT')
    newlog = conf.buildlog % ctx
    os.rename(log, newlog)
    subprocess.Popen(['gzip', newlog]).wait()

