#!/usr/bin/env python
import sys, os, shutil
import xmlrpclib
import urllib2
import hashlib
import warnings
from optparse import OptionParser
import tempfile
import subprocess

def myprint(mystr,fd=None):
    if fd is None:
        print mystr
    else:
        print >> fd, mystr

USER_AGENT = 'pypi-install/0.6.0 ( http://github.com/astraw/stdeb )'

def find_tar_gz(package_name, pypi_url = 'http://python.org/pypi',verbose=0):
    transport = xmlrpclib.Transport()
    transport.user_agent = USER_AGENT
    pypi = xmlrpclib.ServerProxy(pypi_url, transport=transport)

    download_url = None
    expected_md5_digest = None

    if verbose >= 2:
        myprint( 'querying PyPI (%s) for package name "%s"' % (pypi_url,
                                                               package_name) )
    releases = pypi.package_releases(package_name)
    if verbose >= 2:
        myprint( 'found releases: %s' % (', '.join(releases),) )
    if len(releases) > 1:
        # XXX how to sort versions?
        raise NotImplementedError('no ability to handle more than one release')
    for version in releases:

        urls = pypi.release_urls( package_name,version)
        for url in urls:
            if url['packagetype']=='sdist':
                assert url['python_version']=='source', 'how can an sdist not be a source?'
                if url['url'].endswith('.tar.gz'):
                    download_url = url['url']
                    if 'md5_digest' in url:
                        expected_md5_digest = url['md5_digest']
                    break

        if download_url is None:
            # PyPI doesn't have package. Is download URL provided?
            result = pypi.release_data(package_name,version)
            if result['download_url'] != 'UNKNOWN':
                download_url = result['download_url']
                # no download URL provided, see if PyPI itself has download
                urls = pypi.release_urls( result['name'], result['version'] )
    if download_url is None:
        raise ValueError('no package "%s" was found'%package_name)
    return download_url, expected_md5_digest

def get_source_tarball(package_name,verbose=0):
    download_url, expected_md5_digest = find_tar_gz(package_name,
                                                    verbose=verbose)
    if verbose >= 1:
        myprint( 'downloading %s' % download_url )
    request = urllib2.Request(download_url)
    request.add_header('User-Agent', USER_AGENT )
    opener = urllib2.build_opener()
    package_tar_gz = opener.open(request).read()
    if verbose >= 1:
        myprint( 'done downloading %d bytes.' % ( len(package_tar_gz), ) )
    if expected_md5_digest is not None:
        m = hashlib.md5()
        m.update(package_tar_gz)
        actual_md5_digest = m.hexdigest()
        if verbose >= 2:
            myprint( 'md5:   actual %s\n     expected %s' % (actual_md5_digest,
                                                             expected_md5_digest))
        if actual_md5_digest != expected_md5_digest:
            raise ValueError('actual and expected md5 digests do not match')
    else:
        warnings.warn('no md5 digest found -- cannot verify source file')
    fname = download_url.split('/')[-1]
    fd = open(fname,mode='wb')
    fd.write( package_tar_gz )
    fd.close()
    return fname

def main():
    usage = '%prog PACKAGE_NAME [options]'
    parser = OptionParser(usage)
    parser.add_option('--verbose', type='int',
                      help='verbosity level',
                      default=0)
    parser.add_option('--keep', action='store_true',
                      default=False,
                      help='do not remove temporary files')
    (options, args) = parser.parse_args()
    if len(args) != 1:
        myprint('need exactly one PACKAGE_NAME',fd=sys.stderr)
        parser.print_help()
        sys.exit(1)

    package_name = args[0]

    orig_dir = os.path.abspath( os.curdir )
    tmpdir = os.path.abspath(tempfile.mkdtemp())
    try:
        if options.verbose >= 2:
            myprint('downloading to %s'%tmpdir)
        os.chdir( tmpdir )
        tarball_fname = get_source_tarball(package_name,verbose=options.verbose)
        cmd = 'tar xzf %s' % tarball_fname
        if options.verbose >= 2:
            myprint('executing: %s'%cmd)
        subprocess.check_call(cmd, shell=True)

        expanded_dir = None
        for entry in os.listdir(os.curdir):
            if os.path.isdir(entry):
                assert expanded_dir is None, "only expected one directory"
                expanded_dir = entry

        os.chdir( expanded_dir )
        cmd = ('%s setup.py --command-packages=stdeb.command sdist_dsc '
               '--guess-conflicts-provides-replaces=True bdist_deb' %
               (sys.executable, ) )
        if options.verbose >= 2:
            myprint('executing: %s'%cmd)
        subprocess.check_call(cmd, shell=True)

        os.chdir( 'deb_dist' )
        cmd = 'sudo dpkg -i *.deb'
        if options.verbose >= 2:
            myprint('executing: %s'%cmd)
        subprocess.check_call(cmd, shell=True)

    finally:
        os.chdir( orig_dir )
        if not options.keep:
            shutil.rmtree(tmpdir)

if __name__=='__main__':
    main()
