#
# Installing Gnosis_Utils:
#
#	  python setup.py install
#
# Or, if you have multiple versions of Python installed,
# you can install for all of them at once using:
#
#	  python setup.py install_all
#
# Other commands available (for maintainers):
#
#	  # build but don't install
#	  python setup.py build
#
#	  # create source distribution (placed in dist/)
#	  python setup.py makedist
#
#	  # clean out junk files
#	  python setup.py clean
#
# You should *not* run any other distutils commands, since
# there is extra magic that needs to be done.

# [FYI, this file is called 'setup.py' because that
#  is what users traditionally expect, but also because
#  that name is hardcoded a few places in distutils.]
#
# --frankm@hiwaay.net

# put disthelper & gnosis in path so they're usable before installation
import sys
sys.path.insert(0,'.')

from distutils.core import setup
import os, re, shutil
from glob import glob
from disthelper.misc import unlink, rmtree, make_tempdir
from disthelper.setuplib import zip_current_dir, tar_bz2_current_dir, \
     tar_gz_current_dir

# use string functions instead of string methods, to maintain
# compatibility w/Python 1.5 (even though PyXML has dropped support
# for Python < 2.0, so the XML portions of gnosis won't work, unless
# you find an old PyXML)
import string

import gnosis.pyconfig

# sanity check for botched Python installations
# (probably means that pyexpat wasn't built)
def is_DOM_okay():
    s = '<?xml version="1.0"?><P hello="1"></P>'
    import StringIO
    try:
        from xml.dom import minidom
        # test 1: will it parse at all?
        doc = minidom.parse(StringIO.StringIO(s))
        # test 2: does getAttribute on non-existant nodes crash?
        # (xml.pickle DOM parser assumes this returns '')
        a = doc.firstChild.getAttribute('bogus')
        return 1
    except:
        # need a newer version of PyXML
        return 0

def remake_MANIFEST():
    print "Creating MANIFEST ..."
    
    # create empty MANIFEST
    unlink('MANIFEST')
    open('MANIFEST','w').write('')

    # create real MANIFEST, including MANIFEST in listing
    # (yes, it's weird, but works best this way)
    os.system('%s setup.py sdist --manifest-only' % sys.executable)
    
if not os.path.exists('MANIFEST'):
    # should only happen in the dev environment if you do a 'make clean'
    # without remaking the sdist
    remake_MANIFEST()

def ensure_at_toplevel():
    "Make kinda sure I'm at the toplevel."
    files = ['gnosis','MANIFEST','disthelper']
    for file in files:
        if not os.path.exists(file):
            print "*** Hey, you're supposed to run this from the toplevel."
            sys.exit(1)

# just check globally for now
ensure_at_toplevel()

# ensure that an entire path exists
# os.makedirs doesn't seem to work as I expected ... :-(
# [I think this was a bug in earlier Python versions, but anyways
# it's well tested now and doesn't hurt anything. --fpm]
def makepath(path):
    # path is from MANIFEST, so we know it'll have forward slashes
    # (see distutils docs)
    parts = string.split(path,'/')
    partial = ''
    for part in parts:
        partial = os.path.join(partial,part)
        try: os.mkdir(partial)
        except: pass

# try running setup(), returning 1 on success, 0 on failure
def do_setup():
    import gnosis.version # only import when needed!
    
    try:
        pkglist = ["gnosis",
                   "gnosis.anon",
                   "gnosis.magic",
                   "gnosis.util",
                   "gnosis.util.convert",
                   "gnosis.xml",
                   "gnosis.xml.objectify",
                   "gnosis.xml.objectify.doc",
                   "gnosis.xml.objectify.test",
                   "gnosis.xml.pickle",
                   "gnosis.xml.pickle.ext",
                   "gnosis.xml.pickle.util",
                   "gnosis.xml.pickle.doc",
                   "gnosis.xml.pickle.test",
                   "gnosis.xml.pickle.parsers"]

        # see if this Python has the capability to run certain
        # packages.
        
        # (this is really weird ... I have to remove them
        # from the pkglist *AND* delete them in copy_extra_files.
        # I don't understand distutils sometimes ...)

        if gnosis.pyconfig.Have_Generators():
            # need generators for relax
            pkglist.append( "gnosis.xml.relax" )

        if gnosis.pyconfig.Have_ListComprehensions():
            # need list comprehensions here
            pkglist.append( "gnosis.xml.validity" )

        kwargs = {
            # Note: PKG-INFO is autogenerated & placed in the sdist
            #		using info from this dictionary, as follows:
            #
            #	name			 -> Name
            #	version			 -> Version
            #	description		 -> Summary
            #	url				 -> Home-page
            #	author			 -> Author
            #	author_email	 -> Author-email
            #	license			 -> License
            #	long_description -> Description
            #	platforms		 -> Platform (multiple lines if needed)

            'name' : gnosis.version.PKGNAME,
            'version': gnosis.version.VSTRING,
            'description': "Modules and Utilities for XML Documents and Other Miscellany",
            'long_description': "Include modules: xml.pickle, xml.objectify, xml.indexer, xml.validity, and friends.",
            'long_description':	 "Include modules:	xml.pickle, xml.objectify, "\
            
                                 "indexer, xml.indexer, xml.validity, gnosis.anon, "\
                                 "multimethods, magic, and friends.",
            
            'author': "Gnosis Software",
            'author_email': "mertz@gnosis.cx",
            'url': "http://gnosis.cx/download/",
            'packages': pkglist,
            'license': "Public Domain"
            }


        # Python 2.0 dies if you pass a 'platforms' arg, but if we
        # leave it out, we get UNKNOWN in PKG-INFO. Our sdist will
        # always be built with Python >= 2.1, so it's not a problem.
        # This keeps us from bombing when installing on Python 2.0.
        if not hasattr(sys,'version_info') or \
           (int(sys.version_info[0]) >= 2 and \
            int(sys.version_info[1]) >= 1):
            kwargs['platforms'] = 'Any'

        # Python <= 2.2 misspells 'license' (deprecation warning in 2.3+)
        if not hasattr(sys,'version_info') or \
               not (int(sys.version_info[0]) >= 2 and \
                    int(sys.version_info[1]) >= 3):
            kwargs['licence'] = kwargs['license']
            del kwargs['license']
            
        apply(setup,[],kwargs)
        rval = 1		
    except Exception,exc:
        print "*** ERROR: %s" % str(exc)
        rval = 0

    del gnosis.version
    
    return rval

# by default, we copy EVERYTHING from MANIFEST to build/lib*.
# this has the nice side-effect of converting all text files
# to the platform text format. setting this to zero means we
# only copy files NOT already under build/lib*
copy_all_files = 1

def copy_extra_files():
    destroot = glob(os.path.join('build','lib'))[0]

    # go through MANIFEST to see what is supposed to be under build directory
    print "Copying extra files to %s ..." % destroot

    f = open('MANIFEST','r')
    for srcfile in f.readlines():
        srcfile = string.rstrip(srcfile) # remove newline char(s)
        dest = os.path.join(destroot,os.path.normpath(srcfile))
        if not os.path.exists(dest) or copy_all_files:
            dir,file = os.path.split(dest)
            if file == 'setup.py':
                continue # skip
            
            makepath(dir)
            open(dest,'w').write(open(srcfile,'r').read())

    if not gnosis.pyconfig.Have_Generators():
        # see note about pkglist in do_setup() ... have to delete it here too
        rmtree(os.path.join(destroot,'gnosis','xml','relax'))		

    if not gnosis.pyconfig.Have_ListComprehensions():
        # ditto re: do_setup()
        rmtree(os.path.join(destroot,'gnosis','xml','validity'))
        
if len(sys.argv) < 2:
    import gnosis.version # import only when needed!
    
    print "\nGnosis Utilities %s installation." % gnosis.version.VSTRING
    print ""
    print "Usage:"
    print ""
    print "		# Install, for a single version of Python"
    print "		python setup.py install"
    print ""
    print "		# Install for ALL Python versions on this machine"
    print "		python setup.py install_all"
    print ""
    print "** Maintainer commands **"
    print ""
    print "		# create source distribution (in dist/)"
    print "		python setup.py makedist"
    print ""
    print "		# clean out junk files"
    print "		python setup.py clean"
    print ""
    print "** DO NOT run any other distutils commands **"
    print ""

    del gnosis.version
    
    sys.exit(1)

if 'build' in sys.argv:
    # when building for multiple Pythons, it isn't smart
    # enough to seperate the builds, so manually delete
    # the build/ tree before beginning
    rmtree('build')
    # fall through to do_setup() below
    
if 'clean' in sys.argv:
    print "Cleaning tree ..."
    
    # remove .pyc, *~, coredumps, .md5envelope files
    patts = "*.pyc,*~,core,*.md5envelope"
    os.system('%s disthelper/scripts/rmfind.py -v -R "%s" .' % \
              (sys.executable,patts))

    # rm -rf build & dist	
    rmtree('build')
    rmtree('dist')

    # remove some test output files that may be around
    gxpt = os.path.join('gnosis','xml','pickle','test')
    names = glob(os.path.join(gxpt,'TESTS.OUT-*'))
    for name in names:
        unlink(name)

    unlink(os.path.join(gxpt,'aaa.xml'))
    unlink('MANIFEST')
    unlink('PKG-INFO')	

    # setup will complain if MANIFEST missing, so just regenerate
    remake_MANIFEST()
    
    sys.exit(0)

if 'taball' in sys.argv:
    "Convert spaces->tabs in all .py files"
    #os.system('%s disthelper/scripts/tabtree.py -v -x py -r .' % \
    #		  sys.executable)
    sys.exit(0)

if 'formatdist' in sys.argv:
    "Format files for distribution."
    
    # convert tabs to spaces in all .py files to be politically correct :-)
    print "Untabifying tree ..."
    os.system('%s disthelper/scripts/untabtree.py -w 4 -x py -r .' % \
              sys.executable)

    # put sources in unix textfile format (\n), so auto-conversion
    # to platform format works (in setup.py)
    print "Converting text format ..."
    os.system('%s disthelper/scripts/porttext.py -x py -r .' % sys.executable)

    sys.exit(0)

if 'makedist' in sys.argv:
    "Create source distribution"

    # clean tree
    os.system('%s setup.py clean' % sys.executable)
    # format text files
    os.system('%s setup.py formatdist' % sys.executable)

    # create MANIFEST
    remake_MANIFEST()

    rmtree('dist')
    
    # actually, we don't want the sdist anymore -- the 'master'
    # archive has everything (primarily due to the fact that
    # we DON'T want to install disthelper, but it still needs
    # to be in the sdist, and make sdist won't do that

    # the ONLY think needed from the sdist is PKG-INFO.
    # Could just write it ourselves, but lets do the cheesy
    # thing and grab it from the sdist :-)
    
    os.system('%s setup.py sdist --keep-temp' % sys.executable)

    import gnosis.version # only import when needed!

    rawdir = os.path.join('%s-%s' % (gnosis.version.PKGNAME,
                                     gnosis.version.VSTRING))

    if not os.path.isdir(rawdir):
        print "*****************************************"
        print "* AACK! Where is sdist rawdir?"
        print "*****************************************"
        raise "Punt"
    
    buf = open(os.path.join(rawdir,'PKG-INFO'),'r').read()
    del gnosis.version
    
    open('PKG-INFO','w').write(buf)

    print "Deleting %s" % rawdir
    rmtree( rawdir )

    # start clean again ... (sdist has same name as the .tgz
    # I'm going to create!)
    print "Deleting dist/"	
    rmtree('dist')
    
    # create dist (which *includes* MANIFEST just created)
    # (yes, its gross, but required as far as I can tell)
    rmtree('dist')

    os.system('%s setup.py master' % sys.executable)

    sys.exit(0)
    
if 'master' in sys.argv:
    import gnosis.version # only as needed!
    
    myver = gnosis.version.VSTRING

    # -- create archives, multiple formats for user convenience --

    tempdir = make_tempdir()

    excludes = [re.compile('.+\.pyc$')]
    
    # .zip file
    zipname = os.path.join(tempdir,'Gnosis_Utils-%s.zip' % myver)
    print "Creating %s ..." % os.path.basename(zipname)
    zip_current_dir( zipname, 'Gnosis_Utils-%s' % myver, excludes )

    # .tar.gz
    targz_name = os.path.join(tempdir,'Gnosis_Utils-%s.tar.gz' % myver)
    print "Creating %s ..." % os.path.basename(targz_name)
    tar_gz_current_dir( targz_name, 'Gnosis_Utils-%s' % myver, excludes )

    # .tar.bz2
    tarbz2_name = os.path.join(tempdir,'Gnosis_Utils-%s.tar.bz2' % myver)
    print "Creating %s ..." % os.path.basename(tarbz2_name)
    tar_bz2_current_dir( tarbz2_name, 'Gnosis_Utils-%s' % myver, excludes )

    # place in dist/
    if not os.path.isdir('dist'):
        os.mkdir('dist')

    # shutil.move() doesn't exist in older Pythons
    shutil.copy2(zipname,'dist')
    unlink(zipname)

    shutil.copy2(targz_name,'dist')
    unlink(targz_name)

    shutil.copy2(tarbz2_name,'dist')
    unlink(tarbz2_name)		

    os.rmdir(tempdir)

    sys.exit(0)
    
if 'install' in sys.argv:
    
    #if not os.path.isdir('build'):
        #print "** Please run build command first **"
        #sys.exit(1)
    #	os.system('%s setup.py build' % sys.executable)

    # make sure it's a clean build!
    os.system('%s setup.py build' % sys.executable)	

    # fall through to do_setup()
    
if 'install_all' in sys.argv:
    from disthelper.find_python import get_python_verlist

    # rebuild command line, replacing 'install_all' with 'install'
    args = ''
    for arg in sys.argv:
        if arg == 'install_all':
            args = args + ' install '
        else:
            args = args + ' ' + arg + ' '
            
    print "Searching for all installed Pythons ..."
    
    pylist = get_python_verlist()

    for exe,info in pylist:
        print '%s %s' % (exe,args)
        os.system('%s %s' % (exe,args))		
    
    sys.exit(0)
    
if do_setup() != 1:
    print "** ERROR: setup() failed"
    sys.exit(1)

if 'build' in sys.argv:
    copy_extra_files()

if not is_DOM_okay():
    print ""
    print "** WARNING: xml.dom.minidom is not working."
    print "**		Some portions of the package will not work."
    print "**		If you are using Python 2.0, you should install PyXML:"
    print "**			http://pyxml.sourceforge.net/topics/download.html"
    print ""
elif 'install' in sys.argv:
    print "\n*** Gnosis_Utils - Installed OK ***\n"

    
    
