#Academic Torrents setup.py for installing the software application

#Copyright (C) [2017] Ronald D. Barrios

#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:

#The above copyright notice and this permission notice shall be included in all
#copies or substantial portions of the Software.

#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#SOFTWARE.

""" Custom setup.py install through the BuildingLibtorrent Class
Features:
- Installs Boost from source code.
- Installs Openssl from source code.
- Installs Libtorrent from source code.
- Generates an .at_profile for sourcing environment variables required by
  main academictorrents application.
- Installs via pip other package dependencies.
"""

from distutils import log
import urllib
import os
import tarfile
import sys
import logging
import subprocess as sub
import shutil as sh
from setuptools import setup
from setuptools.command.install import install
import six


def message(code, phase):
    """ Prints a custom message that depends on the code returned by the
    subprocess command executor.

    Args:
        code: int value returned by subprocess.Popen call.
        phase: a string that describes the context in which subprocess.Popen
               was called.
    """

    if code == 0:
        six.print_(phase + " successful")
    else:
        six.print_(phase+ " with errors. See install.log")


def log_subprocess_output(pipe):
    """ Writes a log file to register what subprocess performed.

    Args:
        pipe: stdout line generated by the subprocess.Popen call
    """

    for line in iter(pipe.readline, b''): # b'\n'-separated lines
        logging.info('%r', line)


class BuildingLibtorrent(install):
    """ Custom install Class that builds libtorrent from source code plus all
    its dependencies to be able to work.

    By providing the --user arg to this setup.py module, the custom installation
    is run. If this argument is not provided, it justs installs the python
    modules.

    Usage:
        Option1: $ pip install --install-option='--user' academictorrents
        Option2: $ python setup.py install -- user
    """

    def run(self):
        origin = os.getcwd()
        if '--user' in sys.argv:
            at_home = os.path.join(os.environ['HOME'], ".local")
            os.chdir(at_home)
            logging.basicConfig(filename='install.log',
                                filemode='w', level=logging.DEBUG)
            pkg = os.path.join(os.environ['HOME'], "at-pkg")
            os.mkdir(pkg)
            os.chdir(pkg)

            six.print_("Preparing Boost")
            boost_url = ('https://sourceforge.net/projects/boost/files/'
                         'boost/1.63.0/boost_1_63_0.tar.gz')
            boost_tb = 'boost_1_63_0.tar.gz'
            boost_dir = 'boost_1_63_0'
            urllib.urlretrieve(boost_url, boost_tb)

            six.print_("Preparing Openssl")
            openssl_url = 'https://www.openssl.org/source/openssl-1.1.0e.tar.gz'
            openssl_tb = 'openssl-1.1.0e.tar.gz'
            openssl_dir = 'openssl-1.1.0e'
            urllib.urlretrieve(openssl_url, openssl_tb)

            six.print_("Preparing Libtorrent")
            libtorrent_url = ('https://github.com/arvidn/libtorrent/'
                              'releases/download/libtorrent-1_1_3/'
                              'libtorrent-rasterbar-1.1.3.tar.gz')
            libtorrent_tb = 'libtorrent-rasterbar-1.1.3.tar.gz'
            libtorrent_dir = 'libtorrent-rasterbar-1.1.3'
            urllib.urlretrieve(libtorrent_url, libtorrent_tb)

            six.print_("Uncompressing libraries")
            for lib in [boost_tb, openssl_tb, libtorrent_tb]:
                six.print_("Uncompressing " + lib)
                tar = tarfile.open(lib)
                tar.extractall()
            tar.close()
            with_python = os.popen('which python2.7').read()
            six.print_("Python executable to use is: " + with_python)

            six.print_("Configuring Openssl")
            os.chdir(os.path.join(pkg, openssl_dir))

            cmd = ['./config', '--prefix=%s'%at_home,
                   '--openssldir=%s'%os.path.join(at_home, "ssl")]

            myproc = sub.Popen(cmd, stdout=sub.PIPE)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode, six.text_type("Openssl"))

            six.print_("Make Openssl")
            os.chdir(os.path.join(pkg, openssl_dir))
            myproc = sub.Popen(['make'], stdout=sub.PIPE, stderr=sub.STDOUT)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode, six.text_type("Make Openssl"))

            six.print_("Make test Openssl")
            os.chdir(os.path.join(pkg, openssl_dir))
            myproc = sub.Popen(['make', 'test'], stdout=sub.PIPE,
                               stderr=sub.STDOUT)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode, six.text_type("Make test Openssl"))

            six.print_("Make install Openssl")
            os.chdir(os.path.join(pkg, openssl_dir))
            myproc = sub.Popen(['make', 'install'], stdout=sub.PIPE,
                               stderr=sub.STDOUT)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode,
                    six.text_type("Make install Openssl"))

            six.print_("Bootstrapping Boost")
            os.chdir(os.path.join(pkg, boost_dir))

            cmd = ['./bootstrap.sh', '--with-python=%s'%with_python,
                   '--prefix=%s'%at_home]

            myproc = sub.Popen(cmd, stdout=sub.PIPE)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode, six.text_type("Bootstrap"))

            six.print_("Building Boost C++ libraries")
            cmd = ['./b2', '-s', 'NO_BZIP2=1', '--with-system',
                   '--with-date_time', '--with-python', '--with-chrono',
                   '--with-random', 'install', '--prefix=%s'%at_home]

            myproc = sub.Popen(cmd, stdout=sub.PIPE, stderr=sub.STDOUT)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode, six.text_type("Building"))

            six.print_("Configuring Libtorrent")
            os.chdir(os.path.join(pkg, libtorrent_dir))
            cmd = ['./configure', '--enable-python-binding',
                   '--disable-dependency-tracking', '--disable-silent-rules',
                   'PYTHON=%s'%with_python, '--prefix=%s'%at_home,
                   '--with-boost=%s'%at_home, '--with-libiconv',
                   '--with-boost-python=boost_python',
                   '--with-openssl=%s'%at_home,
                   'BOOST_ROOT=%s'%os.path.join(pkg, boost_dir)]

            myproc = sub.Popen(cmd, stdout=sub.PIPE, stderr=sub.STDOUT)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode, six.text_type("Configuring Libtorrent"))

            six.print_("Making Libtorrent")
            os.chdir(os.path.join(pkg, libtorrent_dir))
            myproc = sub.Popen(['make'], stdout=sub.PIPE, stderr=sub.STDOUT)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode, six.text_type("Making Libtorrent"))

            six.print_("Make install Libtorrent")
            os.chdir(os.path.join(pkg, libtorrent_dir))
            myproc = sub.Popen(['make', 'install'], stdout=sub.PIPE,
                               stderr=sub.STDOUT)
            with myproc.stdout:
                log_subprocess_output(myproc.stdout)
            myproc.wait()
            message(myproc.returncode,
                    six.text_type("Making install Libtorrent"))

            sh.rmtree(pkg)
            six.print_("Building of all C++ libraries finished")

            six.print_("Creating .at_profile")
            with open(os.path.join(os.environ['HOME'],
                                   ".at_profile"), "w") as outfile:
                outfile.write("export LD_LIBRARY_PATH=" +
                              os.path.join(at_home, "lib") + "\n")
                outfile.write("export PKG_CONFIG_PATH=" +
                              os.path.join(at_home, "lib", "pkgconfig"))

            six.print_("Finished custom install")
            os.chdir(origin)

        install.run(self)
        import pip
        required_packages = self.distribution.install_requires
        for package in required_packages:
            self.announce('Installing %s...' % package, log.INFO)
            pip.main(['install', '--user', package])
        self.announce('Dependencies installed.')

setup(
    name='AcademicTorrents',
    version='1.9',
    author='Ronald Barrios',
    author_email='ronald.degmar@gmail.com',
    packages=['urwid', 'tests'],
    include_package_data=True,
    keywords='torrent bittorrent p2p fileshare filesharing',
    long_description="""AcademicTorrents is a bittorrent client that has
        been developed in order to be used in servers where you cannot sudo.
        AcademicTorrents uses libtorrent in it's backend to handle the
        bittorrent protocol. Console User Interface has been developed by
        using urwid, curses, and npyscreen python libraries""",
    license='GPLv3',
    py_modules=['menu', 'console', 'academictorrents', 'prior'],
    entry_points={
        'console_scripts': ['at-console = console:main'],
    },
    package_data={'tests': ['*.torrent', '.coveragerc']},
    install_requires=[
        'npyscreen', 'coverage',
    ],
    cmdclass={
        'install': BuildingLibtorrent
    }
)
