Source

thg / setup.py

Full commit
TK Soh 9935bc5 
Germán Poo-Caama… 9c1b7b5 
Steve Borho bd8ca53 
Germán Poo-Caama… 9c1b7b5 
Steve Borho bd8ca53 


TK Soh 9935bc5 
Steve Borho f03027a 
TK Soh 9935bc5 


Steve Borho b116bd3 
Steve Borho 0563f76 
Yuya Nishihara ae6e69c 
Yuya Nishihara 02ababb 
Yuya Nishihara 6ce3e4a 
Yuya Nishihara 14273bb 
Yuya Nishihara ae6e69c 
Yuya Nishihara bcf7534 
Peer Sommerlund bdde059 
Toshi MARUYAMA 04b0a54 
Peer Sommerlund bdde059 
Adrian Buehlmann a51bc97 

Peer Sommerlund bdde059 
Yuya Nishihara 6ce3e4a 
Peer Sommerlund bdde059 

Yuya Nishihara 6ce3e4a 






Peer Sommerlund bdde059 






Peer Sommerlund b012c68 
Peer Sommerlund bdde059 








Peer Sommerlund b012c68 
Peer Sommerlund bdde059 







Yuya Nishihara 6ce3e4a 
Yuya Nishihara a0dc320 
Yuya Nishihara bcf7534 


Yuya Nishihara 6ce3e4a 

Yuya Nishihara bcf7534 
Yuya Nishihara 6ce3e4a 

Yuya Nishihara bcf7534 
Yuya Nishihara 6ce3e4a 
Toshi MARUYAMA 04b0a54 



Yuya Nishihara bcf7534 

Toshi MARUYAMA 04b0a54 




Yuya Nishihara 02ababb 
Toshi MARUYAMA 04b0a54 
kiilerix b5b0cd5 


Toshi MARUYAMA 04b0a54 





Yuya Nishihara bcf7534 

Toshi MARUYAMA 04b0a54 
kiilerix b5b0cd5 



Yuya Nishihara 23c5d88 


Toshi MARUYAMA 04b0a54 
Yuya Nishihara 68b55b4 
Yuya Nishihara 95470e4 

Toshi MARUYAMA 04b0a54 





Yuya Nishihara 68b55b4 


















Yuya Nishihara f116b1f 

Yuya Nishihara 68b55b4 


Yuya Nishihara ae6e69c 


























Yuya Nishihara 14273bb 




Peer Sommerlund bdde059 
Yuya Nishihara ae6e69c 









Peer Sommerlund bdde059 
Yuya Nishihara 14273bb 
Yuya Nishihara 33f47cd 
Toshi MARUYAMA 04b0a54 
Yuya Nishihara ae6e69c 

Toshi MARUYAMA 04b0a54 
TK Soh 9935bc5 
Adrian Buehlmann 92447cd 
Germán Poo-Caama… 9c1b7b5 


Steve Borho a931631 
Germán Poo-Caama… 9c1b7b5 
Steve Borho b994c8a 
TK Soh 9935bc5 
Steve Borho ad7d3f5 

















Germán Poo-Caama… 9c1b7b5 


TK Soh 9935bc5 
Germán Poo-Caama… 9c1b7b5 
Steve Borho b994c8a 



Germán Poo-Caama… 9c1b7b5 

Sune Foldager 2addb6a 
Yuya Nishihara cef10e7 








Sune Foldager 2addb6a 
Steve Borho b994c8a 






Steve Borho 6dbe8a1 
Germán Poo-Caama… 9c1b7b5 
Steve Borho 154e4a5 
Sune Foldager 2addb6a 
Germán Poo-Caama… 9c1b7b5 
Yuya Nishihara 35d985e 

Steve Borho 154e4a5 
Steve Borho e5308ea 
Germán Poo-Caama… 9c1b7b5 

Steve Borho b116bd3 
Steve Borho 594b199 
Steve Borho b116bd3 




Adrian Buehlmann a51bc97 

Adrian Buehlmann afa14c7 
Adrian Buehlmann 92447cd 

Steve Borho e673083 
Adrian Buehlmann d9e4d29 
Adrian Buehlmann 92447cd 

Steve Borho 594b199 

Steve Borho b116bd3 
Steve Borho 8d34a59 



Adrian Buehlmann 73b858c 
Adrian Buehlmann a51bc97 
Adrian Buehlmann fa9c420 
Adrian Buehlmann 92447cd 

Steve Borho 594b199 
Germán Poo-Caama… 9c1b7b5 
Steve Borho 6dbe8a1 
Germán Poo-Caama… 9c1b7b5 




Steve Borho a931631 

Germán Poo-Caama… 9c1b7b5 


Steve Borho d45a11d 
Steve Borho 5b3e082 

Germán Poo-Caama… 9c1b7b5 


Steve Borho 4e30f55 
Steve Borho db36d1f 
Steve Borho 66ff650 
Steve Borho 4e30f55 
Steve Borho bbeda1f 



kiilerix 0b4e5b9 
Steve Borho bbeda1f 
Steve Borho 0c7a335 
Steve Borho 6dbe8a1 
Germán Poo-Caama… 9c1b7b5 
Steve Borho cadd0b2 













Yuya Nishihara cf2d80d 

Steve Borho 0563f76 
Yuya Nishihara cf2d80d 


































Steve Borho cadd0b2 
Yuya Nishihara cf2d80d 



Steve Borho cc4bb7c 
Yuya Nishihara cf2d80d 











# setup.py
# A distutils setup script to install TortoiseHg in Windows and Posix
# environments.
#
# On Windows, this script is mostly used to build a stand-alone
# TortoiseHg package.  See installer\build.txt for details. The other
# use is to report the current version of the TortoiseHg source.


import time
import sys
import os
import shutil
import subprocess
from fnmatch import fnmatch
from distutils import log
from distutils.core import setup, Command
from distutils.command.build import build as _build_orig
from distutils.command.clean import clean as _clean_orig
from distutils.dep_util import newer
from distutils.spawn import spawn, find_executable
from os.path import isdir, exists, join, walk, splitext

thgcopyright = 'Copyright (C) 2010 Steve Borho and others'
hgcopyright = 'Copyright (C) 2005-2010 Matt Mackall and others'

class build_mo(Command):

    description = "build translations (.mo files)"
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        if not find_executable('msgfmt'):
            self.warn("could not find msgfmt executable, no translations "
                     "will be built")
            return

        podir = 'i18n/tortoisehg'
        if not os.path.isdir(podir):
            self.warn("could not find %s/ directory" % podir)
            return

        join = os.path.join
        for po in os.listdir(podir):
            if not po.endswith('.po'):
                continue
            pofile = join(podir, po)
            modir = join('locale', po[:-3], 'LC_MESSAGES')
            mofile = join(modir, 'tortoisehg.mo')
            cmd = ['msgfmt', '-v', '-o', mofile, pofile]
            if sys.platform != 'sunos5':
                # msgfmt on Solaris does not know about -c
                cmd.append('-c')
            self.mkpath(modir)
            self.make_file([pofile], mofile, spawn, (cmd,))

class build_qt(Command):
    description = "build PyQt GUIs (.ui) and resources (.qrc)"
    user_options = [('force', 'f', 'forcibly compile everything'
                     ' (ignore file timestamps)')]
    boolean_options = ('force',)

    def initialize_options(self):
        self.force = None

    def finalize_options(self):
        self.set_undefined_options('build', ('force', 'force'))

    def compile_ui(self, ui_file, py_file=None):
        # Search for pyuic4 in python bin dir, then in the $Path.
        if py_file is None:
            py_file = splitext(ui_file)[0] + "_ui.py"
        if not(self.force or newer(ui_file, py_file)):
            return
        try:
            from PyQt4 import uic
            fp = open(py_file, 'w')
            uic.compileUi(ui_file, fp)
            fp.close()
            log.info('compiled %s into %s' % (ui_file, py_file))
        except Exception, e:
            self.warn('Unable to compile user interface %s: %s' % (py_file, e))
            if not exists(py_file) or not file(py_file).read():
                raise SystemExit(1)
            return

    def compile_rc(self, qrc_file, py_file=None):
        # Search for pyuic4 in python bin dir, then in the $Path.
        if py_file is None:
            py_file = splitext(qrc_file)[0] + "_rc.py"
        if not(self.force or newer(qrc_file, py_file)):
            return
        if os.system('pyrcc4 "%s" -o "%s"' % (qrc_file, py_file)) > 0:
            self.warn("Unable to generate python module %s for resource file %s"
                      % (py_file, qrc_file))
            if not exists(py_file) or not file(py_file).read():
                raise SystemExit(1)
        else:
            log.info('compiled %s into %s' % (qrc_file, py_file))

    def run(self):
        self._wrapuic()
        basepath = join(os.path.dirname(__file__), 'tortoisehg', 'hgqt')
        for dirpath, _, filenames in os.walk(basepath):
            for filename in filenames:
                if filename.endswith('.ui'):
                    self.compile_ui(join(dirpath, filename))
                elif filename.endswith('.qrc'):
                    self.compile_rc(join(dirpath, filename))

    _wrappeduic = False
    @classmethod
    def _wrapuic(cls):
        """wrap uic to use gettext's _() in place of tr()"""
        if cls._wrappeduic:
            return

        from PyQt4.uic.Compiler import compiler, qtproxies, indenter

        class _UICompiler(compiler.UICompiler):
            def createToplevelWidget(self, classname, widgetname):
                o = indenter.getIndenter()
                o.level = 0
                o.write('from tortoisehg.hgqt.i18n import _')
                return super(_UICompiler, self).createToplevelWidget(classname, widgetname)
        compiler.UICompiler = _UICompiler

        class _i18n_string(qtproxies.i18n_string):
            def __str__(self):
                return "_('%s')" % self.string.encode('string-escape')
        qtproxies.i18n_string = _i18n_string

        cls._wrappeduic = True

class clean_local(Command):
    pats = ['*.py[co]', '*_ui.py', '*_rc.py', '*.orig', '*.rej']
    excludedirs = ['.hg', 'build', 'dist']
    description = 'clean up generated files (%s)' % ', '.join(pats)
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        for e in self._walkpaths('.'):
            log.info("removing '%s'" % e)
            os.remove(e)

    def _walkpaths(self, path):
        for root, _dirs, files in os.walk(path):
            if any(root == join(path, e) or root.startswith(join(path, e, ''))
                   for e in self.excludedirs):
                continue
            for e in files:
                fpath = join(root, e)
                if any(fnmatch(fpath, p) for p in self.pats):
                    yield fpath

class build(_build_orig):
    sub_commands = [
        ('build_qt', None),
        ('build_mo', None),
        ] + _build_orig.sub_commands

class clean(_clean_orig):
    sub_commands = [
        ('clean_local', None),
        ] + _clean_orig.sub_commands

    def run(self):
        _clean_orig.run(self)
        for e in self.get_sub_commands():
            self.run_command(e)

cmdclass = {
        'build': build,
        'build_qt': build_qt ,
        'build_mo': build_mo ,
        'clean': clean,
        'clean_local': clean_local,
    }

def setup_windows(version):
    # Specific definitios for Windows NT-alike installations
    _scripts = []
    _data_files = []
    _packages = ['tortoisehg.hgqt', 'tortoisehg.util', 'tortoisehg']
    extra = {}
    hgextmods = []

    # py2exe needs to be installed to work
    try:
        import py2exe

        # Help py2exe to find win32com.shell
        try:
            import modulefinder
            import win32com
            for p in win32com.__path__[1:]: # Take the path to win32comext
                modulefinder.AddPackagePath("win32com", p)
            pn = "win32com.shell"
            __import__(pn)
            m = sys.modules[pn]
            for p in m.__path__[1:]:
                modulefinder.AddPackagePath(pn, p)
        except ImportError:
            pass

    except ImportError:
        if '--version' not in sys.argv:
            raise

    if 'py2exe' in sys.argv:
        import hgext
        hgextdir = os.path.dirname(hgext.__file__)
        hgextmods = set(["hgext." + os.path.splitext(f)[0]
                      for f in os.listdir(hgextdir)])
        _data_files = [(root, [os.path.join(root, file_) for file_ in files])
                            for root, dirs, files in os.walk('icons')]

    # for PyQt, see http://www.py2exe.org/index.cgi/Py2exeAndPyQt
    includes = ['sip']

    # Qt4 plugins, see http://stackoverflow.com/questions/2206406/
    def qt4_plugins(subdir, *dlls):
        import PyQt4
        pluginsdir = join(os.path.dirname(PyQt4.__file__), 'plugins')
        return (subdir, [join(pluginsdir, subdir, e) for e in dlls])
    _data_files.append(qt4_plugins('imageformats', 'qico4.dll', 'qsvg4.dll'))

    # Manually include other modules py2exe can't find by itself.
    if 'hgext.highlight' in hgextmods:
        includes += ['pygments.*', 'pygments.lexers.*', 'pygments.formatters.*',
                     'pygments.filters.*', 'pygments.styles.*']
    if 'hgext.patchbomb' in hgextmods:
        includes += ['email.*', 'email.mime.*']

    extra['options'] = {
       "py2exe" : {
           "skip_archive" : 0,

           # Don't pull in all this MFC stuff used by the makepy UI.
           "excludes" : "pywin,pywin.dialogs,pywin.dialogs.list"
                        ",setup,distutils",  # required only for in-place use
           "includes" : includes,
           "optimize" : 1
       }
    }
    shutil.copyfile('thg', 'thgw')
    extra['console'] = [
            {'script':'thg',
             'icon_resources':[(0,'icons/thg_logo.ico')],
             'description':'TortoiseHg GUI tools for Mercurial SCM',
             'copyright':thgcopyright,
             'product_version':version},
            {'script':'contrib/hg', 
             'icon_resources':[(0,'icons/hg.ico')],
             'description':'Mercurial Distributed SCM',
             'copyright':hgcopyright,
             'product_version':version},
            {'script':'win32/docdiff.py',
             'icon_resources':[(0,'icons/TortoiseMerge.ico')],
             'copyright':thgcopyright,
             'product_version':version}
            ]
    extra['windows'] = [
            {'script':'thgw',
             'icon_resources':[(0,'icons/thg_logo.ico')],
             'description':'TortoiseHg GUI tools for Mercurial SCM',
             'copyright':thgcopyright,
             'product_version':version},
            {'script':'TortoiseHgOverlayServer.py',
             'icon_resources':[(0,'icons/thg_logo.ico')],
             'description':'TortoiseHg Overlay Icon Server',
             'copyright':thgcopyright,
             'product_version':version}
            ]

    return _scripts, _packages, _data_files, extra


def setup_posix():
    # Specific definitios for Posix installations
    _extra = {}
    _scripts = ['thg']
    _packages = ['tortoisehg', 'tortoisehg.hgqt', 'tortoisehg.util']
    _data_files = [(os.path.join('share/pixmaps/tortoisehg', root),
        [os.path.join(root, file_) for file_ in files])
        for root, dirs, files in os.walk('icons')]
    _data_files += [(os.path.join('share', root),
        [os.path.join(root, file_) for file_ in files])
        for root, dirs, files in os.walk('locale')]
    _data_files += [('lib/nautilus/extensions-2.0/python',
                     ['contrib/nautilus-thg.py'])]

    # Create a config.py.  Distributions will need to supply their own
    cfgfile = os.path.join('tortoisehg', 'util', 'config.py')
    if not os.path.exists(cfgfile) and not os.path.exists('.hg/requires'):
        f = open(cfgfile, "w")
        f.write('bin_path     = "/usr/bin"\n')
        f.write('license_path = "/usr/share/doc/tortoisehg/Copying.txt.gz"\n')
        f.write('locale_path  = "/usr/share/locale"\n')
        f.write('icon_path    = "/usr/share/pixmaps/tortoisehg/icons"\n')
        f.write('nofork       = True\n')
        f.close()

    return _scripts, _packages, _data_files, _extra

def runcmd(cmd, env):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE, env=env)
    out, err = p.communicate()
    # If root is executing setup.py, but the repository is owned by
    # another user (as in "sudo python setup.py install") we will get
    # trust warnings since the .hg/hgrc file is untrusted. That is
    # fine, we don't want to load it anyway.
    err = [e for e in err.splitlines()
           if not e.startswith('Not trusting file')]
    if err:
        return ''
    return out

if __name__ == '__main__':
    version = ''

    if os.path.isdir('.hg'):
        from tortoisehg.util import version as _version
        branch, version = _version.liveversion()
        if version.endswith('+'):
            version += time.strftime('%Y%m%d')
    elif os.path.exists('.hg_archival.txt'):
        kw = dict([t.strip() for t in l.split(':', 1)]
                  for l in open('.hg_archival.txt'))
        if 'tag' in kw:
            version =  kw['tag']
        elif 'latesttag' in kw:
            version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
        else:
            version = kw.get('node', '')[:12]

    if version:
        f = open("tortoisehg/util/__version__.py", "w")
        f.write('# this file is autogenerated by setup.py\n')
        f.write('version = "%s"\n' % version)
        f.close()

    try:
        import tortoisehg.util.__version__
        version = tortoisehg.util.__version__.version
    except ImportError:
        version = 'unknown'

    if os.name == "nt":
        (scripts, packages, data_files, extra) = setup_windows(version)
        desc = 'Windows shell extension for Mercurial VCS'
        # Windows binary file versions for exe/dll files must have the
        # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
        from tortoisehg.util.version import package_version
        setupversion = package_version()
        productname = 'TortoiseHg'
    else:
        (scripts, packages, data_files, extra) = setup_posix()
        desc = 'TortoiseHg dialogs for Mercurial VCS'
        setupversion = version
        productname = 'tortoisehg'

    setup(name=productname,
            version=setupversion,
            author='Steve Borho',
            author_email='steve@borho.org',
            url='http://tortoisehg.org',
            description=desc,
            license='GNU GPL2',
            scripts=scripts,
            packages=packages,
            data_files=data_files,
            cmdclass=cmdclass,
            **extra
        )