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:
Antoine Nguyen
2012-10-14 16:07:53 +02:00
parent 419eb66fef
commit cfc249c24c
3 changed files with 100 additions and 21 deletions
+85 -3
View File
@@ -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')
+5 -2
View File
@@ -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)
+10 -16
View File
@@ -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'
}
},