mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
wip: command line tool
deploy command evolution: in addition to the project creation, the command configures database connections and run associated django commands. see #314
This commit is contained in:
@@ -1,9 +1,26 @@
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import getpass
|
||||
import subprocess
|
||||
from django.core import management
|
||||
from django.template import Context, Template
|
||||
from modoboa.core.management import Command
|
||||
|
||||
dbconn_tpl = """
|
||||
'{{ conn_name }}': {
|
||||
'ENGINE': 'django.db.backends.{{ dbtype }}', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
|
||||
'NAME': '{{ dbname }}', # Or path to database file if using sqlite3.
|
||||
'USER': '{{ username }}', # Not used with sqlite3.
|
||||
'PASSWORD': '{{ password }}', # Not used with sqlite3.
|
||||
'HOST': '{{ dbhost }}', # Set to empty string for localhost. Not used with sqlite3.
|
||||
'PORT': '', # Set to empty string for default. Not used with sqlite3.{% if dbtype == 'mysql' %}
|
||||
'OPTIONS' : {
|
||||
"init_command" : 'SET foreign_key_checks = 0;',
|
||||
},{% endif %}
|
||||
},
|
||||
"""
|
||||
|
||||
class DeployCommand(Command):
|
||||
help = "Create a fresh django project (calling startproject) and apply Modoboa specific settings."
|
||||
|
||||
@@ -11,23 +28,88 @@ class DeployCommand(Command):
|
||||
super(DeployCommand, self).__init__(*args, **kwargs)
|
||||
self._parser.add_argument('name', type=str,
|
||||
help='The name of your Modoboa instance')
|
||||
self._parser.add_argument('--with-amavis', action='store_true', default=False,
|
||||
help='Include amavis configuration')
|
||||
self._parser.add_argument('--run-syncdb', action='store_true', default=False,
|
||||
help='Run django syncdb command')
|
||||
self._parser.add_argument('--run-collectstatic', action='store_true', default=False,
|
||||
help='Run django collectstatic command')
|
||||
|
||||
def _exec_django_command(self, name, cwd, *args):
|
||||
"""Run a django command for the freshly created project
|
||||
|
||||
:param name: the command name
|
||||
:param cwd: the directory where the command must be executed
|
||||
"""
|
||||
cmd = 'python manage.py %s %s' % (name, " ".join(args))
|
||||
if not self._verbose:
|
||||
p = subprocess.Popen(cmd,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
shell=True, cwd=cwd)
|
||||
output = p.communicate()
|
||||
else:
|
||||
p = subprocess.Popen(cmd, shell=True, cwd=cwd)
|
||||
p.wait()
|
||||
output = None
|
||||
if p.returncode:
|
||||
if output:
|
||||
print >>sys.stderr, "\n".join(filter(lambda l: l != None, output))
|
||||
print >>sys.stderr, "%s failed, check your configuration" % cmd
|
||||
|
||||
def ask_db_info(self, name='default'):
|
||||
"""Prompt the user for database information
|
||||
|
||||
Gather all information required to create a new database
|
||||
connection (into settings.py).
|
||||
|
||||
:param name: the connection name
|
||||
"""
|
||||
print "Configuring database connection: %s" % name
|
||||
info = {'conn_name' : name}
|
||||
info['dbtype'] = raw_input('Database type (mysql or postgres): ')
|
||||
if info['dbtype'] not in ['mysql', 'postgres']:
|
||||
info['dbtype'] = 'mysql'
|
||||
if info['dbtype'] == 'postgres':
|
||||
info['dbtype'] = 'postgresql_psycopg2'
|
||||
info['dbhost'] = raw_input('Database host (default: localhost): ')
|
||||
if info['dbhost'] == '':
|
||||
info['dbhost'] = 'localhost'
|
||||
info['dbname'] = raw_input('Database name: ')
|
||||
info['username'] = raw_input('Username: ')
|
||||
info['password'] = getpass.getpass('Password: ')
|
||||
return info
|
||||
|
||||
def handle(self, parsed_args):
|
||||
management.call_command('startproject', parsed_args.name, verbosity=False)
|
||||
if os.path.exists("%(name)s/%(name)s" % {'name' : parsed_args.name}):
|
||||
# Django 1.4+
|
||||
path = "%(name)s/%(name)s" % {'name' : parsed_args.name}
|
||||
sys.path.append(parsed_args.name)
|
||||
django14 = True
|
||||
else:
|
||||
path = parsed_args.name
|
||||
sys.path.append(".")
|
||||
django14 = False
|
||||
|
||||
t = Template(dbconn_tpl)
|
||||
default_conn = t.render(Context(self.ask_db_info()))
|
||||
amavis_conn = t.render(Context(self.ask_db_info('amavis'))) if parsed_args.with_amavis \
|
||||
else None
|
||||
|
||||
mod = __import__(parsed_args.name, globals(), locals(), ['settings'])
|
||||
tpl = self._render_template("%s/settings.py" % self._templates_dir, {
|
||||
'secret_key' : mod.settings.SECRET_KEY,
|
||||
'name' : parsed_args.name
|
||||
})
|
||||
'default_conn' : default_conn, 'amavis_conn' : amavis_conn,
|
||||
'secret_key' : mod.settings.SECRET_KEY,
|
||||
'name' : parsed_args.name, 'django14' : django14
|
||||
})
|
||||
fp = open("%s/settings.py" % path, "w")
|
||||
fp.write(tpl)
|
||||
fp.close()
|
||||
shutil.copyfile("%s/urls.py" % self._templates_dir, "%s/urls.py" % path)
|
||||
os.mkdir("%s/media" % path)
|
||||
|
||||
if parsed_args.run_syncdb:
|
||||
self._exec_django_command("syncdb", parsed_args.name, '--migrate', '--noinput')
|
||||
|
||||
if parsed_args.run_collectstatic:
|
||||
self._exec_django_command("collectstatic", parsed_args.name, '--noinput')
|
||||
|
||||
@@ -13,9 +13,10 @@ class Command(object):
|
||||
"""
|
||||
help = "No help available."
|
||||
|
||||
def __init__(self, commands, **kwargs):
|
||||
def __init__(self, commands, verbose=False, **kwargs):
|
||||
self._commands = commands
|
||||
self._parser = argparse.ArgumentParser()
|
||||
self._verbose = verbose
|
||||
if not settings.configured:
|
||||
settings.configure()
|
||||
self._templates_dir = "%s/templates" % os.path.dirname(__file__)
|
||||
@@ -74,6 +75,8 @@ def handle_command_line():
|
||||
epilog="""Available commands:
|
||||
%s
|
||||
""" % "\n".join(map(lambda c: "\t" + c, sorted(commands))))
|
||||
parser.add_argument('--verbose', action='store_true',
|
||||
help='Activate verbose output')
|
||||
parser.add_argument('command', type=str,
|
||||
help='A valid command name')
|
||||
(args, remaining) = parser.parse_known_args()
|
||||
@@ -82,4 +85,4 @@ def handle_command_line():
|
||||
print >>sys.stderr, "Unknown command '%s'" % args.command
|
||||
sys.exit(1)
|
||||
|
||||
commands[args.command](commands).run(remaining)
|
||||
commands[args.command](commands, verbose=args.verbose).run(remaining)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Django settings for toto project.
|
||||
import os
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
@@ -11,28 +12,21 @@ ADMINS = (
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
|
||||
'NAME': '', # Or path to database file if using sqlite3.
|
||||
'USER': '', # Not used with sqlite3.
|
||||
'PASSWORD': '', # Not used with sqlite3.
|
||||
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
|
||||
'PORT': '', # Set to empty string for default. Not used with sqlite3.
|
||||
},
|
||||
DATABASES = { {{ default_conn|safe }}
|
||||
# "pfxadmin" : {
|
||||
# "ENGINE" : "django.db.backends.",
|
||||
# "NAME" : "",
|
||||
# "USER" : "",
|
||||
# "PASSWORD" : ""
|
||||
# },
|
||||
# },{% if not amavis_conn %}
|
||||
# "amavis": {
|
||||
# "ENGINE" : "django.db.backends.",
|
||||
# "HOST" : "",
|
||||
# "NAME" : "",
|
||||
# "USER" : "",
|
||||
# "PASSWORD" : ""
|
||||
# }
|
||||
# }{% else %}
|
||||
{{ amavis_conn|safe }}{% endif %}
|
||||
}
|
||||
|
||||
DATABASE_ROUTERS = ["modoboa.extensions.amavis.dbrouter.AmavisRouter"]
|
||||
@@ -153,7 +147,7 @@ INSTALLED_APPS = (
|
||||
'modoboa.extensions.postfix_autoreply',
|
||||
'modoboa.extensions.webmail',
|
||||
'modoboa.extensions.stats',
|
||||
'modoboa.extensions.amavis',
|
||||
{% if not amavis_conn %}#{% endif %}'modoboa.extensions.amavis',
|
||||
'modoboa.extensions.sievefilters',
|
||||
|
||||
# Extra tools
|
||||
@@ -173,15 +167,15 @@ AUTHENTICATION_BACKENDS = (
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
{% if django14 %}'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
},{% endif %}
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'level': 'ERROR',{% if django14 %}
|
||||
'filters': ['require_debug_false'],{% endif %}
|
||||
'class': 'django.utils.log.AdminEmailHandler'
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user