#
# This file is part of gruvi. Gruvi is free software available under the
# terms of the MIT license. See the file "LICENSE" that was provided
# together with this source file for the licensing terms.
#
# Copyright (c) 2012-2013 the gruvi authors. See the file "AUTHORS" for a
# complete list.

from __future__ import absolute_import, print_function

import os
import sys
import textwrap
import subprocess

from setuptools import setup

# CFFI is needed to call setup() and therefore it needs to be installed before
# this setup script can be run. However it would be nice if the user could just
# to "pip install gruvi" and it would install CFFI as a dependency.
# We can work around it with a hack. When pip installs a package, it will call
# the "egg_info" command first to get dependencies.  We exploit this by injecting
# adding the cffi dependency to "install_requires" when "egg_info" is run, but
# only import cffi when "install" is run. Note this requires us to list all
# cffi dependencies as collected dependencies will be installed last. At the
# moment this is only "pycparser". The process above also works when installing
# from requirements.txt.

egg_info = 'egg_info' if sys.argv[:2] == ['-c', 'egg_info'] else None

if not egg_info:
    try:
        import cffi
    except ImportError:
        sys.stderr.write('Error: CFFI (required for setup) is not available.\n')
        sys.stderr.write('Please use "pip install cffi", or equivalent.\n')
        sys.exit(1)


version_info = {
    'name': 'gruvi',
    'version': '0.9.2',
    'description': 'Synchronous evented IO with pyuv and fibers',
    'author': 'Geert Jansen',
    'author_email': 'geertj@gmail.com',
    'url': 'https://github.com/geertj/gruvi',
    'license': 'MIT',
    'classifiers': [
        'Development Status :: 4 - Beta',
        'License :: OSI Approved :: MIT License',
        'Operating System :: POSIX',
        'Operating System :: Microsoft :: Windows',
        'Operating System :: MacOS :: MacOS X',
        'Programming Language :: Python :: 2.6',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3.3'
    ]
}

topdir, _ = os.path.split(os.path.abspath(__file__))


def update_version():
    """Update the _version.py file."""
    fname = os.path.join('.', 'gruvi', '_version.py')
    try:
        with open(fname) as fin:
            current = fin.read()
    except IOError:
        current = None
    new = textwrap.dedent("""\
            # This file is autogenerated. Do not edit.
            __version__ = '{0[version]}'
            """.format(version_info))
    if current == new:
        return
    tmpname = '{0}.{1}-tmp'.format(fname, os.getpid())
    with open(tmpname, 'w') as fout:
        fout.write(new)
    os.rename(tmpname, fname)
    print('Updated _version.py')


def update_manifest():
    """Update the MANIFEST.in file from git, if necessary."""
    # It would be more efficient to create MANIFEST directly, rather
    # than creating a MANIFEST.in where every line just includes one file.
    # Unfortunately, setuptools/distribute do not support this (distutils
    # does).
    gitdir = os.path.join('.', '.git')
    try:
        st = os.stat(gitdir)
    except OSError:
        return
    cmd = subprocess.Popen(['git', 'ls-tree', '-r', 'master', '--name-only'],
                           stdout=subprocess.PIPE)
    stdout, _ = cmd.communicate()
    files = stdout.decode('ascii').splitlines()
    files.append('gruvi/_version.py')
    lines = ['include {0}\n'.format(fname) for fname in files]
    new = ''.join(sorted(lines))
    try:
        with open('MANIFEST.in', 'r') as fin:
            current = fin.read()
    except IOError:
        current = None
    if new == current:
        return
    tmpname = 'MANIFEST.in.{0}-tmp'.format(os.getpid())
    with open(tmpname, 'w') as fout:
        fout.write(new)
    os.rename(tmpname, 'MANIFEST.in')
    print('Updated MANIFEST.in')
    # Remove the SOURCES.txt that setuptools maintains. It appears not to
    # accurately regenerate it when MANIFEST.in changes.
    sourcestxt = os.path.join('lib', 'gruvi.egg-info', 'SOURCES.txt')
    if not os.access(sourcestxt, os.R_OK):
        return
    os.unlink(sourcestxt)
    print('Removed {0}'.format(sourcestxt))


def main():
    os.chdir(topdir)
    update_version()
    update_manifest()
    if egg_info:
        ext_modules = []
    else:
        sys.path.append('gruvi')
        import dbus_ffi, http_ffi, jsonrpc_ffi
        ext_modules = [dbus_ffi.ffi.verifier.get_extension(),
                       http_ffi.ffi.verifier.get_extension(),
                       jsonrpc_ffi.ffi.verifier.get_extension()]
    sys.path.pop()
    setup(
        packages = ['gruvi', 'gruvi.txdbus'],
        install_requires = ['pycparser', 'cffi', 'fibers', 'pyuv'],
        test_suite = 'nose.collector',
        zip_safe = False,
        ext_modules = ext_modules,
        **version_info
    )


if __name__ == '__main__':
    main()
