deluge/setup.py

602 lines
18 KiB
Python
Raw Normal View History

2011-05-21 12:00:59 +00:00
#!/usr/bin/env python
2014-09-22 21:15:33 +00:00
# -*- coding: utf-8 -*-
2007-07-04 08:24:30 +00:00
#
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
2014-09-22 21:15:33 +00:00
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
2008-07-14 20:42:11 +00:00
#
2014-09-22 21:15:33 +00:00
# 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.
2007-07-04 08:24:30 +00:00
#
from __future__ import print_function
import glob
2012-11-14 12:27:41 +00:00
import os
import platform
import sys
from distutils import cmd
2007-09-16 01:24:08 +00:00
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 distutils.spawn import find_executable
2016-11-27 17:04:12 +00:00
from shutil import rmtree
from setuptools import find_packages, setup
2014-09-25 20:05:57 +00:00
from setuptools.command.test import test as _test
import msgfmt
from version import get_version
2009-07-22 23:52:18 +00:00
try:
from sphinx.setup_command import BuildDoc
except ImportError:
2009-07-22 23:52:18 +00:00
class BuildDoc(object):
pass
2008-02-03 01:04:26 +00:00
def windows_check():
2008-10-23 11:27:37 +00:00
return platform.system() in ('Windows', 'Microsoft')
2008-02-03 01:04:26 +00:00
2015-09-20 17:39:20 +00:00
def osx_check():
return platform.system() == 'Darwin'
2015-09-20 17:39:20 +00:00
2016-11-16 22:18:18 +00:00
desktop_data = 'deluge/ui/data/share/applications/deluge.desktop'
appdata_data = 'deluge/ui/data/share/appdata/deluge.appdata.xml'
# Variables for setuptools.setup
_package_data = {}
_exclude_package_data = {}
_entry_points = {'console_scripts': [], 'gui_scripts': [], 'deluge.ui': []}
_data_files = []
_version = get_version(prefix='deluge-', suffix='.dev0')
2014-09-25 20:05:57 +00:00
class PyTest(_test):
def initialize_options(self):
2014-09-25 20:05:57 +00:00
_test.initialize_options(self)
self.pytest_args = []
def finalize_options(self):
2014-09-25 20:05:57 +00:00
_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)
2016-11-27 17:04:12 +00:00
class CleanDocs(cmd.Command):
description = 'Clean the documentation build and module rst files'
2016-11-27 17:04:12 +00:00
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
docs_build = 'docs/build'
print('Deleting {}'.format(docs_build))
try:
rmtree(docs_build)
except OSError:
pass
for module in glob.glob('docs/source/modules/deluge*.rst'):
os.remove(module)
2016-11-27 17:04:12 +00:00
class BuildWebUI(cmd.Command):
description = 'Minify WebUI files'
2016-11-27 22:07:56 +00:00
user_options = []
2016-11-27 22:07:56 +00:00
JS_DIR = os.path.join('deluge', 'ui', 'web', 'js')
JS_SRC_DIRS = ('deluge-all', os.path.join('extjs', 'ext-extensions'))
def initialize_options(self):
2016-11-27 22:07:56 +00:00
pass
def finalize_options(self):
2016-11-27 22:07:56 +00:00
pass
def run(self):
2016-11-27 22:07:56 +00:00
js_basedir = os.path.join(os.path.dirname(__file__), self.JS_DIR)
try:
from minify_web_js import minify_js_dir
2016-11-27 22:07:56 +00:00
import_error = ''
except ImportError as err:
import_error = err
2016-11-27 22:07:56 +00:00
for js_src_dir in self.JS_SRC_DIRS:
source_dir = os.path.join(js_basedir, js_src_dir)
try:
minify_js_dir(source_dir)
except NameError:
js_file = source_dir + '.js'
2017-01-09 18:02:28 +00:00
if os.path.isfile(js_file):
print(
'Unable to minify but found existing minified: {}'.format(
js_file
)
)
2016-11-27 22:07:56 +00:00
else:
# Unable to minify and no existing minified file found so exiting.
print('Import error: %s' % import_error)
sys.exit(1)
# Create the gettext.js file for translations.
2017-06-27 14:11:19 +00:00
try:
from gen_web_gettext import create_gettext_js
except ImportError:
pass
else:
deluge_all_path = os.path.join(js_basedir, self.JS_SRC_DIRS[0])
print('Creating WebUI translation file: %s/gettext.js' % deluge_all_path)
create_gettext_js(deluge_all_path)
2016-11-27 22:07:56 +00:00
class CleanWebUI(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):
js_basedir = os.path.join(os.path.dirname(__file__), BuildWebUI.JS_DIR)
# Remove files generated by minify script.
2016-11-27 22:07:56 +00:00
for js_src_dir in BuildWebUI.JS_SRC_DIRS:
for file_type in ('.js', '-debug.js'):
js_file = os.path.join(js_basedir, js_src_dir + file_type)
print('Deleting {}'.format(js_file))
try:
os.remove(js_file)
except OSError:
pass
# Remove generated gettext.js
js_file = os.path.join(js_basedir, 'gettext.js')
print('Deleting {}'.format(js_file))
try:
os.remove(js_file)
except OSError:
pass
class BuildTranslations(cmd.Command):
2012-01-02 16:53:28 +00:00
description = 'Compile .po files into .mo files & create .desktop file'
2007-09-16 01:24:08 +00:00
2008-11-29 01:22:29 +00:00
user_options = [
('build-lib', None, 'lib build folder'),
('develop', 'D', 'Compile translations in develop mode (deluge/i18n)'),
2008-11-29 01:22:29 +00:00
]
boolean_options = ['develop']
2008-11-29 01:22:29 +00:00
2007-09-16 01:24:08 +00:00
def initialize_options(self):
2008-11-29 01:22:29 +00:00
self.build_lib = None
self.develop = False
2007-09-16 01:24:08 +00:00
def finalize_options(self):
2008-11-29 01:22:29 +00:00
self.set_undefined_options('build', ('build_lib', 'build_lib'))
2007-09-16 01:24:08 +00:00
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')
intltool_merge = 'intltool-merge'
if not windows_check() and find_executable(intltool_merge):
intltool_merge_opts = '--utf8 --quiet'
for data_file in (desktop_data, appdata_data):
# creates the translated file from .in file.
in_file = data_file + '.in'
if 'xml' in data_file:
intltool_merge_opts += ' --xml-style'
elif 'desktop' in data_file:
intltool_merge_opts += ' --desktop-style'
print('Creating file: %s' % data_file)
os.system(
'C_ALL=C '
+ '%s '
* 5
% (intltool_merge, intltool_merge_opts, po_dir, in_file, data_file)
)
print('Compiling po files from %s...' % po_dir)
2007-09-16 01:24:08 +00:00
for path, names, filenames in os.walk(po_dir):
for f in filenames:
upto_date = False
2007-09-16 01:24:08 +00:00
if f.endswith('.po'):
lang = f[: len(f) - 3]
2007-09-16 01:24:08 +00:00
src = os.path.join(path, f)
dest_path = os.path.join(basedir, lang, 'LC_MESSAGES')
2007-09-16 01:24:08 +00:00
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()
2007-09-16 01:24:08 +00:00
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()
2007-09-16 01:24:08 +00:00
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')
2007-09-16 01:24:08 +00:00
class CleanTranslations(cmd.Command):
description = 'Cleans translations files.'
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):
for path in (desktop_data, appdata_data):
if os.path.isfile(path):
print('Deleting %s' % path)
os.remove(path)
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 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':
2016-11-13 15:09:30 +00:00
print('Deleting egg file "%s"' % path)
os.remove(path)
# Delete the .egg-link
if path[-9:] == '.egg-link':
2016-11-13 15:09:30 +00:00
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 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:
2017-12-17 10:55:13 +00:00
from deluge._libtorrent import LT_VERSION
2017-12-17 10:55:13 +00:00
print('Info: Found libtorrent ({}) installed.'.format(LT_VERSION))
except ImportError as ex:
print('Warning: libtorrent (libtorrent-rasterbar) 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 Clean(_clean):
sub_commands = _clean.sub_commands + [
('clean_plugins', None),
('clean_trans', None),
('clean_webui', 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)
2016-11-16 22:18:18 +00:00
2007-09-16 01:24:08 +00:00
cmdclass = {
2014-09-20 17:55:21 +00:00
'build': Build,
'build_webui': BuildWebUI,
2014-09-20 17:55:21 +00:00
'build_trans': BuildTranslations,
'build_plugins': BuildPlugins,
'build_docs': BuildDoc,
'install_data': InstallData,
2014-09-20 17:55:21 +00:00
'clean_plugins': CleanPlugins,
'clean_trans': CleanTranslations,
2016-11-27 17:04:12 +00:00
'clean_docs': CleanDocs,
2016-11-27 22:07:56 +00:00
'clean_webui': CleanWebUI,
2014-09-20 17:55:21 +00:00
'clean': Clean,
'egg_info_plugins': EggInfoPlugins,
'test': PyTest,
2007-09-16 01:24:08 +00:00
}
2015-09-20 17:39:20 +00:00
if not windows_check() and not osx_check():
2016-12-01 19:41:58 +00:00
for icon_path in glob.glob('deluge/ui/data/icons/hicolor/*x*'):
size = os.path.basename(icon_path)
_data_files.append(
(
'share/icons/hicolor/{}/apps'.format(size),
['{}/apps/deluge.png'.format(icon_path)],
)
)
_data_files.extend(
[
(
'share/icons/hicolor/scalable/apps',
['deluge/ui/data/icons/hicolor/scalable/apps/deluge.svg'],
),
('share/pixmaps', ['deluge/ui/data/pixmaps/deluge.png']),
(
'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.isfile(desktop_data):
_data_files.append(('share/applications', [desktop_data]))
if os.path.isfile(appdata_data):
_data_files.append(('share/appdata', [appdata_data]))
_entry_points['console_scripts'] = [
2016-12-01 19:41:58 +00:00
'deluge-console = deluge.ui.console:start',
'deluge-web = deluge.ui.web:start',
'deluged = deluge.core.daemon_entry:start_daemon',
]
2010-10-31 09:18:09 +00:00
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',
]
)
_entry_points['gui_scripts'] = [
2016-12-01 19:41:58 +00:00
'deluge = deluge.ui.ui_entry:start_ui',
'deluge-gtk = deluge.ui.gtk3:start',
]
_entry_points['deluge.ui'] = [
2016-12-01 19:41:58 +00:00
'console = deluge.ui.console:Console',
'web = deluge.ui.web:Web',
'gtk = deluge.ui.gtk3:Gtk',
]
2010-10-31 09:18:09 +00:00
_package_data['deluge.ui'] = [
'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.gtk3'] = ['glade/*.ui']
setup_requires = ['setuptools', 'wheel']
install_requires = [
'twisted[tls]>=16.6',
# Add pyasn1 for setuptools workaround:
# https://github.com/pypa/setuptools/issues/1510
'pyasn1',
'pyopenssl',
'pyxdg',
'pillow',
'mako',
'chardet',
'six',
'setproctitle',
"pywin32; sys.platform == 'win32'",
"py2-ipaddress; sys.platform == 'win32'",
"certifi; sys.platform == 'win32'",
'zope.interface',
]
tests_require = ['pytest', 'pytest-twisted']
2007-07-04 08:24:30 +00:00
# Main setup
setup(
name='deluge',
version=_version,
fullname='Deluge BitTorrent Client',
description='BitTorrent Client',
2017-06-24 22:23:36 +00:00
author='Deluge Team',
maintainer='Calum Lind',
maintainer_email='calumlind+deluge@gmail.com',
keywords='torrent bittorrent p2p fileshare filesharing',
long_description=open('README.md').read(),
long_description_content_type='text/markdown',
url='https://deluge-torrent.org',
2017-06-24 22:23:36 +00:00
classifiers=[
'Development Status :: 4 - Beta',
2017-06-24 22:23:36 +00:00
'Environment :: Console',
'Environment :: Web Environment',
'Environment :: X11 Applications :: GTK',
'Framework :: Twisted',
'Intended Audience :: End Users/Desktop',
(
'License :: OSI Approved :: '
'GNU General Public License v3 or later (GPLv3+)'
),
'Programming Language :: Python',
2017-06-24 22:23:36 +00:00
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Topic :: Internet',
],
license='GPLv3+',
cmdclass=cmdclass,
setup_requires=setup_requires,
install_requires=install_requires,
tests_require=tests_require,
data_files=_data_files,
package_data=_package_data,
exclude_package_data=_exclude_package_data,
packages=find_packages(exclude=['deluge.plugins.*', 'deluge.tests']),
namespace_packages=['deluge', 'deluge.plugins'],
entry_points=_entry_points,
2008-07-10 04:40:13 +00:00
)