# -*- coding: utf-8 -*-
from paver.easy import *
from paver.setuputils import setup
from paver.doctools import cog
import os
import sys
import shutil
import re
from glob import glob
from tempfile import mkdtemp
from urllib import urlretrieve
from subprocess import call, Popen, PIPE
from zipfile 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'],
'RSS plugins': ['feedparser'],
},
#setup_requires=["setuptools_hg"],
entry_points={
'console_scripts': [
'pyLoadCore = pyLoadCore:main',
'pyLoadCli = pyLoadCli: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()
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()
urlretrieve(options.src, "pyload_src.zip")
zip = 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.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 = Popen(cmd)
p.communicate()
(outdir / "thriftgen").rmtree()
(outdir / "gen-py").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 = Popen(["coffee", "-cbs"], stdin=open(f, "rb"), stdout=PIPE)
yui = 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", "pyload/cli", "web/locale", "web/ajax", "web/cnl", "web/pyload",
"setup.py"]
makepot("core", path("pyload"), EXCLUDE, "./pyload.py\n")
makepot("cli", path("pyload") / "cli", [], includes="./pyload-cli.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(mkdtemp())
shutil.copy('locale/crowdin.yaml', tmp)
os.mkdir(tmp / 'pyLoad')
for f in glob('locale/*.pot'):
if os.path.isfile(f):
shutil.copy(f, tmp / 'pyLoad')
config = tmp / 'crowdin.yaml'
content = open(config, 'rb').read()
content = content.format(key=options.key, tmp=tmp)
f = open(config, 'wb')
f.write(content)
f.close()
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(mkdtemp())
shutil.copy('locale/crowdin.yaml', tmp)
os.mkdir(tmp / 'pyLoad')
for f in glob('locale/*.pot'):
if os.path.isfile(f):
shutil.copy(f, tmp / 'pyLoad')
config = tmp / 'crowdin.yaml'
content = open(config, 'rb').read()
content = content.format(key=options.key, tmp=tmp)
f = open(config, 'wb')
f.write(content)
f.close()
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(language / 'LC_MESSAGES' / '*.po'):
print "Compiling %s" % f
call(['msgfmt', '-o', f.replace('.po', '.mo'), f])
@task
def tests():
call(["nosetests2"])
@task
def virtualenv(options):
"""Setup virtual environment"""
if path(options.dir).exists():
return
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
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
f = open("includes.txt", "wb")
if includes:
f.write(includes)
if p:
f.write(walk_trans(path(p), excludes, endings))
f.close()
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)