#!/usr/bin/env python

# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
# See LICENSE for details.


from __future__ import nested_scopes

### Twisted Preamble
# This makes sure that users don't have to set up their environment
# specially in order to run these programs from bin/.
import sys, os, string
if string.find(os.path.abspath(sys.argv[0]), os.sep+'Twisted') != -1:
    sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir)))
sys.path.insert(0, os.curdir)
### end of preamble

from twisted.python import usage, dist, reflect
from twisted.python.release import runChdirSafe, sh, DirectoryExists, DirectoryDoesntExist

import glob

packaged_projects = dist.twisted_subprojects[:]
packaged_projects.remove('web2')
packaged_projects.remove('vfs')


def makeCommands():
    # Yeah, I could do dynamic lookups and for loops and shit, but
    # this makes the code greppable.
    return {
        'exportTemp': exportTemp,
        'makeDocAll': makeDocAll,
        'makeDocCore': makeDocCore,
        'makeBallAll': makeBallAll,
        'makeBallCore': makeBallCore,
        'makeBallSumo': makeBallSumo,

        'makeDocConch': makeMakeDoc('conch'),
        'makeDocFlow': makeMakeDoc('flow'),
        'makeDocLore': makeMakeDoc('lore'),
        'makeDocMail': makeMakeDoc('mail'),
        'makeDocNames': makeMakeDoc('names'),
        'makeDocNews': makeMakeDoc('news'),
        'makeDocPair': makeMakeDoc('pair'),
        'makeDocRunner': makeMakeDoc('runner'),
        'makeDocWeb': makeMakeDoc('web'),
        'makeDocWeb2': makeMakeDoc('web2'),
        'makeDocWords': makeMakeDoc('words'),

        'makeBallConch': makeMakeBall('conch'),
        'makeBallFlow': makeMakeBall('flow'),
        'makeBallLore': makeMakeBall('lore'),
        'makeBallMail': makeMakeBall('mail'),
        'makeBallNames': makeMakeBall('names'),
        'makeBallNews': makeMakeBall('news'),
        'makeBallPair': makeMakeBall('pair'),
        'makeBallRunner': makeMakeBall('runner'),
        'makeBallWeb': makeMakeBall('web'),
        'makeBallWeb2': makeMakeBall('web2'),
        'makeBallWords': makeMakeBall('words'),
        }


class Options(usage.Options):
    optParameters = [
        ['commands', None, 'exportTemp,makeDocAll,makeBallAll,makeBallSumo',
         "(optional) Comma-separated list of individual steps to run"],
        ['release-source', None, '/trunk',
         "SVN path to be released."],
        ['sumo-version', None, None,
         "Version of Twisted (affects tarball/directory name)"],
        ]


    _desc = """
Things appropriate for --commands are:

%s

Generally, the release manager will want to run this from a checkout
of a branch of Twisted that has been given version numbers with
admin/change-versions.
"""

    longdesc = property(lambda s: s._desc
                        % ', '.join(sorted(ALL_COMMANDS)))

    def postOptions(self):
        commands = self['commands'].split(',')
        commands = [ALL_COMMANDS[x] for x in commands]
        self['commands'] = commands
        print "GOING TO DO", ','.join([x.__name__ for x in commands])


def main():
    try:
        opts = Options()
        opts.parseOptions()
    except usage.UsageError, ue:
        print "%s: %s (see --help)" % (sys.argv[0], ue)
        sys.exit(2)

    for command in opts['commands']:
        print
        print command.__name__
        print "="*len(command.__name__)
        runChdirSafe(command, opts)


##
# Utilities
##
def lore(ver, docdir):
    # We get an arg like "doc/<blah>/", "doc/<blah>/sub/", and so
    # forth. We need to pass -l to lore such that, in http/html terms,
    # we get from a given file in one of these directories to
    # doc/<blah>/howto.

    # doc/<blat>/howto -> ../howto (for ease of implementation)
    # doc/<blat>/ -> howto
    # doc/<blat>/foo -> ../howto
    # doc/<blat>/foo/bar -> ../../howto
    # we always get doc/<blat>/ at least
    relativity = list(os.path.normpath(docdir)).count('/') - 1 
    homelink = ('../' * relativity) + 'howto/'
    sh("./bin/lore/lore -p --config template=doc/core/howto/template.tpl "
       "--config ext=.html --config version=%(ver)s "
       "--config noapi=please -l %(homelink)s "
       "%(docdir)s/*.xhtml" % {'ver': ver, 'docdir': docdir,
                               'homelink': homelink})
    sh("rm -f %(docdir)s/*.xhtml" % {'docdir': docdir})

def tar(tdir):
    sh('find %(tdir)s -name "*.pyc" | xargs rm -f' % locals())
    sh('tar cjhf %(tdir)s.tar.bz2 %(tdir)s' % locals())

##
# The MEAT.
##

def exportTemp(opts):
    if os.path.exists('Twisted.exp'):
        raise DirectoryExists("ExportTemp: 'Twisted.exp' already exists")
    sh('svn export . Twisted.exp')


def makeDocCore(opts):
    ver = dist.getVersion('core')
    os.chdir('Twisted.exp')

    for docdir in ['howto', 'howto/tutorial', 'upgrades',
                   'examples',
                   'upgrades/2.0', # ugh
                   'specifications', '']:
        lore(ver, os.path.join('doc/core', docdir))
    # development docs go in core, for lack of anywhere better
    for docdir in ['legal', 'policy', '']:
        lore(ver, os.path.join('doc/development', docdir))

    #shwack the crap

def makeMakeDoc(projname):
    def makeDoc(opts):
        os.chdir('Twisted.exp')
        base = 'doc/%s' % (projname,)
        for sub in ('howto', 'examples'):
            sub = os.path.join(base, sub)
            if os.path.exists(sub):
                lore(dist.getVersion(projname), sub)
    return makeDoc


def makeDocAll(opts):
    runChdirSafe(makeDocCore, opts)
    for sub in packaged_projects:
        runChdirSafe(ALL_COMMANDS['makeDoc%s' % sub.capitalize()],
                     opts)

def makeBallAll(opts):
    runChdirSafe(makeBallCore, opts)
    for sub in packaged_projects:
        runChdirSafe(ALL_COMMANDS['makeBall%s' % sub.capitalize()],
                     opts)


def makeBallCore(opts):
    ver = dist.getVersion('core')
    tdir = "TwistedCore-%s" % (ver,)
    if not os.path.exists('Twisted.exp'):
        raise DirectoryDoesntExist("MakeBalls: Twisted.exp doesn't exist")

    os.makedirs(os.path.join(tdir, 'twisted'))
    os.makedirs(os.path.join(tdir, 'bin'))

    twisted_subprojects = ','.join(dist.twisted_subprojects)
    package_blacklist = ','.join(dist.twisted_subprojects)

    sh('''
    ln -s `pwd`/Twisted.exp/twisted/* %(tdir)s/twisted/
    rm -f %(tdir)s/twisted/{%(package_blacklist)s}
    rm -f %(tdir)s/twisted/topfiles
    ln -s `pwd`/Twisted.exp/LICENSE %(tdir)s/
    ln -s `pwd`/Twisted.exp/twisted/topfiles/* %(tdir)s/
    mkdir %(tdir)s/doc
    ln -s `pwd`/Twisted.exp/doc/core/* %(tdir)s/doc/
    ln -s `pwd`/Twisted.exp/doc/fun %(tdir)s/doc/fun
    ln -s `pwd`/Twisted.exp/doc/development %(tdir)s/doc/development
    ln -s `pwd`/Twisted.exp/bin/* %(tdir)s/bin
    rm -f %(tdir)s/bin/{%(twisted_subprojects)s}

    ''' % locals())

    tar(tdir)


def makeBallSumo(opts):
    ver = opts['sumo-version']
    if not ver:
        raise Exception("Please provide a --sumo-version")
    basever = dist.getVersion('core')
    tdir = "Twisted-%s" % (ver,)
    if not os.path.exists('twistedballs'):
        raise Exception("Please create a 'twistedballs' directory and "
                        "populate it with tarballs of Twisted projects "
                        "and Zope Interface.")
    zig = glob.glob('twistedballs/ZopeInterface-*.tgz')
    if not zig:
        raise Exception(
            "Creating sumo distribution requires a ZopeInterface tarball - "
            "Please download one from "
            "<http://www.zope.org/Products/ZopeInterface>.")
    os.makedirs(tdir)
    twistedBalls = glob.glob('twistedballs/Twisted*.tar.bz2')
    for tb in twistedBalls:
        sh('tar xjf %s -C %s' % (tb, tdir))
    sh('tar xzf %s -C %s' % (zig[0], tdir))
    sh('''
    cp `pwd`/README %(tdir)s/
    cp `pwd`/LICENSE %(tdir)s/
    cp `pwd`/setup.py %(tdir)s/setup.py
    ''' % locals())
    tar(tdir)


def createSubprojectDirectory(proj, version):
    sdir = 'Twisted%s-%s' % (proj.capitalize(), version)
    os.makedirs(sdir+'/twisted/%s' % (proj,))
    os.makedirs(sdir+'/twisted/plugins')

    sh("""
    ln -s `pwd`/Twisted.exp/twisted/%(proj)s/* %(sdir)s/twisted/%(proj)s
    rm %(sdir)s/twisted/%(proj)s/topfiles
    rm %(sdir)s/twisted/%(proj)s/__init__.py
    cp `pwd`/Twisted.exp/twisted/%(proj)s/__init__.py %(sdir)s/twisted/%(proj)s/
    ln -s `pwd`/Twisted.exp/LICENSE %(sdir)s
    ln -s `pwd`/Twisted.exp/twisted/%(proj)s/topfiles/* %(sdir)s
    """ % locals())
    
    if os.path.exists('Twisted.exp/twisted/plugins/twisted_%s.py' % (proj,)):
        sh("ln -s `pwd`/Twisted.exp/twisted/plugins/twisted_%(proj)s.py "
           "%(sdir)s/twisted/plugins" % locals())
    
    if os.path.exists('Twisted.exp/doc/'+proj):
        sh('ln -s `pwd`/Twisted.exp/doc/%(proj)s %(sdir)s/doc' % locals())
    if os.path.exists('Twisted.exp/bin/'+proj):
        sh('ln -s `pwd`/Twisted.exp/bin/%(proj)s %(sdir)s/bin' % locals())


def makeMakeBall(proj):
    def makeBall(opts):
        projver = dist.getVersion(proj)
        projdir = 'Twisted%s-%s' % (proj.capitalize(), projver,)
        createSubprojectDirectory(proj, projver)
        tar(projdir)
    return makeBall



ALL_COMMANDS = makeCommands()

if __name__=='__main__':
    main()

