2014-10-22 00:06:27 +03:00
|
|
|
import click
|
2013-11-08 20:20:40 +02:00
|
|
|
import re
|
|
|
|
import os
|
|
|
|
import hashlib
|
|
|
|
import json
|
2014-09-14 06:47:17 +03:00
|
|
|
import string
|
|
|
|
import random
|
2014-10-17 20:03:38 +03:00
|
|
|
import sys
|
2014-10-17 00:54:45 +03:00
|
|
|
from jinja2 import Template
|
2013-11-08 20:20:40 +02:00
|
|
|
|
|
|
|
|
2014-01-14 01:07:13 +02:00
|
|
|
class AttrDict(dict):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(AttrDict, self).__init__(*args, **kwargs)
|
|
|
|
self.__dict__ = self
|
|
|
|
|
|
|
|
|
2014-09-14 06:47:17 +03:00
|
|
|
def random_string(size=6, chars=string.ascii_lowercase + string.ascii_uppercase + string.digits):
|
|
|
|
return ''.join(random.choice(chars) for _ in range(size))
|
|
|
|
|
|
|
|
|
2014-01-14 01:07:13 +02:00
|
|
|
def to_json(data):
|
|
|
|
return json.dumps(to_dict(data), separators=(',', ':'))
|
|
|
|
|
|
|
|
|
|
|
|
def to_dict(data):
|
|
|
|
|
|
|
|
if not data:
|
|
|
|
return AttrDict()
|
|
|
|
|
|
|
|
def row2dict(row):
|
|
|
|
d = AttrDict()
|
|
|
|
for column in row.__table__.columns:
|
|
|
|
d[column.name] = getattr(row, column.name)
|
|
|
|
|
|
|
|
return d
|
|
|
|
|
|
|
|
if isinstance(data, list):
|
|
|
|
return [row2dict(x) for x in data]
|
|
|
|
else:
|
|
|
|
return row2dict(data)
|
|
|
|
|
|
|
|
|
2013-11-08 20:20:40 +02:00
|
|
|
def mkdir_safe(path):
|
|
|
|
if path and not(os.path.exists(path)):
|
|
|
|
os.makedirs(path)
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
def extract_path(file_path):
|
|
|
|
if not file_path:
|
|
|
|
return None
|
|
|
|
last_slash = file_path.rindex("/")
|
|
|
|
if last_slash:
|
|
|
|
return file_path[0, last_slash]
|
|
|
|
|
|
|
|
|
|
|
|
def clean_path(path):
|
|
|
|
if path:
|
|
|
|
if path[0] != '/':
|
|
|
|
path.insert(0, '/')
|
|
|
|
return re.sub(r"//+", '/', path)
|
|
|
|
|
|
|
|
|
|
|
|
def extract_name(file_path):
|
|
|
|
if file_path[-1] == "/":
|
|
|
|
return None
|
|
|
|
return os.path.basename(file_path)
|
|
|
|
|
|
|
|
|
|
|
|
def remove_ext(path):
|
|
|
|
return os.path.splitext(path)[0]
|
|
|
|
|
|
|
|
|
|
|
|
def clean_url(url):
|
|
|
|
if not url:
|
|
|
|
return url
|
|
|
|
|
|
|
|
url = url.replace('%2F', '/')
|
|
|
|
url = re.sub(r"^/+", "", url)
|
|
|
|
return re.sub(r"//+", '/', url)
|
|
|
|
|
|
|
|
|
|
|
|
def to_canonical(s):
|
|
|
|
"""
|
|
|
|
Double space -> single dash
|
|
|
|
Double dash -> single dash
|
|
|
|
Remove all non alphanumeric and dash
|
|
|
|
Limit to first 64 chars
|
|
|
|
"""
|
|
|
|
s = s.encode('ascii', 'ignore')
|
|
|
|
s = str(s)
|
|
|
|
s = re.sub(r"\s\s*", "-", s)
|
|
|
|
s = re.sub(r"\-\-+", "-", s)
|
|
|
|
s = re.sub(r"[^a-zA-Z0-9\-]", "", s)
|
|
|
|
s = s[:64]
|
|
|
|
return s
|
|
|
|
|
2014-11-17 19:25:26 +02:00
|
|
|
|
2014-11-13 01:06:56 +02:00
|
|
|
def cname_to_filename(cname):
|
|
|
|
""" Convert canonical name to filename
|
|
|
|
|
|
|
|
:param cname: Canonical name
|
|
|
|
:return: str -- Filename
|
|
|
|
|
|
|
|
"""
|
|
|
|
return cname + ".md"
|
|
|
|
|
|
|
|
|
|
|
|
def filename_to_cname(filename):
|
|
|
|
"""Convert filename to canonical name.
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
It's assumed filename is already canonical format
|
|
|
|
|
|
|
|
"""
|
|
|
|
return os.path.splitext(filename)[0]
|
2013-11-08 20:20:40 +02:00
|
|
|
|
2014-11-17 19:25:26 +02:00
|
|
|
|
2013-11-08 20:20:40 +02:00
|
|
|
def gravatar_url(email):
|
2014-08-20 18:28:25 +03:00
|
|
|
return "//www.gravatar.com/avatar/" + hashlib.md5(email).hexdigest()
|
2014-10-17 00:54:45 +03:00
|
|
|
|
2014-10-17 20:03:38 +03:00
|
|
|
|
|
|
|
def in_virtualenv():
|
|
|
|
return hasattr(sys, 'real_prefix')
|
|
|
|
|
|
|
|
|
|
|
|
def is_su():
|
|
|
|
return os.geteuid() == 0
|
|
|
|
|
|
|
|
|
2014-10-22 00:06:27 +03:00
|
|
|
def green(s):
|
|
|
|
click.secho(s, fg='green')
|
|
|
|
|
|
|
|
|
|
|
|
def yellow(s):
|
|
|
|
click.secho(s, fg='yellow')
|
|
|
|
|
|
|
|
|
|
|
|
def red(s):
|
|
|
|
click.secho(s, fg='red')
|
|
|
|
|
|
|
|
|
2014-10-17 00:54:45 +03:00
|
|
|
def upstart_script(user='root', app_dir=None, port=5000, workers=2, path=None):
|
|
|
|
script = """
|
|
|
|
limit nofile 65335 65335
|
|
|
|
|
|
|
|
respawn
|
|
|
|
|
|
|
|
description "Realms Wiki"
|
|
|
|
author "scragg@gmail.com"
|
|
|
|
|
|
|
|
chdir {{ app_dir }}
|
|
|
|
|
|
|
|
{% if path %}
|
|
|
|
env PATH={{ path }}:/usr/local/bin:/usr/bin:/bin:$PATH
|
|
|
|
export PATH
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
env LC_ALL=en_US.UTF-8
|
|
|
|
env GEVENT_RESOLVER=ares
|
|
|
|
|
|
|
|
export LC_ALL
|
|
|
|
export GEVENT_RESOLVER
|
|
|
|
|
|
|
|
setuid {{ user }}
|
|
|
|
setgid {{ user }}
|
|
|
|
|
|
|
|
start on runlevel [2345]
|
|
|
|
stop on runlevel [!2345]
|
|
|
|
|
|
|
|
respawn
|
|
|
|
|
|
|
|
exec gunicorn \
|
|
|
|
--name realms-wiki \
|
|
|
|
--access-logfile - \
|
|
|
|
--error-logfile - \
|
|
|
|
--worker-class gevent \
|
|
|
|
--workers {{ workers }} \
|
|
|
|
--bind 0.0.0.0:{{ port }} \
|
|
|
|
--user {{ user }} \
|
|
|
|
--group {{ user }} \
|
|
|
|
--chdir {{ app_dir }} \
|
2014-10-23 00:45:37 +03:00
|
|
|
'realms:create_app()'
|
2014-10-17 00:54:45 +03:00
|
|
|
|
|
|
|
"""
|
|
|
|
template = Template(script)
|
|
|
|
return template.render(user=user, app_dir=app_dir, port=port, workers=workers, path=path)
|