deluge/setup.py

461 lines
15 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#
from __future__ import print_function
import glob
import os
import platform
import sys
from distutils import cmd
from distutils.command.build import build as _build
from distutils.command.clean import clean as _clean
from distutils.command.install_data import install_data as _install_data
from shutil import rmtree
from setuptools import find_packages, setup
from setuptools.command.test import test as _test
import msgfmt
from version import get_version
try:
from sphinx.setup_command import BuildDoc
except ImportError:
class BuildDoc(object):
pass
def windows_check():
return platform.system() in ('Windows', 'Microsoft')
def osx_check():
return platform.system() == 'Darwin'
desktop_data = 'deluge/ui/data/share/applications/deluge.desktop'
class PyTest(_test):
def initialize_options(self):
_test.initialize_options(self)
self.pytest_args = []
def finalize_options(self):
_test.finalize_options(self)
self.test_args = []
self.test_suite = True
def run_tests(self):
import pytest
errcode = pytest.main(self.test_args)
sys.exit(errcode)
class BuildDocs(BuildDoc):
description = 'Build the documentation'
def run(self):
print('Generating module documentation...')
os.system('sphinx-apidoc --force -o docs/source/modules/ deluge deluge/plugins')
BuildDoc.run(self)
class CleanDocs(cmd.Command):
description = 'Clean the documentation build and rst files'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
for docs_dir in ('docs/build', 'docs/source/modules'):
try:
print('Deleting {}'.format(docs_dir))
rmtree(docs_dir)
except OSError:
pass
class BuildWebUI(cmd.Command):
description = 'Minify WebUI files'
user_options = [
('build-lib', None, 'build folder containing javascript files'),
('develop', 'D', 'build javascript files in develop mode')
]
boolean_options = ['develop']
def initialize_options(self):
self.build_lib = None
self.develop = False
def finalize_options(self):
self.set_undefined_options('build', ('build_lib', 'build_lib'))
def run(self):
if self.develop:
js_basedir = os.path.join(os.path.dirname(__file__), 'deluge', 'ui', 'web', 'js')
else:
js_basedir = os.path.join(self.build_lib, 'deluge', 'ui', 'web', 'js')
js_source_dirs = [os.path.join(js_basedir, 'deluge-all'),
os.path.join(js_basedir, 'extjs', 'ext-extensions')]
import_error = ''
try:
from minify_web_js import minify_js_dir
except ImportError as err:
import_error = err
for source_dir in js_source_dirs:
# If unable to import minify script and there is no existing minified file, raise error.
if import_error:
js_file = os.path.join(os.path.dirname(source_dir), os.path.basename(source_dir)) + '.js'
if not os.path.exists(js_file):
raise ImportError(import_error)
minify_js_dir(source_dir)
class BuildTranslations(cmd.Command):
description = 'Compile .po files into .mo files & create .desktop file'
user_options = [
('build-lib', None, 'lib build folder'),
('develop', 'D', 'Compile translations in develop mode (deluge/i18n)')
]
boolean_options = ['develop']
def initialize_options(self):
self.build_lib = None
self.develop = False
def finalize_options(self):
self.set_undefined_options('build', ('build_lib', 'build_lib'))
def run(self):
po_dir = os.path.join(os.path.dirname(__file__), 'deluge', 'i18n')
if self.develop:
basedir = po_dir
else:
basedir = os.path.join(self.build_lib, 'deluge', 'i18n')
if not windows_check():
# creates the translated desktop file
intltool_merge = 'intltool-merge'
intltool_merge_opts = '--utf8 --quiet --desktop-style'
desktop_in = 'deluge/ui/data/share/applications/deluge.desktop.in'
print('Creating desktop file: %s' % desktop_data)
os.system('C_ALL=C ' + '%s ' * 5 % (intltool_merge, intltool_merge_opts,
po_dir, desktop_in, desktop_data))
print('Compiling po files from %s...' % po_dir)
for path, names, filenames in os.walk(po_dir):
for f in filenames:
upto_date = False
if f.endswith('.po'):
lang = f[:len(f) - 3]
src = os.path.join(path, f)
dest_path = os.path.join(basedir, lang, 'LC_MESSAGES')
dest = os.path.join(dest_path, 'deluge.mo')
if not os.path.exists(dest_path):
os.makedirs(dest_path)
if not os.path.exists(dest):
sys.stdout.write('%s, ' % lang)
sys.stdout.flush()
msgfmt.make(src, dest)
else:
src_mtime = os.stat(src)[8]
dest_mtime = os.stat(dest)[8]
if src_mtime > dest_mtime:
sys.stdout.write('%s, ' % lang)
sys.stdout.flush()
msgfmt.make(src, dest)
else:
upto_date = True
if upto_date:
sys.stdout.write(' po files already upto date. ')
sys.stdout.write('\b\b \nFinished compiling translation files. \n')
class BuildPlugins(cmd.Command):
description = 'Build plugins into .eggs'
user_options = [
('install-dir=', None, 'develop install folder'),
('develop', 'D', 'Compile plugins in develop mode')
]
boolean_options = ['develop']
def initialize_options(self):
self.install_dir = None
self.develop = False
def finalize_options(self):
pass
def run(self):
# Build the plugin eggs
plugin_path = 'deluge/plugins/*'
for path in glob.glob(plugin_path):
if os.path.exists(os.path.join(path, 'setup.py')):
if self.develop and self.install_dir:
os.system('cd ' + path + '&& ' + sys.executable +
' setup.py develop --install-dir=%s' % self.install_dir)
elif self.develop:
os.system('cd ' + path + '&& ' + sys.executable + ' setup.py develop')
else:
os.system('cd ' + path + '&& ' + sys.executable + ' setup.py bdist_egg -d ..')
class EggInfoPlugins(cmd.Command):
description = 'Create .egg-info directories for plugins'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
# Build the plugin eggs
plugin_path = 'deluge/plugins/*'
for path in glob.glob(plugin_path):
if os.path.exists(os.path.join(path, 'setup.py')):
os.system('cd ' + path + '&& ' + sys.executable + ' setup.py egg_info')
class Build(_build):
sub_commands = [('build_webui', None), ('build_trans', None), ('build_plugins', None)] + _build.sub_commands
def run(self):
# Run all sub-commands (at least those that need to be run).
_build.run(self)
try:
from deluge._libtorrent import lt
print('Found libtorrent version: %s' % lt.__version__)
except ImportError as ex:
print('Warning libtorrent not found: %s' % ex)
class InstallData(_install_data):
"""Custom class to fix `setup install` copying data files to incorrect location. (Bug #1389)"""
def finalize_options(self):
self.install_dir = None
self.set_undefined_options('install', ('install_data', 'install_dir'),
('root', 'root'), ('force', 'force'),)
def run(self):
_install_data.run(self)
class CleanPlugins(cmd.Command):
description = 'Cleans the plugin folders'
user_options = [('all', 'a', 'Remove all build output, not just temporary by-products')]
boolean_options = ['all']
def initialize_options(self):
self.all = None
def finalize_options(self):
self.set_undefined_options('clean', ('all', 'all'))
def run(self):
print('Cleaning the plugin\'s folders...')
plugin_path = 'deluge/plugins/*'
for path in glob.glob(plugin_path):
if os.path.exists(os.path.join(path, 'setup.py')):
c = 'cd ' + path + ' && ' + sys.executable + ' setup.py clean'
if self.all:
c += ' -a'
print('Calling \'%s\'' % c)
os.system(c)
# Delete the .eggs
if path[-4:] == '.egg':
print('Deleting egg file "%s"' % path)
os.remove(path)
# Delete the .egg-link
if path[-9:] == '.egg-link':
print('Deleting egg link "%s"' % path)
os.remove(path)
egg_info_dir_path = 'deluge/plugins/*/*.egg-info'
for path in glob.glob(egg_info_dir_path):
# Delete the .egg-info's directories
if path[-9:] == '.egg-info':
print('Deleting %s' % path)
for fpath in os.listdir(path):
os.remove(os.path.join(path, fpath))
os.removedirs(path)
class Clean(_clean):
sub_commands = _clean.sub_commands + [('clean_plugins', None)]
def run(self):
# Remove deluge egg-info.
root_egg_info_dir_path = 'deluge*.egg-info'
for path in glob.glob(root_egg_info_dir_path):
print('Deleting %s' % path)
for fpath in os.listdir(path):
os.remove(os.path.join(path, fpath))
os.removedirs(path)
# Run all sub-commands (at least those that need to be run)
for cmd_name in self.get_sub_commands():
self.run_command(cmd_name)
_clean.run(self)
if os.path.exists(desktop_data):
print('Deleting %s' % desktop_data)
os.remove(desktop_data)
cmdclass = {
'build': Build,
'build_webui': BuildWebUI,
'build_trans': BuildTranslations,
'build_plugins': BuildPlugins,
'build_docs': BuildDocs,
'install_data': InstallData,
'clean_plugins': CleanPlugins,
'clean_docs': CleanDocs,
'clean': Clean,
'egg_info_plugins': EggInfoPlugins,
'test': PyTest,
}
# Data files to be installed to the system.
_data_files = []
if not windows_check() and not osx_check():
_data_files = [
('share/icons/hicolor/scalable/apps', ['deluge/ui/data/icons/hicolor/scalable/apps/deluge.svg']),
('share/icons/hicolor/128x128/apps', ['deluge/ui/data/icons/hicolor/128x128/apps/deluge.png']),
('share/icons/hicolor/16x16/apps', ['deluge/ui/data/icons/hicolor/16x16/apps/deluge.png']),
('share/icons/hicolor/192x192/apps', ['deluge/ui/data/icons/hicolor/192x192/apps/deluge.png']),
('share/icons/hicolor/22x22/apps', ['deluge/ui/data/icons/hicolor/22x22/apps/deluge.png']),
('share/icons/hicolor/24x24/apps', ['deluge/ui/data/icons/hicolor/24x24/apps/deluge.png']),
('share/icons/hicolor/256x256/apps', ['deluge/ui/data/icons/hicolor/256x256/apps/deluge.png']),
('share/icons/hicolor/32x32/apps', ['deluge/ui/data/icons/hicolor/32x32/apps/deluge.png']),
('share/icons/hicolor/36x36/apps', ['deluge/ui/data/icons/hicolor/36x36/apps/deluge.png']),
('share/icons/hicolor/48x48/apps', ['deluge/ui/data/icons/hicolor/48x48/apps/deluge.png']),
('share/icons/hicolor/64x64/apps', ['deluge/ui/data/icons/hicolor/64x64/apps/deluge.png']),
('share/icons/hicolor/72x72/apps', ['deluge/ui/data/icons/hicolor/72x72/apps/deluge.png']),
('share/icons/hicolor/96x96/apps', ['deluge/ui/data/icons/hicolor/96x96/apps/deluge.png']),
('share/pixmaps', ['deluge/ui/data/pixmaps/deluge.png', 'deluge/ui/data/pixmaps/deluge.xpm']),
('share/man/man1', [
'docs/man/deluge.1',
'docs/man/deluged.1',
'docs/man/deluge-gtk.1',
'docs/man/deluge-web.1',
'docs/man/deluge-console.1'])
]
if os.path.exists(desktop_data):
_data_files.append(('share/applications', [desktop_data]))
entry_points = {
'console_scripts': [
'deluge-console = deluge.ui.console:start',
'deluge-web = deluge.ui.web:start',
'deluged = deluge.core.daemon_entry:start_daemon'
],
'gui_scripts': [
'deluge = deluge.ui.ui_entry:start_ui',
'deluge-gtk = deluge.ui.gtkui:start'
],
'deluge.ui': [
'console = deluge.ui.console:Console',
'web = deluge.ui.web:Web',
'gtk = deluge.ui.gtkui:Gtk',
],
}
if windows_check():
entry_points['console_scripts'].extend([
'deluge-debug = deluge.ui.ui_entry:start_ui',
'deluge-web-debug = deluge.ui.web:start',
'deluged-debug = deluge.core.daemon_entry:start_daemon'])
_package_data = {}
_package_data['deluge'] = [
'ui/data/pixmaps/*.png',
'ui/data/pixmaps/*.svg',
'ui/data/pixmaps/*.ico',
'ui/data/pixmaps/*.gif',
'ui/data/pixmaps/flags/*.png',
'plugins/*.egg',
'i18n/*/LC_MESSAGES/*.mo']
_package_data['deluge.ui.web'] = [
'index.html',
'css/*.css',
'icons/*.png',
'images/*.gif',
'images/*.png',
'js/*.js',
'js/extjs/*.js',
'render/*.html',
'themes/css/*.css',
'themes/images/*/*.gif',
'themes/images/*/*.png',
'themes/images/*/*/*.gif',
'themes/images/*/*/*.png']
_package_data['deluge.ui.gtkui'] = ['glade/*.ui']
_version = get_version(prefix='deluge-', suffix='.dev0')
if 'dev' in _version:
_exclude_package_data = {}
else:
_exclude_package_data = {'deluge.ui.web': ['*-debug.js', '*-debug.css']}
# Main setup
setup(
name='deluge',
version=_version,
fullname='Deluge BitTorrent Client',
description='BitTorrent Client',
author='Andrew Resch, Damien Churchill',
author_email='andrewresch@gmail.com, damoxc@gmail.com',
keywords='torrent bittorrent p2p fileshare filesharing',
long_description='''Deluge is a BitTorrent client that utilizes a
daemon/client model. There are various user interfaces available for
Deluge such as the GTK-UI, the Web-UI and a Console-UI. Deluge uses
libtorrent in it's backend to handle the BitTorrent protocol.''',
url='http://deluge-torrent.org',
license='GPLv3',
cmdclass=cmdclass,
tests_require=['pytest'],
data_files=_data_files,
package_data=_package_data,
exclude_package_data=_exclude_package_data,
packages=find_packages(exclude=['plugins', 'docs', 'tests']),
namespace_packages=['deluge', 'deluge.plugins'],
entry_points=entry_points
)