setup.py 8.94 KB
Newer Older
André's avatar
André committed
1 2 3 4 5
#!/usr/bin/env python3

import os
import sys

Philipp Hörist's avatar
Philipp Hörist committed
6
if sys.version_info < (3, 5):
7
    sys.exit('Gajim needs Python 3.5+')
André's avatar
André committed
8 9

from setuptools import setup, find_packages
André's avatar
André committed
10
from setuptools import Command
11
from setuptools.command.build_py import build_py as _build
12
from setuptools.command.install import install as _install
André's avatar
André committed
13 14 15
from distutils import log
from distutils.util import convert_path, newer

André's avatar
André committed
16 17
import subprocess

André's avatar
André committed
18 19 20 21
import gajim

pos = [x for x in os.listdir('po') if x[-3:] == ".po"]
ALL_LINGUAS = sorted([os.path.split(x)[-1][:-3] for x in pos])
22 23 24
MAN_FILES = ['gajim.1', 'gajim-history-manager.1', 'gajim-remote.1']
META_FILES = [('data/org.gajim.Gajim.desktop', 'share/applications', '--desktop'),
              ('data/org.gajim.Gajim.appdata.xml', 'share/metainfo', '--xml')]
25
cwd = os.path.dirname(os.path.realpath(__file__))
26
build_dir = os.path.join(cwd, "build")
André's avatar
André committed
27

André's avatar
André committed
28 29 30 31 32 33 34 35 36 37

def update_trans():
    '''
    Update translation files
    '''
    template = os.path.join('po', 'gajim.pot')
    files = [os.path.join(root, f) for root, d, files in os.walk('gajim') for f in files if os.path.isfile(
        os.path.join(root, f)) and (f.endswith('.py') or f.endswith('.ui'))]
    files.append(os.path.join("data", "org.gajim.Gajim.desktop.in"))
    files.append(os.path.join("data", "org.gajim.Gajim.appdata.xml.in"))
38
    cmd = 'xgettext -c# --from-code=utf-8 --keyword=Q_ -o %s %s' % (
André's avatar
André committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
        template, " ".join(files))
    if os.system(cmd) != 0:
        msg = "ERROR: %s could not be created!\n" % template
        raise SystemExit(msg)

    for lang in ALL_LINGUAS:
        po_file = os.path.join('po', lang + '.po')
        cmd = 'msgmerge -U %s %s' % (po_file, template)
        if os.system(cmd) != 0:
            msg = 'ERROR: Updating language translation file failed.'
            ask = msg + '\n Continue updating y/n [n] '
            reply = input(ask)
            if reply in ['n', 'N']:
                raise SystemExit(msg)
        log.info('Updating %s', po_file)


André's avatar
André committed
56 57 58 59 60 61
def build_trans(build_cmd):
    '''
    Translate the language files into gajim.mo
    '''
    for lang in ALL_LINGUAS:
        po_file = os.path.join('po', lang + '.po')
62
        mo_file = os.path.join(build_dir, 'mo', lang, 'LC_MESSAGES', 'gajim.mo')
André's avatar
André committed
63
        mo_dir = os.path.dirname(mo_file)
64
        if not (os.path.isdir(mo_dir) or os.path.islink(mo_dir)):
André's avatar
André committed
65 66 67 68 69 70 71 72 73 74 75 76 77
            os.makedirs(mo_dir)

        if newer(po_file, mo_file):
            cmd = 'msgfmt %s -o %s' % (po_file, mo_file)
            if os.system(cmd) != 0:
                os.remove(mo_file)
                msg = 'ERROR: Building language translation files failed.'
                ask = msg + '\n Continue building y/n [n] '
                reply = input(ask)
                if reply in ['n', 'N']:
                    raise SystemExit(msg)
            log.info('Compiling %s >> %s', po_file, mo_file)

78 79 80 81 82

def install_trans(install_cmd):
    data_files = install_cmd.distribution.data_files
    for lang in ALL_LINGUAS:
        mo_file = os.path.join(build_dir, 'mo', lang, 'LC_MESSAGES', 'gajim.mo')
André's avatar
André committed
83
        target = 'share/locale/' + lang + '/LC_MESSAGES'
84
        data_files.append((target, [mo_file]))
André's avatar
André committed
85

André's avatar
André committed
86

André's avatar
André committed
87 88
def build_man(build_cmd):
    '''
89
    Compress Gajim manual files
André's avatar
André committed
90
    '''
91 92 93
    newdir = os.path.join(build_dir, 'man')
    if not (os.path.isdir(newdir) or os.path.islink(newdir)):
        os.makedirs(newdir)
André's avatar
André committed
94

95 96
    for man in MAN_FILES:
        filename = os.path.join('data', man)
André's avatar
André committed
97 98 99 100 101 102 103 104
        man_file_gz = os.path.join(newdir, man + '.gz')
        if os.path.exists(man_file_gz):
            if newer(filename, man_file_gz):
                os.remove(man_file_gz)
            else:
                filename = False

        if filename:
105
            import gzip
André's avatar
André committed
106
            # Binary io, so open is OK
André's avatar
André committed
107 108 109 110 111
            with open(filename, 'rb') as f_in,\
                    gzip.open(man_file_gz, 'wb') as f_out:
                f_out.writelines(f_in)
                log.info('Compiling %s >> %s', filename, man_file_gz)

112 113 114 115 116 117 118 119

def install_man(install_cmd):
    data_files = install_cmd.distribution.data_files
    man_dir = os.path.join(build_dir, 'man')
    target = 'share/man/man1'

    for man in MAN_FILES:
        man_file_gz = os.path.join(man_dir, man + '.gz')
André's avatar
André committed
120
        data_files.append((target, [man_file_gz]))
André's avatar
André committed
121

André's avatar
André committed
122

André's avatar
André committed
123 124 125 126
def build_intl(build_cmd):
    '''
    Merge translation files into desktop and mime files
    '''
127
    base = build_dir
André's avatar
André committed
128

129
    for filename, _, option in META_FILES:
André's avatar
André committed
130 131 132 133 134 135
        filenamelocal = convert_path(filename)
        newfile = os.path.join(base, filenamelocal)
        newdir = os.path.dirname(newfile)
        if not(os.path.isdir(newdir) or os.path.islink(newdir)):
            os.makedirs(newdir)
        merge(filenamelocal + '.in', newfile, option)
136 137 138 139 140 141 142


def install_intl(install_cmd):
    data_files = install_cmd.distribution.data_files

    for filename, target, _ in META_FILES:
        data_files.append((target, [build_dir + '/' + filename]))
André's avatar
André committed
143

André's avatar
André committed
144

145
def merge(in_file, out_file, option, po_dir='po'):
André's avatar
André committed
146
    '''
147
    Run the msgfmt command.
André's avatar
André committed
148
    '''
149
    if os.path.exists(in_file):
150
        cmd = (('msgfmt %(opt)s -d %(po_dir)s --template %(in_file)s '
André's avatar
André committed
151 152 153 154 155
                '-o %(out_file)s') %
               {'opt': option,
                'po_dir': po_dir,
                'in_file': in_file,
                'out_file': out_file})
André's avatar
André committed
156 157
        if os.system(cmd) != 0:
            msg = ('ERROR: %s was not merged into the translation files!\n' %
André's avatar
André committed
158
                   out_file)
André's avatar
André committed
159 160 161 162 163 164 165
            raise SystemExit(msg)
        log.info('Compiling %s >> %s', in_file, out_file)


class build(_build):
    def run(self):
        build_trans(self)
166
        if sys.platform != 'win32':
André's avatar
André committed
167 168 169 170 171
            build_man(self)
            build_intl(self)
        _build.run(self)


172 173 174 175 176 177 178 179 180
class install(_install):
    def run(self):
        install_trans(self)
        if sys.platform != 'win32':
            install_man(self)
            install_intl(self)
        _install.run(self)


André's avatar
André committed
181 182 183 184 185 186 187 188 189 190 191
class test(Command):
    description = "Run all tests"
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
André's avatar
André committed
192
        exit(subprocess.call("./test/runtests.py"))
André's avatar
André committed
193

André's avatar
André committed
194

André's avatar
André committed
195 196 197 198
class test_nogui(test):
    description = "Run tests without GUI"

    def run(self):
André's avatar
André committed
199
        exit(subprocess.call(["./test/runtests.py", "-n"]))
André's avatar
André committed
200

André's avatar
André committed
201

André's avatar
André committed
202 203 204 205 206 207 208 209 210 211 212 213 214
class update_po(Command):
    description = "Update po files"
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        update_trans()

André's avatar
André committed
215

216
package_data_activities = ['data/activities/*/*/*.png']
217
package_data_emoticons = ['data/emoticons/*/*.png',
André's avatar
André committed
218 219
                          'data/emoticons/*/LICENSE']
package_data_gui = ['data/gui/*.ui']
André's avatar
André committed
220 221 222 223 224
package_data_icons = ['data/icons/hicolor/*/*/*.png',
                      'data/icons/hicolor/*/*/*.svg']
package_data_iconsets = ['data/iconsets/*/*/*.gif',
                         'data/iconsets/*/*/*.png',
                         'data/iconsets/transports/*/*/*.png']
225
package_data_moods = ['data/moods/*/*.png']
André's avatar
André committed
226
package_data_other = ['data/other/*']
227
package_data_sounds = ['data/sounds/*.wav']
Philipp Hörist's avatar
Philipp Hörist committed
228
package_data_style = ['data/style/*.css']
229
package_plugins_data = ['data/plugins/*/*']
230 231
package_data = (package_data_activities
                + package_data_emoticons
André's avatar
André committed
232 233 234
                + package_data_gui
                + package_data_icons
                + package_data_iconsets
235
                + package_data_moods
André's avatar
André committed
236
                + package_data_other
237 238 239
                + package_data_sounds
                + package_data_style
                + package_plugins_data)
André's avatar
André committed
240 241 242 243


# only install subdirectories of data
data_files_app_icon = [
André's avatar
André committed
244 245 246 247 248
    ("share/icons/hicolor/64x64/apps",
     ["gajim/data/icons/hicolor/64x64/apps/org.gajim.Gajim.png"]),
    ("share/icons/hicolor/128x128/apps",
     ["gajim/data/icons/hicolor/128x128/apps/org.gajim.Gajim.png"]),
    ("share/icons/hicolor/scalable/apps",
André's avatar
André committed
249 250 251
     ["gajim/data/icons/hicolor/scalable/apps/org.gajim.Gajim.svg"]),
    ("share/icons/hicolor/symbolic/apps",
     ["gajim/data/icons/hicolor/symbolic/apps/org.gajim.Gajim-symbolic.svg"])
André's avatar
André committed
252
]
André's avatar
André committed
253 254 255 256

data_files = data_files_app_icon

setup(
André's avatar
André committed
257 258 259 260 261 262 263 264
    name="gajim",
    description='A GTK+ Jabber client',
    version=gajim.__version__,
    author="Philipp Hörist, Yann Leboulanger",
    author_email="gajim-devel@gajim.org",
    url='https://gajim.org',
    license='GPL v3',
    classifiers=[
265 266
        'Programming Language :: Python :: 3',
    ],
André's avatar
André committed
267
    cmdclass={
268
        'build_py': build,
269
        'install': install,
André's avatar
André committed
270 271
        'test': test,
        'test_nogui': test_nogui,
André's avatar
André committed
272
        'update_po': update_po,
André's avatar
André committed
273
    },
274 275 276 277 278 279 280 281 282
    entry_points={
        'console_scripts': [
            'gajim-remote = gajim.gajim_remote:main',
        ],
        'gui_scripts': [
            'gajim = gajim.gajim:main',
            'gajim-history-manager = gajim.history_manager:main',
        ]
    },
André's avatar
André committed
283 284 285 286
    packages=find_packages(exclude=["gajim.dev", "test*"]),
    package_data={'gajim': package_data},
    data_files=data_files,
    install_requires=[
André's avatar
André committed
287
        'keyring',
288
        'nbxmpp>=0.6.8,<0.7.0',
André's avatar
André committed
289
        'pyOpenSSL>=0.12',
290 291
        'cssutils>=1.0.2',
        'precis-i18n>=1.0.0',
André's avatar
André committed
292
    ]
André's avatar
André committed
293
)