#!/usr/bin/python -u
#----------------------------------------------------------------------
# Name:        build-all.py
# Purpose:     Master build script for building all the installers and
#              such on all the build machines in my lab, and then 
#              distributing the results as needed.
#
#              This will replace the build-all bash script and is
#              needed because the needs of the build have outgrown
#              what I can do with bash.
#
# Author:      Robin Dunn
#
# Created:     05-Nov-2004
# RCS-ID:      $Id: build-all,v 1.35.2.2 2006/04/02 00:58:43 RD Exp $
# Copyright:   (c) 2004 by Total Control Software
# Licence:     wxWindows license
#----------------------------------------------------------------------

import sys
import os
import time
from taskrunner import Job, Task, TaskRunner

#----------------------------------------------------------------------
# Configuration items

class Config:
    def write(self, filename="config", outfile=None):
        if outfile is None:
            f = file(filename, "w")
        else:
            f = outfile
        for k, v in self.__dict__.items():
            f.write('%s="%s"\n' % (k, v))

config = Config()

# the local spot that we put everything when done, before possibly copying 
# to remote hosts
config.STAGING_DIR = "./BUILD"


# host name of the machine to use for windows builds
config.WIN_HOST = "beast"
# Where is the build dir from the remote machine's perspective?
config.WIN_BUILD = "/c/BUILD"


# Just like the above
config.OSX_HOST_panther = "bigmac"
config.OSX_HOST_jaguar = "whopper"
config.OSX_BUILD = "/BUILD"


# Alsmost the same...  See below for hosts and other info
config.LINUX_BUILD = "/tmp/BUILD"


# Upload server locations
config.UPLOAD_HOST = "starship.python.net"
config.UPLOAD_DAILY_ROOT = "/home/crew/robind/public_html/wxPython/daily"
config.UPLOAD_PREVIEW_ROOT = "/home/crew/robind/public_html/wxPython/rc"

# defaults for build options
config.KIND = "dryrun"
config.skipsource = "no"
config.onlysource = "no"
config.skipdocs = "no"
config.skipwin = "no"
config.skiposx = "no"
config.skiplinux = "no"
config.skipclean = "no"
config.skipupload = "no"
config.skipnewdocs = "no"
config.startcohost = "yes"

#----------------------------------------------------------------------
# Define all the build tasks

class Job(Job):
    LOGBASE = "./tmp"

CFGFILE = "./tmp/config"


# Things that need to be done before any of the builds
initialTask = Task([ Job("", ["distrib/all/build-setup", CFGFILE]),
                     Job("", ["distrib/all/build-docs", CFGFILE]),
                     Job("", ["distrib/all/build-sources", CFGFILE]),
                     ])

# Build tasks.  Anything that can be done in parallel (depends greatly
# on the nature of the build machines configurations...) is a separate
# task.

jaguarTask =  Task( Job("whopper.23",
                        ["distrib/all/build-osx", CFGFILE, config.OSX_HOST_jaguar, "jaguar", "2.3"]) )

pantherTask =  Task([ Job("bigmac.23", 
                          ["distrib/all/build-osx", CFGFILE, config.OSX_HOST_panther, "panther", "2.3"]),
                      Job("bigmac.24",
                          ["distrib/all/build-osx", CFGFILE, config.OSX_HOST_panther, "panther", "2.4"])
                     ])

beastTask1 = Task([ Job("beast.23",     ["distrib/all/build-windows", CFGFILE, "2.3"]),
                    Job("co-rh9.23",    ["distrib/all/build-rpm", CFGFILE, "beast", "co-rh9",   "rh9",   "2.3"]),
                    Job("beast.24",     ["distrib/all/build-windows", CFGFILE, "2.4"]),
                    Job("co-rh9.24",    ["distrib/all/build-rpm", CFGFILE, "beast", "co-rh9",   "rh9",   "2.4"]),
                    Job("co-mdk2006.24",["distrib/all/build-rpm", CFGFILE, "beast", "co-mdk2006","mdk2006","2.4"]),
                    ])

beastTask2 = Task([ Job("co-fc2.23",    ["distrib/all/build-rpm", CFGFILE, "beast", "co-fc2",   "fc2",   "2.3"]),
                    #Job("co-mdk101.23", ["distrib/all/build-rpm", CFGFILE, "beast", "co-mdk101","mdk101","2.3"]),
                    Job("co-fc4.24",    ["distrib/all/build-rpm", CFGFILE, "beast", "co-fc4",   "fc4",   "2.4"]),
                    #Job("co-fc2.24",    ["distrib/all/build-rpm", CFGFILE, "beast", "co-fc2",   "fc2",   "2.4"]),
                    Job("co-mdk102.24", ["distrib/all/build-rpm", CFGFILE, "beast", "co-mdk102","mdk102","2.4"]),
                    ])

## cyclopsTask = Task([ Job("co-mdk92.23",  ["distrib/all/build-rpm", CFGFILE, "cyclops", "co-mdk92", "mdk92", "2.3"]),
##                      Job("co-rh9.23",    ["distrib/all/build-rpm", CFGFILE, "cyclops", "co-rh9",   "rh9",   "2.3"]),
##                      Job("co-mdk92.24",  ["distrib/all/build-rpm", CFGFILE, "cyclops", "co-mdk92", "mdk92", "2.4"]),
##                      Job("co-rh9.24",    ["distrib/all/build-rpm", CFGFILE, "cyclops", "co-rh9",   "rh9",   "2.4"]),
##                      ])

buildTasks = [ jaguarTask,
               pantherTask,
               beastTask1,
               beastTask2,
##               cyclopsTask,
               ]

# Finalization.  This is for things that must wait until all the
# builds are done, such as copying the installers someplace, sending
# emails, etc.
finalizationTask = Task( Job("", ["distrib/all/build-finalize", CFGFILE]) )


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

def usage():
    print ""
    print "Usage: build-all [command flags...]"
    print ""
    print "build types:"
    print "   dryrun       Do the build, but don't copy anywhere (default)"
    print "   daily        Do a daily build, copy to starship"
    print "   release      Do a normal release (cantidate) build, copy to starship"
    print ""
    print "optional command flags:"
    print "   skipsource   Don't build the source archives, use the ones"
    print "                already in the staging dir."
    print "   onlysource   Exit after building the source and docs archives"
    print "   skipdocs     Don't rebuild the docs"
    print "   skipwin      Don't do the remote Windows build"
    print "   skiposx      Don't do the remote OSX build"
    print "   skiplinux    Don't do the remote Linux build"
    print "   skipclean    Don't do the cleanup step on the remote builds"
    print "   skipupload   Don't upload the builds to starship"
    print ""
    print "   nocohost     Don't start the coLinux sessions if they are"
    print "                not already online"
    print ""
    

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

def main(args):
    # Make sure we are running in the right directory.  TODO: make
    # this test more robust.  Currenly we just test for the presence
    # of 'wxPython' and 'wx' subdirs.
    if not os.path.isdir("wxPython") or not os.path.isdir("wx"):
        print "Please run this script from the root wxPython directory."
        sys.exit(1)

    # Check command line flags
    for flag in args:
        if flag in ["dryrun", "daily", "release"]:
            config.KIND = flag

        elif flag == "skipsource":
            config.skipsource = "yes"
            
        elif flag == "onlysource":
            config.onlysource = "yes"
            
        elif flag == "skipdocs":
            config.skipdocs = "yes"
            
        elif flag == "skipnewdocs":
            config.skipnewdocs = "yes"
            
        elif flag == "skipwin":
            config.skipwin = "yes"
            
        elif flag == "skiposx":
            config.skiposx = "yes"
            
        elif flag == "skiplinux":
            config.skiplinux = "yes"
            
        elif flag == "skipclean":
            config.skipclean = "yes"
            
        elif flag == "skipupload":
            config.skipupload = "yes"

        elif flag == "nocohost":
            config.startcohost = "no"
            
        else:
            print 'Unknown flag: "%s"' % flag
            usage()
            sys.exit(2)


    # ensure the staging area exists
    if not os.path.exists(config.STAGING_DIR):
        os.makedirs(config.STAGING_DIR)

    # Figure out the wxPython version number, possibly adjusted for being a daily build
    if config.KIND == "daily":
        t = time.localtime()
        config.DAILY = time.strftime("%Y%m%d")   # should it include the hour too?  2-digit year?
        file("DAILY_BUILD", "w").write(config.DAILY)
    sys.path.append('.')
    import setup
    config.VERSION = setup.VERSION

    # write the config file where the build scripts can find it
    config.write(CFGFILE)
    print "Build getting started at: ", time.ctime()


    # Run the first task, which will create the docs and sources tarballs
    tr = TaskRunner(initialTask)
    rc = tr.run()

    # cleanup the DAILY_BUILD file
    if config.KIND == "daily":
        os.unlink("DAILY_BUILD")

    # Quit now?
    if rc != 0 or config.onlysource == "yes":
        sys.exit(rc)


    # Run the main build tasks
    tr = TaskRunner(buildTasks)
    rc = tr.run()
    if rc != 0:
        sys.exit(rc)


    # when all the builds are done, run the finalization task
    tr = TaskRunner(finalizationTask)
    rc = tr.run()
    if rc != 0:
        sys.exit(rc)

    
    print "Build finished at: ", time.ctime()
    sys.exit(0)




if __name__ == "__main__":
    main(sys.argv[1:])
