#!/usr/bin/env python
# -*- Mode: python -*-

#    Copyright (C) 2001-2006 Artifex Software Inc.
# 
# This file is part of GNU ghostscript
#
# GNU ghostscript is free software; you can redistribute it and/or
# modify it under the terms of the version 2 of the GNU General Public
# License as published by the Free Software Foundation.
#
# This software is provided AS-IS with no warranty, either express or
# implied. That is, 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.,
# 51 Franklin Street, Fifth Floor, Boston, MA, 02110-1301.


# $Id: run_nightly,v 1.8 2007/08/01 14:26:58 jemarch Exp $

import os
import sys
import re
import time
import string
import gsconf
import anydbm
from popen2 import Popen4

# configuration variables

NOW = time.time()
YESTERDAY = time.strftime("%Y%m%d", time.localtime(NOW - (24*60*60)))
YESTERDAY_CTIME = time.ctime(NOW - (24*60*60))

def change_gsproduct(file):
    tmpfile = "%s.tmp" % (file,)

    startre = re.compile("^#ifndef\ GS_PRODUCT$")
    changere = re.compile("^.*?\"[A-Za-z -]+\".*?$")
    endre = re.compile("^$")

    old = open(file, "r")
    new = open(tmpfile, "w")

    state = 0
    for line in old.readlines():
        if state == 0:
            m = startre.search(line)
            if m:
                state = 1
                
            new.write(line)
        elif state == 1:
            m = changere.search(line)
            if m:
                state = 2
                new.write("\t\"AFPL Ghostscript\"\n")
            else:
                new.write(line)
        elif state == 2:
            m = endre.search(line)
            if m:
                state = 0

            new.write(line)


    old.close()
    new.close()

    os.unlink(file)
    os.rename(tmpfile, file)

def read_fnord(file):
    if os.path.exists(file):
        f = open(file)
        keyword = f.readline()
        keyword = keyword.strip()
        f.close()
        return keyword
    else:
        return ''

def sendmail(frm, to, subject, text):
    import smtplib

    keyword = read_fnord(gsconf.codedir + 'fnord')
    if keyword:
        msg = 'From: %s\r\nTo: %s\r\nSubject: %s\r\nX-Fnord: %s\r\n\r\n%s' % (frm, to, subject, keyword, text)
    else:
        msg = 'From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s' % (frm, to, subject, text)

    server = smtplib.SMTP(gsconf.mail_server)
    server.sendmail(frm, to, msg)
    server.quit()

def die(msg):
    sendmail(gsconf.report_from, gsconf.report_to, "error running regression", msg)
    sys.exit(0)

def update_ghostscript():
    cwd = os.getcwd()
    os.chdir(gsconf.gsroot)
    
    if os.system("date >> " + gsconf.update_log_stdout) != 0: return (1, None, None, None)
    if os.system("date >> " + gsconf.update_log_stderr) != 0: return (1, None, None)

    starttime = time.time()

    # undo our product name alteration	
    f = "%s/src/gscdef.c" % (gsconf.gsroot,)
    if os.path.exists(f):
	os.unlink(f)

    if os.system("svn update >> " + gsconf.update_log_stdout + " 2>> " +
                 gsconf.update_log_stderr) != 0: return (1, None, None, None)

    os.system("echo 'svn update complete' >> " + gsconf.update_log_stdout)

    endtime = time.time()
    
    revision = "unknown"
    p = os.popen("svn info")
    for line in p:
	if line[:10] == "Revision: ":
	    revision = line[10:]
	    break

    os.system("echo 'revision is " + str(revision) + "' >> " + 
		gsconf.update_log_stdout)

    change_gsproduct("%s/src/gscdef.c" % (gsconf.gsroot,))

    os.system("echo 'product change complete' >> " + gsconf.update_log_stdout)
	
    if os.system("./autogen.sh --prefix=/home/regression/gshead/ > " + 
		gsconf.config_log_stdout + " 2> " +
                gsconf.config_log_stderr) != 0: return (2, None, None, revision)

    os.system("echo 'configuration complete' >> " + gsconf.update_log_stdout)

    if os.system("make clean > /dev/null 2> /dev/null") != 0:
        return (-1, None, None, revision)

    os.system("echo 'make clean complete' >> " + gsconf.update_log_stdout)
    
    if os.system("make > " + gsconf.make_log_stdout + " 2> " +
                 gsconf.make_log_stderr) != 0: return (3, None, None, revision)

    os.system("echo 'make complete' >> " + gsconf.update_log_stdout)

    if os.system("make install > " + gsconf.install_log_stdout + " 2> " + \
                 gsconf.install_log_stderr) != 0: return (4, None, None, revision)

    os.system("echo 'make install complete' >> " + gsconf.update_log_stdout)

    return (0, starttime, endtime, revision)

def get_file(f):
    file = open(f, 'r')
    lines = file.readlines()
    file.close()
    return string.join(lines, '')

# set umask
os.umask(0002)

(err, starttime, endtime, revision) = update_ghostscript()
if err != 0:
    if err == 1:
        msg = "Ghostscript update failed updating from SVN.\n\n"
        msg = msg + "stdout log:\n\n"
        msg = msg + get_file(gsconf.update_log_stdout)
        msg = msg + "\nstderr log:\n\n"
        msg = msg + get_file(gsconf.update_log_stderr)
        die(msg)
    elif err == 2:
        msg = "Ghostscript update failed during configuration.\n\n"
        msg = msg + "stdout log:\n\n"
        msg = msg + get_file(gsconf.make_log_stdout)
        msg = msg + "\nstderr log:\n\n"
        msg = msg + get_file(gsconf.make_log_stderr)
        die(msg)
    elif err == 3:
        msg = "Ghostscript update failed during make.\n\n"
        msg = msg + "stdout log:\n\n"
        msg = msg + get_file(gsconf.make_log_stdout)
        msg = msg + "\nstderr log:\n\n"
        msg = msg + get_file(gsconf.make_log_stderr)
        die(msg)
    elif err == 4:
        msg = "Ghostscript update failed during install.\n\n"
        msg = msg + "stdout log:\n\n"
        msg = msg + get_file(gsconf.install_log_stdout)
        msg = msg + "\nstderr log:\n\n"
        msg = msg + get_file(gsconf.install_log_stderr)
        die(msg)
    else:
        die("Unknown error updating Ghostscript")

# rotate and start new log files
try:
    for i in range(int(gsconf.rotate) - 1, 0, -1):
        if os.path.isfile(gsconf.log_stdout + ".%d" % (i,)):
            os.rename(gsconf.log_stdout + ".%d" % (i,),
                      gsconf.log_stdout + ".%d" % (i + 1,))
	if os.path.isfile(gsconf.log_stderr + ".%d" % (i,)):
	    os.rename(gsconf.log_stderr + ".%d" % (i,),
		      gsconf.log_stderr + ".%d" % (i + 1,))
	if os.path.isfile(gsconf.log_regression + ".%d" % (i,)):
	    os.rename(gsconf.log_regression + ".%d" % (i,),
		      gsconf.log_regression + ".%d" % (i + 1,))

    if os.path.isfile(gsconf.log_stdout):
        os.rename(gsconf.log_stdout, gsconf.log_stdout + ".1")
    if os.path.isfile(gsconf.log_stderr):
        os.rename(gsconf.log_stderr, gsconf.log_stderr + ".1")
    if os.path.isfile(gsconf.log_regression):
        os.rename(gsconf.log_regression, gsconf.log_regression + ".1")

    log = open(gsconf.log_stdout, "w")
    log.close()
    log = open(gsconf.log_stderr, "w")
    log.close()
except:
    die("The log files were not able to be rotated and opened")

p = os.popen(gsconf.regression_script + " --track 2>&1")
if p == None:
    die("Could not open and run the regression script.")

regout = '\n\nThe complete list of regressions for today:\n'
pattern = 'ok$'
msg = ''
for line in p.readlines():
    if re.search(pattern, line):
        continue
    regout += line
	
p.close()

# now do the daily diff
diff = 'The following regression changes happened since yesterday\'s report:\n'

p = os.popen(gsconf.diff_script + " " + YESTERDAY + " 2>&1")
if p:
    for line in p.readlines():
        diff = diff + line
    p.close()
else:
    diff = diff + 'no changes\n'

# Get updated baselines
baselines = 'The following files had their baselines updated:\n'
p = Popen4(gsconf.get_baselines + " '" + YESTERDAY_CTIME + "'", 1)
if p:
    for line in p.fromchild.readlines():
        baselines = baselines + line
    p.wait()
else:
    baselines = baselines + 'no updates\n'
baselines += "\n\n"

# Prepend checkout times
times = "SVN checkout for this report started at " + time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime(starttime)) + "\n"
times += "SVN checkout ended at " + time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime(endtime)) + "\n"
times += "complete regression run took %.0f seconds.\n" % (time.time()-NOW)
times += "Testing revision " + revision + "\n"
times += "\n"

# Prepend host information
p = os.popen('hostname -f')
if p:
    hostname = string.strip(p.readline())
    p.close()
else:
    hostname = 'unknown host'
host = "Running regression test on " + hostname + " ("
p = os.popen('uname -m -o')
if p:
    host += string.strip(p.readline())
    p.close()
host += ')\n\n'

# Build the report and capture it in a rotating log file
log = open(gsconf.log_regression, "w")
msg = host + times + baselines + diff
log.write(msg)
log.write(regout)
log.close()

# Always include the main body in the email on Mondays
if time.gmtime().tm_wday == 0:
    msg += regout
# Otherwise trip by size
elif len(regout) < 300*1024:
    msg += regout
else:
    msg += "(report omitted due to length)\n"

retry = 1
while retry:
    try:
        sendmail(gsconf.report_from, gsconf.report_to, 'gs regression report - %s' % (time.strftime('%Y-%m-%d'),), msg)
	time.sleep(5)
	retry = 0
    except:
        pass
