#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import with_statement from paver.easy import * from paver.setuputils import setup from paver.doctools import cog import glob import os import shutil import sys import re import subprocess import tempfile import urllib import zipfile PROJECT_DIR = path(__file__).dirname() sys.path.append(PROJECT_DIR) options = environment.options path("pyload").mkdir() extradeps = [] if sys.version_info <= (2, 5): extradeps += 'simplejson' setup( name="pyload", version="0.4.10", description='Fast, lightweight and full featured download manager.', long_description=open(PROJECT_DIR / "README.md").read(), keywords = ("pyload", "download-manager", "one-click-hoster", "download"), url="http://pyload.org", download_url='http://pyload.org/download', license='GPL v3', author="pyLoad Team", author_email="support@pyload.org", platforms = ('Any',), # package_dir={'pyload': "src"}, packages=["pyload"], # package_data=find_package_data(), # data_files=[], include_package_data=True, exclude_package_data={'pyload': ["docs*", "scripts*", "tests*"]}, #: exluced from build but not from sdist # 'bottle >= 0.10.0' not in list, because its small and contain little modifications install_requires=['thrift >= 0.8.0', 'jinja2', 'pycurl', 'Beaker', 'BeautifulSoup >= 3.2, < 3.3'] + extradeps, extras_require={ 'SSL': ["pyOpenSSL"], 'DLC': ['pycrypto'], 'lightweight webserver': ['bjoern'], }, # setup_requires=["setuptools_hg"], entry_points={'console_scripts': ['pyLoadCore = pyLoadCore:main']}, zip_safe=False, classifiers=[ "Development Status :: 5 - Production/Stable", "Topic :: Internet :: WWW/HTTP", "Environment :: Console", "Environment :: Web Environment", "Intended Audience :: End Users/Desktop", "License :: OSI Approved :: GNU General Public License (GPL)", "Operating System :: OS Independent", "Programming Language :: Python :: 2" ] ) options( sphinx=Bunch( builddir="_build", sourcedir="" ), get_source=Bunch( src="https://bitbucket.org/spoob/pyload/get/tip.zip", rev=None, clean=False ), thrift=Bunch( path="../thrift/trunk/compiler/cpp/thrift", gen="" ), virtualenv=Bunch( dir="env", python="python2", virtual="virtualenv2", ), cog=Bunch( pattern="*.py", ) ) # xgettext args xargs = ["--language=Python", "--add-comments=L10N", "--from-code=utf-8", "--copyright-holder=pyLoad Team", "--package-name=pyLoad", "--package-version=%s" % options.version, "--msgid-bugs-address='bugs@pyload.org'"] @task @needs('cog') def html(): """Build html documentation""" module = path("docs") / "pyload" pyload.rmtree() subprocess.call_task('paver.doctools.html') @task @cmdopts([ ('src=', 's', 'Url to source'), ('rev=', 'r', "HG revision"), ("clean", 'c', 'Delete old source folder') ]) def get_source(options): """ Downloads pyload source from bitbucket tip or given rev""" if options.rev: options.url = "https://bitbucket.org/spoob/pyload/get/%s.zip" % options.rev pyload = path("pyload") if len(pyload.listdir()) and not options.clean: return elif pyload.exists(): pyload.rmtree() urllib.urlretrieve(options.src, "pyload_src.zip") zip = zipfile.ZipFile("pyload_src.zip") zip.extractall() path("pyload_src.zip").remove() folder = [x for x in path(".").dirs() if x.name.startswith("spoob-pyload-")][0] folder.shutil.move(pyload) change_mode(pyload, 0644) change_mode(pyload, 0755, folder=True) for file in pyload.files(): if file.name.endswith(".py"): file.chmod(0755) (pyload / ".hgtags").remove() (pyload / ".gitignore").remove() #(pyload / "docs").rmtree() f = open(pyload / "__init__.py", "wb") f.close() # options.setup.packages = find_packages() # options.setup.package_data = find_package_data() @task @needs('clean', 'generate_setup', 'minilib', 'get_source', 'setuptools.command.sdist') def sdist(): """ Build source code package with distutils """ @task @cmdopts([ ('path=', 'p', 'Thrift path'), ('gen=', 'g', "Extra --gen option") ]) def thrift(options): """ Generate Thrift stubs """ print "add import for TApplicationException manually as long it is not fixed" outdir = path("pyload") / "remote" / "thriftbackend" (outdir / "gen-py").rmtree() cmd = [options.thrift.path, "-strict", "-o", outdir, "--gen", "py:slots, dynamic", outdir / "pyload.thrift"] if options.gen: cmd.insert(len(cmd) - 1, "--gen") cmd.insert(len(cmd) - 1, options.gen) print "running", cmd p = subprocess.Popen(cmd) p.communicate() (outdir / "thriftgen").rmtree() (outdir / "gen-py").shutil.move(outdir / "thriftgen") # create light ttypes from pyload.remote.socketbackend.create_ttypes import main main() @task def compile_js(): """ Compile .coffee files to javascript""" root = path("pyload") / "web" / "media" / "js" for f in root.glob("*.coffee"): print "generate", f coffee = subprocess.Popen(["coffee", "-cbs"], stdin=open(f, "rb"), stdout=PIPE) yui = subprocess.Popen(["yuicompressor", "--type", "js"], stdin=coffee.stdout, stdout=PIPE) coffee.stdout.close() content = yui.communicate()[0] with open(root / f.name.replace(".coffee", ".js"), "wb") as js: js.write("{% autoescape true %}\n") js.write(content) js.write("\n{% endautoescape %}") @task def generate_locale(): """ Generates localization files """ EXCLUDE = ["BeautifulSoup.py", "web/locale", "web/ajax", "web/cnl", "web/pyload", "setup.py"] makepot("core", path("pyload"), EXCLUDE, "./pyload.py\n") makepot("setup", "", [], includes="./pyload/setup.py\n") EXCLUDE = ["ServerThread.py", "web/media/default"] # strings from js files strings = set() for fi in path("pyload/web").walkfiles(): if not fi.name.endswith(".js") and not fi.endswith(".coffee"): continue with open(fi, "rb") as c: content = c.read() strings.update(re.findall(r"_\s*\(\s*\"([^\"]+)", content)) strings.update(re.findall(r"_\s*\(\s*\'([^\']+)", content)) trans = path("pyload") / "web" / "translations.js" with open(trans, "wb") as js: for s in strings: js.write('_("%s")\n' % s) makepot("django", path("pyload/web"), EXCLUDE, "./%s\n" % trans.relpath(), [".py", ".html"], ["--language=Python"]) trans.remove() path("includes.txt").remove() print "Locale generated" @task @cmdopts([ ('key=', 'k', 'api key') ]) def upload_translations(options): """ Uploads the locale files to translation server """ tmp = path(tempfile.mkdtemp()) shutil.shutil.copy('locale/crowdin.yaml', tmp) os.mkdir(tmp / 'pyLoad') for f in glob.glob('locale/*.pot'): if os.path.isfile(f): shutil.shutil.copy(f, tmp / 'pyLoad') config = tmp / 'crowdin.yaml' with open(config, 'rb') as f: content = f.read() content = content.format(key=options.key, tmp=tmp) with open(config, 'wb') as f: f.write(content) subprocess.call(['crowdin-cli', '-c', config, 'upload', 'source']) shutil.rmtree(tmp) print "Translations uploaded" @task @cmdopts([ ('key=', 'k', 'api key') ]) def download_translations(options): """ Downloads the translated files from translation server """ tmp = path(tempfile.mkdtemp()) shutil.shutil.copy('locale/crowdin.yaml', tmp) os.mkdir(tmp / 'pyLoad') for f in glob.glob('locale/*.pot'): if os.path.isfile(f): shutil.shutil.copy(f, tmp / 'pyLoad') config = tmp / 'crowdin.yaml' with open(config, 'rb') as f: content = f.read() content = content.format(key=options.key, tmp=tmp) with open(config, 'wb') as f: f.write(content) subprocess.call(['crowdin-cli', '-c', config, 'download']) for language in (tmp / 'pyLoad').listdir(): if not language.isdir(): continue target = path('locale') / language.basename() print "Copy language %s" % target if target.exists(): shutil.rmtree(target) shutil.copytree(language, target) shutil.rmtree(tmp) @task def compile_translations(): """ Compile PO files to MO """ for language in path('locale').listdir(): if not language.isdir(): continue for f in glob.glob(language / 'LC_MESSAGES' / '*.po'): print "Compiling %s" % f subprocess.call(['msgfmt', '-o', f.replace('.po', '.mo'), f]) @task def tests(): subprocess.call(["nosetests2"]) @task def virtualenv(options): """Setup virtual environment""" if path(options.dir).exists(): return subprocess.call([options.virtual, "--no-site-packages", "--python", options.python, options.dir]) print "$ source %s/bin/activate" % options.dir @task def clean_env(): """Deletes the virtual environment""" env = path(options.virtualenv.dir) if env.exists(): env.rmtree() @task @needs('generate_setup', 'minilib', 'get_source', 'virtualenv') def env_install(): """Install pyLoad into the virtualenv""" venv = options.virtualenv subprocess.call([path(venv.dir) / "bin" / "easy_install", "."]) @task def clean(): """Cleans build directories""" path("build").rmtree() path("dist").rmtree() # helper functions def walk_trans(path, EXCLUDE, endings=[".py"]): result = "" for f in path.walkfiles(): if [True for x in EXCLUDE if x in f.dirname().relpath()]: continue if f.name in EXCLUDE: continue for e in endings: if f.name.endswith(e): result += "./%s\n" % f.relpath() break return result def makepot(domain, p, excludes=[], includes="", endings=[".py"], xxargs=[]): print "Generate %s.pot" % domain with open("includes.txt", "wb") as f: if includes: f.write(includes) if p: f.write(walk_trans(path(p), excludes, endings)) subprocess.call(["xgettext", "--files-from=includes.txt", "--default-domain=%s" % domain] + xargs + xxargs) # replace charset und move file with open("%s.po" % domain, "rb") as f: content = f.read() path("%s.po" % domain).remove() content = content.replace("charset=CHARSET", "charset=UTF-8") with open("locale/%s.pot" % domain, "wb") as f: f.write(content) def change_owner(dir, uid, gid): for p in dir.walk(): p.chown(uid, gid) def change_mode(dir, mode, folder=False): for p in dir.walk(): if folder and p.isdir(): p.chmod(mode) elif p.isfile() and not folder: p.chmod(mode)