def main(args):
    scriptlog = setup_logging(args)
    logging.info("Starting %s build" % BUILD_TYPE)
    # for total runtime
    script_start = datetime.now()
    logging.info(script_start)

    # set vars for uploading/mirroring
    if not args.user:
        droid_user = os.getenv('DROID_USER')
    else:
        droid_user = args.user
    if not args.host:
        droid_host = os.getenv('DROID_HOST')
    else:
        droid_host = args.host
    if not args.remotedir:
        droid_path = os.getenv('DROID_PATH')
    else:
        droid_path= args.remotedir
    if not args.localdir:
        droid_mirror = os.getenv('DROID_MIRROR')
        if not droid_mirror:
            droid_mirror = os.getenv('DROID_LOCAL_MIRROR')
    else:
        droid_mirror = args.localdir
    if not args.port:
        droid_host_port = os.getenv('DROID_HOST_PORT')
        if not droid_host_port:
            droid_host_port = '22'
    else:
        droid_host_port = args.port

    uploading = False
    if droid_host and droid_user and droid_path:
        uploading = True

    mirroring = False
    if droid_mirror:
        mirroring = True

    # we must put the builds somewhere
    if not mirroring and not uploading:
        logging.error("DROID_MIRROR not set")
        logging.error("DROID_HOST or DROID_USER or DROID_PATH not set")
        logging.error("no where put builds. BAILING!!")
        exit()

    # cd working dir
    previous_working_dir = os.getcwd()
    os.chdir(args.source)

    if uploading:
        upload_path = droid_path
        # upload thread
        upq = Queue.Queue()
        t1 = rsync.rsyncThread(upq, port=droid_host_port, message='Uploaded')
        t1.setDaemon(True)
        t1.start()

    if mirroring:
        mirror_path = droid_mirror
        # mirror thread
        m_q = Queue.Queue()
        t2 = rsync.rsyncThread(m_q, message='Mirrored')
        t2.setDaemon(True)
        t2.start()

    # Sync
    html_changelog = get_changelog(args)
    if html_changelog is not None:
        # add changelog to rsync queues
        if uploading:
            # make the remote directories
            full_upload_path_cl = os.path.join(upload_path, get_codename())
            try:
                subprocess.check_call(('ssh',
                    '-p%s' % (droid_host_port),
                    '%s@%s' % (droid_user, droid_host),
                    'test -d %s || mkdir -p %s' %
                        (full_upload_path_cl, full_upload_path_cl)
                    ))
            except subprocess.CalledProcessError as e:
                logging.error('ssh returned %d while making %s' %
                        (e.returncode, full_upload_path_cl))
            else:
                upq.put((html_changelog,
                    "%s@%s:%s" % (droid_user, droid_host, full_upload_path_cl)
                    ))
        if mirroring:
            full_mirror_path_cl = os.path.join(mirror_path, get_codename())
            try:
                if not os.path.isdir(full_mirror_path_cl):
                    os.makedirs(full_mirror_path_cl)
            except OSError as e:
                logging.error(e)
            else:
                m_q.put((html_changelog,
                    full_mirror_path_cl
                    ))
    else:
        if NIGHTLY_BUILD and not args.force: # No changes, dont do the build
            return

    #
    # Building
    #

    # for zip storage
    if os.path.isdir("/dev/shm"):
        temp_dir = "/dev/shm/tmp-%s-droidbuilder_zips" % os.getenv("USER")
    else:
        temp_dir = "/tmp/tmp-%s-droidbuilder_zips" % os.getenv("USER")
    if not os.path.isdir(temp_dir):
        os.makedirs(temp_dir)

    # keep track of builds
    build_start = datetime.now()

    # for json manifest
    json_info = []

    # Targets to run through the squisher
    squisher_targets = (
            'passion',
            'bravo',
            'supersonic',
            'inc',
    )

    # Export the proper build type
    if TESTING_BUILD:
        os.putenv('TESTING_BUILD','true')
        os.putenv('RELEASE_BUILD','false')
        os.putenv('NIGHTLY_BUILD','false')
    elif RELEASE_BUILD:
        os.putenv('TESTING_BUILD','false')
        os.putenv('RELEASE_BUILD','true')
        os.putenv('NIGHTLY_BUILD','false')
    elif NIGHTLY_BUILD:
        os.putenv('TESTING_BUILD','false')
        os.putenv('RELEASE_BUILD','false')
        os.putenv('NIGHTLY_BUILD','true')

    # build each target
    for target in args.target:
        if not args.nobuild:
            target_start = datetime.now()
            pkg = 'otapackage'
            if target in squisher_targets:
                pkg = 'squishedpackage'
            if android.build(target, pkg, not args.rebuild):
                continue # Failed #TODO reverse return value
            else:
                logging.info('Built %s in %s' %
                        (target, pretty_time(datetime.now() - target_start)))
        # find and add the zips to the rsync queues
        zips = []
        target_out_dir = os.path.join('out', 'target', 'product', target)
        if os.path.isdir(target_out_dir):
            for f in os.listdir(target_out_dir):
                if f.startswith('ev') and f.endswith('.zip'):
                    zips.append(f)
        if zips:
            # testing and release builds are put in codename subdirs
            # nightly will just be DATE
            codename = get_codename(target)
            if codename:
                if uploading:
                    # make the remote directories
                    full_upload_path = os.path.join(upload_path, codename)
                    try:
                        subprocess.check_call(('ssh',
                            '-p%s' % (droid_host_port),
                            '%s@%s' % (droid_user, droid_host),
                            'test -d %s || mkdir -p %s' %
                                (full_upload_path, full_upload_path)
                            ))
                    except subprocess.CalledProcessError as e:
                        logging.error('ssh returned %d while making %s' %
                                (e.returncode, full_upload_path))
                        if not mirroring:
                            continue

                if mirroring:
                    full_mirror_path = os.path.join(mirror_path, codename)
                    try:
                        if not os.path.isdir(full_mirror_path):
                            os.makedirs(full_mirror_path)
                    except OSError as e:
                        logging.error(e)
                        continue

                zip_info = []
                for z in zips:
                    zip_path = os.path.join(target_out_dir, z)
                    temp_zip_path = os.path.join(temp_dir, z)
                    zip_info.append({
                            'date': DATE,
                            'device': target,
                            'count': 0,
                            'message': get_message(target,args),
                            'md5sum': md5sum(zip_path),
                            'name': z,
                            'size': os.path.getsize(zip_path),
                            'type': BUILD_TYPE,
                            'location': '%s/%s' % (codename,z),
                    })
                    shutil.copy2(zip_path, temp_zip_path)
                    if uploading:
                        upq.put((temp_zip_path,
                            '%s@%s:%s' % (droid_user, droid_host, full_upload_path)
                            ))
                    if mirroring:
                        m_q.put((temp_zip_path,
                            full_mirror_path
                            ))
                json_info.append({
                        'codename': codename,
                        'zip_info': zip_info,
                })
            else:
                logging.error('Failed to get codename for %s' % (target))
        else:
            logging.warning('No zips found for %s' % target)

    # write total buildtime
    logging.info('Built all targets in %s' %
            (pretty_time(datetime.now() - build_start)))

    # wait for builds to finish uploading/mirroring
    if mirroring:
        m_q.join()
    if uploading:
        upq.join()

    if json_info and mirroring: # TODO uploading
        for entries in json_info:
            # Release and testing builds are stored in the same directory,
            # so we have to read the old entries, add new ones, and rewrite
            # Nightly wont have one initially and all builds are
            # stored in the same directory so it will just re(read/write)
            # for all builds which is stupid but will work fine
            device_manifest = os.path.join(mirror_path,
                              entries.get('codename'), 'info.json')
            device_entries = []
            try:
                f = open(device_manifest)
            except IOError as e:
                pass #logging.error('%s' % e)
            else:
                with f:
                    device_entries = json.load(f)
            for e in entries.get('zip_info'):
                device_entries.append(e)
            try:
                f = open(device_manifest,'w')
            except IOError as e:
                logging.error(e)
            else:
                with f:
                    json.dump(device_entries, f, indent=2)

    # cleanup
    shutil.rmtree(temp_dir)

    logging.info('Total run time: %s' %
            (pretty_time(datetime.now() - script_start)))

    # Write scriptlog for website
    html_scriptlog = write_html_scriptlog(scriptlog)
    if html_scriptlog is not None:
        # add log to rsync queues
        if uploading:
            upq.put((html_scriptlog,
                "%s@%s:%s" % (droid_user, droid_host, os.path.join(upload_path, get_codename()))
                ))
            upq.join()
        if mirroring:
            m_q.put((html_scriptlog,
                os.path.join(mirror_path, get_codename())
                ))
            m_q.join()

    # cd previous working dir
    os.chdir(previous_working_dir)
def main(args):

    # script logging
    log_dir = os.path.join(args.source, 'nightly_logs')
    try:
        if not os.path.isdir(log_dir):
            os.mkdir(log_dir)
    except OSError:
        pass
    scriptlog = os.path.join(log_dir, 'scriptlog-' + DATE + '.log')
    logging.basicConfig(filename=scriptlog, level=logging.INFO,
            format='%(levelname)-8s %(message)s')

    # for total runtime
    script_start = datetime.now()

    logging.info(script_start)

    # set vars for uploading/mirroring
    if not args.user:
        droid_user = os.getenv('DROID_USER')
    else:
        droid_user = args.user
    if not args.host:
        droid_host = os.getenv('DROID_HOST')
    else:
        droid_host = args.host
    if not args.remotedir:
        droid_path = os.getenv('DROID_PATH')
    else:
        droid_path = args.remotedir
    if not args.localdir:
        droid_mirror = os.getenv('DROID_MIRROR')
        if not droid_mirror:
            droid_mirror = os.getenv('DROID_LOCAL_MIRROR')
    else:
        droid_mirror = args.localdir

    # we must put the builds somewhere
    if not droid_mirror:
        mirroring = False
        if droid_host and droid_user and droid_path:
            uploading = True
        else:
            logging.error('DROID_MIRROR not set')
            logging.error('DROID_HOST or DROID_USER or DROID_PATH not set')
            logging.error('no where put builds. BAILING!!')
            exit()
    else:
        mirroring = True
        if droid_host and droid_user and droid_path:
            uploading = True
        else:
            uploading = False

    # cd working dir
    previous_working_dir = os.getcwd()
    os.chdir(args.source)

    # we want group write
    os.umask(002)

    # make the remote directories
    if uploading:
        upload_path = os.path.join(droid_path, DATE)
        try:
            subprocess.check_call(['ssh', '%s@%s' % (droid_user, droid_host),
                    'test -d %s || mkdir -p %s' % (upload_path,upload_path)])
        except subprocess.CalledProcessError as e:
            logging.error('ssh returned %d while making directories' %
                    (e.returncode))
            uploading = False
            if not mirroring:
                logging.error('no where to put builds. BAILING!!')
                exit()
        else:
            # upload thread
            upq = Queue.Queue()
            t1 = rsync.rsyncThread(upq,
                    '%s@%s:%s' % (droid_user, droid_host, upload_path),
                    message='Uploaded')
            t1.setDaemon(True)
            t1.start()

    if mirroring:
        mirror_path = os.path.join(droid_mirror, DATE)
        try:
            if not os.path.isdir(mirror_path):
                os.makedirs(mirror_path)
                subprocess.call(['chmod','775','%s' % (mirror_path)])
        except OSError as e:
            logging.error('failed to make mirror dir: %s' % (e))
            mirroring = False
            if not uploading:
                logging.error('no where to put builds. BAILING!!')
                exit()
        else:
            # mirror thread
            m_q = Queue.Queue()
            t2 = rsync.rsyncThread(m_q,
                    mirror_path,
                    message='Copied')
            t2.setDaemon(True)
            t2.start()

    #
    # Syncing
    #

    if not args.nosync:
        # common directory for all changelogs
        changelog_dir = os.path.join(os.path.realpath(os.getcwd()), 'nightly_changelogs')
        try:
            if not os.path.isdir(changelog_dir):
                os.mkdir(changelog_dir)
        except OSError:
            pass
        # changelog
        changelog = os.path.join(changelog_dir, 'changelog-' + DATE + '.log')
        # sync the tree
        if android.reposync():
            logging.error('Sync failed. Skipping the build')
            args.nobuild = True
            # Remove out so we dont upload yesterdays build
            if os.path.isdir('out'):
                shutil.rmtree('out')
        else:
            android.get_changelog(DATE,changelog)

        # create the html changelog
        if os.path.exists(changelog):
            logging.info('Created changelog for %s' % DATE)
            html_changelog = os.path.join(changelog_dir, 'changelog-' + DATE + '.html')
            cl = html.Create()
            cl.title('Changelog')
            cl.css('body {font-family:"Lucida Console", Monaco, monospace;font-size:0.9em;}')
            clbody = html.parse_file(changelog)
            cl.header(clbody[0])
            cl.body(html.add_line_breaks(clbody[1:]))
            cl.write(html_changelog)
            # add changelog to rsync queues
            if uploading:
                upq.put(html_changelog)
            if mirroring:
                m_q.put(html_changelog)
    else:
        logging.info('Skipped sync')

    #
    # Building
    #

    # export vars for the build script
    os.putenv('NIGHTLY_BUILD', 'true')

    # for zip storage
    if os.path.isdir('/dev/shm'):
        temp_dir = '/dev/shm/tmp-nightlybuilder_zips'
    else:
        temp_dir = '/tmp/tmp-nightlybuilder_zips'
    if not os.path.isdir(temp_dir):
        os.mkdir(temp_dir)

    # keep track of builds
    build_start = datetime.now()

    # for json manifest
    json_info = []

    # Targets to run through the squisher
    squisher_targets = (
            'passion',
            'bravo',
            'supersonic',
            'inc',
    )

    # build each target
    for target in args.target:
        if not args.nobuild:
            target_start = datetime.now()
            pkg = 'otapackage'
            if target in squisher_targets:
                pkg = 'squishedpackage'
            if android.build(target,pkg):
                continue # Failed
            else:
                logging.info('Built %s in %s' %
                        (target, pretty_time(datetime.now() - target_start)))
        # find and add the zips to the rsync queues
        zips = []
        target_out_dir = os.path.join('out', 'target', 'product', target)
        if os.path.isdir(target_out_dir):
            for f in os.listdir(target_out_dir):
                if f.startswith('ev') and f.endswith('.zip'):
                    zips.append(f)
        if zips:
            for z in zips:
                json_info.append({
                        'date': DATE,
                        'device': target,
                        'count': 0,
                        'message': 'Nightly build for %s' % target,
                        'md5sum': md5sum(os.path.join(target_out_dir, z)),
                        'name': z,
                        'size': os.path.getsize(os.path.join(target_out_dir, z)),
                        'type': 'nightly',
                        'location': '%s/%s' % (DATE,z),
                })
                shutil.copy2(os.path.join(target_out_dir, z),os.path.join(temp_dir, z))
                if uploading:
                    upq.put(os.path.join(temp_dir, z))
                if mirroring:
                    m_q.put(os.path.join(temp_dir, z))
        else:
            logging.warning('No zips found for %s' % target)

    # write total buildtime
    logging.info('Built all targets in %s' %
            (pretty_time(datetime.now() - build_start)))

    # write manifest
    if json_info:
        json_info.sort(key=lambda d:d['device'])
        try:
            f = open(os.path.join(temp_dir,'info.json'),'w')
        except IOError as e:
            logging.error('Failed to open info.json: %s' % (e))
        else:
            with f:
                json.dump(json_info, f, indent=2)
            if uploading:
                upq.put(os.path.join(temp_dir,'info.json'))
            if mirroring:
                m_q.put(os.path.join(temp_dir,'info.json'))
        # for website
        ''' # Not using this any more
        if mirroring:
            main_manifest = os.path.join(droid_mirror,'manifest.json')
            try:
                f = open(main_manifest,'r')
            except IOError as e:
                logging.warning('%s' % e)
            else:
                with f:
                    entries = json.load(f)
                for e in json_info:
                    entries.append(e)
                try:
                    f = open(main_manifest,'w')
                except IOError as e:
                    logging.warning('%s' % e)
                else:
                    with f:
                        json.dump(entries,f,indent=2)
        '''

    # wait for builds to finish uploading/mirroring
    if mirroring:
        m_q.join()
    if uploading:
        upq.join()

    # cleanup
    shutil.rmtree(temp_dir)

    logging.info('Total run time: %s' %
            (pretty_time(datetime.now() - script_start)))

    #
    # Finish up
    #

    # create html scriptlog
    if os.path.exists(scriptlog):
        html_scriptlog = os.path.join(log_dir, 'scriptlog-' + DATE + '.html')
        sl = html.Create()
        sl.title('Nightly Log')
        sl.css('body {font-family:"Lucida Console", Monaco, monospace;font-size:0.9em;}')
        sl.header(DATE)
        sl.body(html.add_line_breaks(html.parse_file(scriptlog)))
        sl.write(html_scriptlog)
        # add log to rsync queues
        if uploading:
            upq.put(html_scriptlog)
            upq.join()
        if mirroring:
            m_q.put(html_scriptlog)
            m_q.join()

    # cd previous working dir
    os.chdir(previous_working_dir)