355 lines
8.8 KiB
Python
355 lines
8.8 KiB
Python
from realms import config, create_app, db, cli as cli_, __version__
|
|
from realms.lib.util import is_su, random_string, in_virtualenv, green, yellow, red
|
|
from subprocess import call, Popen
|
|
from multiprocessing import cpu_count
|
|
import click
|
|
import json
|
|
import sys
|
|
import os
|
|
import pip
|
|
|
|
|
|
def print_version(ctx, param, value):
|
|
if not value or ctx.resilient_parsing:
|
|
return
|
|
green(__version__)
|
|
ctx.exit()
|
|
|
|
|
|
@click.group()
|
|
@click.option('--version', is_flag=True, callback=print_version,
|
|
expose_value=False, is_eager=True)
|
|
@click.pass_context
|
|
def cli(ctx):
|
|
# This could probably done better
|
|
if ctx.invoked_subcommand in ['setup', 'pip']:
|
|
if not in_virtualenv() and not is_su():
|
|
# This does not account for people the have user level python installs
|
|
# that aren't virtual environments! Should be rare I think.
|
|
red("This command requires root privileges, use sudo or run as root.")
|
|
sys.exit()
|
|
|
|
cli.add_command(cli_)
|
|
|
|
|
|
def get_user():
|
|
for name in ('SUDO_USER', 'LOGNAME', 'USER', 'LNAME', 'USERNAME'):
|
|
user = os.environ.get(name)
|
|
if user:
|
|
return user
|
|
|
|
|
|
def get_pid():
|
|
try:
|
|
with file(config.PIDFILE) as f:
|
|
pid = f.read().strip()
|
|
return pid if pid and int(pid) > 0 and not call(['kill', '-s', '0', pid]) else False
|
|
except IOError:
|
|
return False
|
|
|
|
|
|
def module_exists(module_name):
|
|
try:
|
|
__import__(module_name)
|
|
except ImportError:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
|
|
@cli.command()
|
|
@click.option('--site-title',
|
|
default=config.SITE_TITLE,
|
|
prompt='Enter site title.')
|
|
@click.option('--base_url',
|
|
default=config.BASE_URL,
|
|
prompt='Enter base URL.')
|
|
@click.option('--port',
|
|
default=config.PORT,
|
|
prompt='Enter port number.')
|
|
@click.option('--secret-key',
|
|
default=config.SECRET_KEY if config.SECRET_KEY != "CHANGE_ME" else random_string(64),
|
|
prompt='Enter secret key.')
|
|
@click.option('--wiki-path',
|
|
default=config.WIKI_PATH,
|
|
prompt='Enter wiki data directory.',
|
|
help='Wiki Directory (git repo)')
|
|
@click.option('--allow-anon',
|
|
default=config.ALLOW_ANON,
|
|
is_flag=True,
|
|
prompt='Allow anonymous edits?')
|
|
@click.option('--registration-enabled',
|
|
default=config.REGISTRATION_ENABLED,
|
|
is_flag=True,
|
|
prompt='Enable registration?')
|
|
@click.option('--cache-type',
|
|
default=config.CACHE_TYPE,
|
|
type=click.Choice([None, 'simple', 'redis', 'memcached']),
|
|
prompt='Cache type?')
|
|
@click.option('--db-uri',
|
|
default=config.DB_URI,
|
|
prompt='Database URI? Examples: http://goo.gl/RyW0cl')
|
|
@click.pass_context
|
|
def setup(ctx, **kw):
|
|
""" Start setup wizard
|
|
"""
|
|
|
|
conf = {}
|
|
|
|
for k, v in kw.items():
|
|
conf[k.upper()] = v
|
|
|
|
conf_path = config.update(conf)
|
|
|
|
if conf['CACHE_TYPE'] == 'redis':
|
|
ctx.invoke(setup_redis)
|
|
elif conf['CACHE_TYPE'] == 'memcached':
|
|
ctx.invoke(setup_memcached)
|
|
|
|
green('Config saved to %s' % conf_path)
|
|
|
|
if not conf_path.startswith('/etc/realms-wiki'):
|
|
yellow('Note: You can move file to /etc/realms-wiki/realms-wiki.conf')
|
|
click.echo()
|
|
|
|
yellow('Type "realms-wiki start" to start server')
|
|
yellow('Type "realms-wiki dev" to start server in development mode')
|
|
yellow('Full usage: realms-wiki --help')
|
|
|
|
@click.command()
|
|
@click.option('--cache-redis-host',
|
|
default=getattr(config, 'CACHE_REDIS_HOST', "127.0.0.1"),
|
|
prompt='Redis host')
|
|
@click.option('--cache-redis-port',
|
|
default=getattr(config, 'CACHE_REDIS_POST', 6379),
|
|
prompt='Redis port')
|
|
@click.option('--cache-redis-password',
|
|
default=getattr(config, 'CACHE_REDIS_PASSWORD', None),
|
|
prompt='Redis password')
|
|
@click.option('--cache-redis-db',
|
|
default=getattr(config, 'CACHE_REDIS_DB', 0),
|
|
prompt='Redis db')
|
|
def setup_redis(**kw):
|
|
conf = {}
|
|
|
|
for k, v in kw.items():
|
|
conf[k.upper()] = v
|
|
|
|
config.update(conf)
|
|
install_redis()
|
|
|
|
|
|
def get_prefix():
|
|
return sys.prefix
|
|
|
|
|
|
@cli.command(name='pip')
|
|
@click.argument('cmd', nargs=-1)
|
|
def pip_(cmd):
|
|
""" Execute pip commands, useful for virtualenvs
|
|
"""
|
|
pip.main(cmd)
|
|
|
|
|
|
def install_redis():
|
|
pip.main(['install', 'redis'])
|
|
|
|
|
|
def install_mysql():
|
|
pip.main(['install', 'MySQL-Python'])
|
|
|
|
|
|
def install_postgres():
|
|
pip.main(['install', 'psycopg2'])
|
|
|
|
|
|
def install_memcached():
|
|
pip.main(['install', 'python-memcached'])
|
|
|
|
|
|
@click.command()
|
|
@click.option('--cache-memcached-servers',
|
|
default=getattr(config, 'CACHE_MEMCACHED_SERVERS', ["127.0.0.1:11211"]),
|
|
type=click.STRING,
|
|
prompt='Memcached servers, separate with a space')
|
|
def setup_memcached(**kw):
|
|
conf = {}
|
|
|
|
for k, v in kw.items():
|
|
conf[k.upper()] = v
|
|
|
|
config.update(conf)
|
|
|
|
|
|
@cli.command()
|
|
@click.option('--user',
|
|
default=get_user(),
|
|
type=click.STRING,
|
|
prompt='Run as which user? (it must exist)')
|
|
@click.option('--port',
|
|
default=config.PORT,
|
|
type=click.INT,
|
|
prompt='What port to listen on?')
|
|
@click.option('--workers',
|
|
default=cpu_count() * 2 + 1,
|
|
type=click.INT,
|
|
prompt="Number of workers? (defaults to ncpu*2+1)")
|
|
def setup_upstart(**kwargs):
|
|
""" Start upstart conf creation wizard
|
|
"""
|
|
from realms.lib.util import upstart_script
|
|
|
|
if in_virtualenv():
|
|
app_dir = get_prefix()
|
|
path = '/'.join(sys.executable.split('/')[:-1])
|
|
else:
|
|
# Assumed root install, not sure if this matters?
|
|
app_dir = '/'
|
|
path = None
|
|
|
|
kwargs.update(dict(app_dir=app_dir, path=path))
|
|
|
|
conf_file = '/etc/init/realms-wiki.conf'
|
|
script = upstart_script(**kwargs)
|
|
|
|
try:
|
|
with open(conf_file, 'w') as f:
|
|
f.write(script)
|
|
green('Wrote file to %s' % conf_file)
|
|
except IOError:
|
|
with open('/tmp/realms-wiki.conf', 'w') as f:
|
|
f.write(script)
|
|
yellow("Wrote file to /tmp/realms-wiki.conf, to install type:")
|
|
yellow("sudo mv /tmp/realms-wiki.conf /etc/init/realms-wiki.conf")
|
|
|
|
click.echo()
|
|
click.echo("Upstart usage:")
|
|
green("sudo start realms-wiki")
|
|
green("sudo stop realms-wiki")
|
|
green("sudo restart realms-wiki")
|
|
green("sudo status realms-wiki")
|
|
|
|
|
|
@cli.command()
|
|
@click.argument('json_string')
|
|
def configure(json_string):
|
|
""" Set config.json, expects JSON encoded string
|
|
"""
|
|
try:
|
|
config.update(json.loads(json_string))
|
|
except ValueError, e:
|
|
red('Config value should be valid JSON')
|
|
|
|
|
|
@cli.command()
|
|
@click.option('--port', default=5000)
|
|
def dev(port):
|
|
""" Run development server
|
|
"""
|
|
green("Starting development server")
|
|
create_app().run(host="0.0.0.0",
|
|
port=port,
|
|
debug=True)
|
|
|
|
|
|
def start_server():
|
|
if get_pid():
|
|
yellow("Server is already running")
|
|
return
|
|
|
|
flags = '--daemon --pid %s' % config.PIDFILE
|
|
|
|
green("Server started. Port: %s" % config.PORT)
|
|
|
|
Popen("gunicorn 'realms:create_app()' -b 0.0.0.0:%s -k gevent %s" %
|
|
(config.PORT, flags), shell=True, executable='/bin/bash')
|
|
|
|
|
|
def stop_server():
|
|
pid = get_pid()
|
|
if not pid:
|
|
yellow("Server is not running")
|
|
else:
|
|
yellow("Shutting down server")
|
|
call(['kill', pid])
|
|
|
|
|
|
@cli.command()
|
|
def run():
|
|
""" Run production server (alias for start)
|
|
"""
|
|
start_server()
|
|
|
|
|
|
@cli.command()
|
|
def start():
|
|
""" Run server daemon
|
|
"""
|
|
start_server()
|
|
|
|
|
|
@cli.command()
|
|
def stop():
|
|
""" Stop server
|
|
"""
|
|
stop_server()
|
|
|
|
|
|
@cli.command()
|
|
def restart():
|
|
""" Restart server
|
|
"""
|
|
stop_server()
|
|
start_server()
|
|
|
|
|
|
@cli.command()
|
|
def status():
|
|
""" Get server status
|
|
"""
|
|
pid = get_pid()
|
|
if not pid:
|
|
yellow("Server is not running")
|
|
else:
|
|
green("Server is running PID: %s" % pid)
|
|
|
|
|
|
@cli.command()
|
|
def create_db():
|
|
""" Creates DB tables
|
|
"""
|
|
green("Creating all tables")
|
|
db.create_all()
|
|
|
|
|
|
@cli.command()
|
|
@click.confirmation_option(help='Are you sure you want to drop the db?')
|
|
def drop_db():
|
|
""" Drops DB tables
|
|
"""
|
|
yellow("Dropping all tables")
|
|
db.drop_all()
|
|
|
|
|
|
@cli.command()
|
|
def test():
|
|
""" Run tests
|
|
"""
|
|
for mod in [('flask.ext.testing', 'Flask-Testing'), ('nose', 'nose'), ('blinker', 'blinker')]:
|
|
if not module_exists(mod[0]):
|
|
pip.main(['install', mod[1]])
|
|
|
|
nosetests = get_prefix() + "/bin/nosetests" if in_virtualenv() else "nosetests"
|
|
|
|
call([nosetests, 'realms'])
|
|
|
|
|
|
@cli.command()
|
|
def version():
|
|
""" Output version
|
|
"""
|
|
green(__version__)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
cli() |