#!/usr/bin/env python2.6
# 2008-2011 copyright David D Lowe
# released under the GPL v3

from __future__ import absolute_import
from distutils.core import setup
from distutils.command.build import build
from distutils.command.build_py import build_py
from distutils.core import Command
import distutils.command.clean
import distutils.command.sdist
import os, sys
import glob
from subprocess import call
import gettext
from xml.dom import minidom

# Epidermis version        
try:
    import epidermis.const
    constPath = os.path.abspath(epidermis.const.__file__)
    if constPath[-4:] in (".pyc", ".pyo"):
        constPath = constPath[:-1]
    if not os.path.samefile(constPath, os.path.join(os.path.dirname(os.path.abspath(__file__)),"epidermis/const.py")):
        print >> sys.stderr, "could not import %s" % os.path.join(os.path.dirname(os.path.abspath(__file__)), "epidermis/const.py")
        raise
    del(constPath)
except:
    print >> sys.stderr, "Could not find version, because python couldn't import epidermis.const"
    raise

def main():
    
    data_files = glob.glob("data/*")  # data_files a list of strings
    # of the relative paths of all non-py files that should be included
    # ex: data_files is ['data/creator.glade', 'data/epidermis.glade', ...]
    
    # Check python version
    if sys.version < '2.6' or sys.version >= '3.0':
        class IncorrectPythonVersion():
            def __str__(self): return "Incorrect python version, need 2.6"
        raise(IncorrectPythonVersion())
    
    setup( name="epidermis", # this should start with a lowercase letter 
        #so that it can be used as a debian package name later on
    version=epidermis.const.VERSION, # string, version of your program, not python version
    description="Epidermis theme manager for your GNOME desktop on Ubuntu", # short
    author="David D Lowe",
    author_email="daviddlowesemail@find-me-at-epidermis.tuxfamily.org",
    url="http://epidermis.tuxfamily.org", # home page for end-users
    license="GPL v2",
    packages=["epidermis", "epidermis.pigments"], # python packages, not debian packages
    data_files=[('share/epidermis/data/', data_files), 
        ('/etc/', ['linux/epidermis.conf']),
        ('share/applications', ['build/i18n/epidermis.desktop']),
        ('/usr/share/pixmaps', ['data/epidermis.svg']),
        ('/usr/share/icons/gnome/scalable/mimetypes', ['linux/gnome-mime-application-x-pigment.svg']),
        ('/usr/share/icons/gnome/32x32/mimetypes', ['linux/gnome-mime-application-x-pigment.png']),
        ('/usr/share/gconf/schemas', ['linux/epidermis.schemas']),
        ('/etc/dbus-1/system.d', ['linux/org.tuxfamily.epidermis.Shell.conf']),
        ('/usr/share/polkit-1/actions', ['build/i18n/org.tuxfamily.epidermis.shell.policy']),
        ('share/mime/packages/', ['linux/epidermis.xml']),
        ('share/apport/package-hooks/', ['linux/source_epidermis.py']),
        ('/etc/apport/crashdb.conf.d/', ['linux/epidermis-crashdb.conf']),
        ('/usr/share/gnome/help/epidermis/C', glob.glob('help/C/*.xml')),
        ('/usr/share/gnome/help/epidermis/C/images', glob.glob('help/C/images/*')),
        ('/usr/share/omf/epidermis', glob.glob('help/lang/*.omf'))], 
            # data_files is a list of tuples
            # each tuple contaning an installation path and a list of data files
    scripts=["run"], # the script that should be run
    classifiers=["Development Status :: 5 - Production/Stable", "Intended Audience :: End Users/Desktop", "License :: OSI Approved :: GNU General Public License (GPL)", "Operating System :: POSIX :: Linux"],
        # a bunch of optional tags, a list of classifiers can be found at http://pypi.python.org/pypi?:action=list_classifiers
    long_description="""Epidermis changes the appearance of your Ubuntu GNOME desktop in all its aspects in one click. Epidermis 'skins' change the appearance of your desktop wallpaper, Metacity windows border theme, your GTK controls theme, your icon theme, your mouse cursor theme, your GRUB bootsplash screen, your GDM login screen theme and your Usplash boot splash image.
Each of these customisations are downloaded in 'pigments' which are available from an Epidermis 'repository'.
Epidermis was written in python with pygtk.
Find more information at http://epidermis.tuxfamily.org and https://launchpad.net/epidermis/""",
    cmdclass={"build":build_with_options,
              "build_py": build_py_keep_permissions,
              "build_dbus_service":build_dbus_service,
              "build_mo":build_mo,
              "clean":total_clean,
              "sdist":sdist})

class build_with_options(build):
    """This class is the same as distutils.command.build.build but with
    one additional option: --installation-dir="""
    user_options = build.user_options
    user_options.append(('installation-dir=',None,"The directory where pshell_service.py is to be found"))
    sub_commands = build.sub_commands
    sub_commands.append(('build_dbus_service',None))
    sub_commands.append(('build_mo',None))
    
    def initialize_options(self):
        build.initialize_options(self)
        self.installation_dir = None
    
    def finalize_options(self):
        build.finalize_options(self)

class build_py_keep_permissions(build_py):
    def copy_file(self, infile, outfile,
                  preserve_mode=1, preserve_times=1, link=None, level=1):
        """Override preserve_mode and set it to 1"""
        build_py.copy_file(self, infile=infile, outfile=outfile, preserve_mode=1,
            preserve_times=preserve_times, link=link, level=level)

class build_dbus_service(Command):
    description = "Build DBus .service file, modifying it so that it points to the correct script"
    user_options = []
    
    def initialize_options(self):
        pass
    
    def finalize_options(self):
        pass
    
    def run(self):
        
        if not os.path.isdir("linux"):
            self.warn("No linux/ directory")
            return
        
        self.mkpath("build/config")
        
        installation_dir = self.get_finalized_command('build').installation_dir
        
        if installation_dir is None:
            install_lib = self.get_finalized_command('install_lib')
            lib_install_dir = install_lib.install_dir
        else:
            lib_install_dir = installation_dir

        self.make_file(["linux/org.tuxfamily.epidermis.Shell.service.in"],
            "build/config/org.tuxfamily.epidermis.Shell.service",
            self._build_dbus_service,[lib_install_dir])
        self.distribution.data_files.append(("/usr/share/dbus-1/system-services",
            ["build/config/org.tuxfamily.epidermis.Shell.service"]))
    
    @staticmethod
    def _build_dbus_service(lib_install_dir):
        """Write build/config/org.tuxfamily.epidermis.Shell.service
        correctly"""
        if lib_install_dir[-1] == "/": lib_install_dir = lib_install_dir[:-1]
        output = ""
        ff = open("linux/org.tuxfamily.epidermis.Shell.service.in","r")
        for line in ff.readlines():
            if line.strip()[:5] == "Exec=":
                line = line.replace("$REPLACE_ME$", lib_install_dir)
            output += line
        ff.close()
        ff = open("build/config/org.tuxfamily.epidermis.Shell.service","w")
        ff.write(output)
        ff.close()

class build_mo(Command):
    description = "Build .mo files and other translated files"
    user_options = []
    
    def initialize_options(self):
        pass
    
    def finalize_options(self):
        pass
    
    def run(self):
        
        if not os.path.exists(os.path.join(os.path.dirname(__file__),
        "convenience_scripts/translate.py")):
            self.warn("could not find %s" % (os.path.join(os.path.dirname(__file__), "convenience_scripts/translate.py")))
            raise
        rp = os.path.join(os.path.dirname(os.path.realpath(__file__)))
        # generate the .mo files from the existing .po files
        environ = os.environ
        environ["MO_BUILD_DIR"] = os.path.join(rp, "build/i18n")
        self.mkpath("build/i18n")
        def call_translate():
            call(["python", "convenience_scripts/translate.py", 
                "--generate-mo", "--ignore-bzr"], cwd=rp, env=environ)
        self.execute(call_translate, [])
        
        mo_files = []
        # mo_files is a list of tuples, each tuple containing one string specifying the location and a list of files
        # to be installed in that location
        # eg: [('/usr/share/locale/en_GB/LC_MESSAGES', ['po/en_GB/LC_MESSAGES/epidermis.mo'])
        for lang in os.listdir("build/i18n/po"):
            if os.path.isdir(os.path.join("build/i18n/po", lang, "LC_MESSAGES")):
                if len(glob.glob(os.path.join("build/i18n/po",lang,"LC_MESSAGES","*.mo"))) <= 0:
                    print >> sys.stderr, "could not find %s" % os.path.join("build/i18n/po",lang,"LC_MESSAGES","*.mo")
                    raise
                mo_files.append((os.path.join("/usr/share/locale", lang, "LC_MESSAGES"), 
                    glob.glob(os.path.join("build/i18n/po", lang, "LC_MESSAGES") + "/*.mo")))
        self.distribution.data_files.extend(mo_files)

        
        # similar to mo_files but for docbooks   
        docbooks = []
        omfs = []
        for lang in os.listdir("build/i18n/help"):
            if os.path.isdir(os.path.join("build/i18n/help", lang)):
                docbooks.append((os.path.join("/usr/share/gnome/help/epidermis", lang), 
                    glob.glob(os.path.join("build/i18n/help", lang) + "/*.xml")))
                omfs.extend(glob.glob(os.path.join("build/i18n/help",lang) + "/*.omf"))
                if os.path.isdir(os.path.join("build/i18n/help",lang,"images")):
                    docbooks.append((os.path.join("/usr/share/gnome/help/epidermis",lang,"images"), 
                        glob.glob(os.path.join("build/i18n/help",lang,"images") + "/*")))
        if len(omfs) > 0:
            docbooks.append(('/usr/share/omf/epidermis',omfs))
        
        self.distribution.data_files.extend(docbooks)
        
        # this fallback returns None, used to verify if strings have been
        # translated
        class Fallback(gettext.NullTranslations):
            def gettext(self, msg):
                return None
        
        # get Translations objects
        translations = {}
        for lang in os.listdir("build/i18n/po"):
            if os.path.isfile(os.path.join("build/i18n/po/%s/LC_MESSAGES/epidermis.mo") % lang):
                translations[lang] = gettext.translation(epidermis.const.APP_NAME,
                    localedir="build/i18n/po",languages=[lang])
        
        # add i18n strings to .policy file (build it)
        policy = minidom.parse("linux/org.tuxfamily.epidermis.shell.policy")
        for action in policy.getElementsByTagName("action"):
            for tagname in ("description", "message"):
                text = self.get_first_text( 
                    action.getElementsByTagName(tagname)[0])
                for trans in translations:
                    translations[trans].add_fallback(Fallback())
                    node = policy.createElement(tagname)
                    node.setAttribute("xml:lang", trans)
                    newtext = translations[trans].gettext(text)
                    if newtext:
                        node.appendChild(policy.createTextNode(newtext.decode('utf-8')))
                        action.appendChild(node)
                        action.appendChild(policy.createTextNode("\n".decode('utf-8')))
        output = policy.toxml()
        open("build/i18n/org.tuxfamily.epidermis.shell.policy","w").write(
            output.encode('utf-8'))
        
        # add i18n strings to .desktop file (build it)
        output = ""
        for line in open("linux/epidermis.desktop","r").readlines():
            output += line
            if line.startswith("Name=") or line.startswith("Comment="):
                sides = line.split("=")
                for trans in translations:
                    newtext = translations[trans].gettext(sides[1][:-1])
                    if newtext:
                        output += "%s[%s]=%s\n" % (sides[0], trans, newtext)
        open("build/i18n/epidermis.desktop","w").write(output)            
    
    @staticmethod
    def get_first_text(thexml):
        """Get text of XML node (ignores comments)"""
        import xml.dom
        for el in thexml.childNodes:
            if el.nodeType == xml.dom.Node.TEXT_NODE:
                return el.data
        return None
            

class total_clean(distutils.command.clean.clean):
    description = distutils.command.clean.clean.description + \
        ", delete build_base directory (usually build/) and any built " + \
        " .mo files"
    
    def run(self):
        # run usual clean command:
        distutils.command.clean.clean.run(self)
        # now delete build/ directory recursively
        if os.path.exists(self.build_base):
            distutils.dir_util.remove_tree(self.build_base, 
                dry_run=self.dry_run)
        else:
            distutils.log.warn("'%s' does not exist -- can't clean it",
                self.build_base)
        # delete any .mo directories
        po_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),"po")
        for ff in os.listdir(os.path.join(os.path.dirname(__file__), "po")):
            if os.path.isdir(os.path.join(po_dir, ff, "LC_MESSAGES")):
                distutils.dir_util.remove_tree(os.path.join(po_dir, ff),
                    dry_run=self.dry_run)
       

class sdist(distutils.command.sdist.sdist):
    def prune_file_list(self):
        distutils.command.sdist.sdist.prune_file_list(self)
        self.filelist.exclude_pattern("~$", is_regex=1) # exclude backup files ending with ~
        self.filelist.exclude_pattern(".pyc$", is_regex=1) # exclude .pyc files

if __name__ == "__main__":
    main()
