From ff72821bb036510a6722ca88ee964412dad2bf4e Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 11 Oct 2012 23:01:30 +0200 Subject: [PATCH] wip: New command-line tool. The deployment command seems to work. see #314 --- modoboa/bin/modoboa-admin.py | 8 ++ modoboa/core/__init__.py | 0 modoboa/core/management.py | 71 +++++++++++ modoboa/core/templates/settings.py | 195 +++++++++++++++++++++++++++++ modoboa/core/templates/urls.py | 18 +++ setup.py | 3 +- 6 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 modoboa/bin/modoboa-admin.py create mode 100644 modoboa/core/__init__.py create mode 100644 modoboa/core/management.py create mode 100644 modoboa/core/templates/settings.py create mode 100644 modoboa/core/templates/urls.py diff --git a/modoboa/bin/modoboa-admin.py b/modoboa/bin/modoboa-admin.py new file mode 100644 index 000000000..6da3810af --- /dev/null +++ b/modoboa/bin/modoboa-admin.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +# coding: utf-8 + +from modoboa.core.management import handle_command_line + +if __name__ == "__main__": + handle_command_line() + diff --git a/modoboa/core/__init__.py b/modoboa/core/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modoboa/core/management.py b/modoboa/core/management.py new file mode 100644 index 000000000..6302da2aa --- /dev/null +++ b/modoboa/core/management.py @@ -0,0 +1,71 @@ +# coding: utf-8 + +from django.core import management +from django.conf import settings +from django.template import Context, Template +import argparse +import sys +import os +import shutil + +class Command(object): + + def __init__(self): + self._parser = argparse.ArgumentParser() + if not settings.configured: + settings.configure() + + def _render_template(self, tplfile, env): + fp = open(tplfile) + t = Template(fp.read()) + fp.close() + return t.render(Context(env)) + + def run(self, cmdline): + args = self._parser.parse_args(cmdline) + self.handle(args) + + def handle(self, parsed_args): + raise NotImplemented + +class DeployCommand(Command): + + def __init__(self): + super(DeployCommand, self).__init__() + self._parser.add_argument('name', type=str, + help='The name of your Modoboa instance') + + def handle(self, parsed_args): + management.call_command('startproject', parsed_args.name, verbosity=False) + templates_dir = "%s/templates" % os.path.dirname(__file__) + 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) + else: + path = parsed_args.name + sys.path.append(".") + mod = __import__(parsed_args.name, globals(), locals(), ['settings']) + tpl = self._render_template("%s/settings.py" % templates_dir, { + 'secret_key' : mod.settings.SECRET_KEY, + 'name' : parsed_args.name + }) + fp = open("%s/settings.py" % path, "w") + fp.write(tpl) + fp.close() + shutil.copyfile("%s/urls.py" % templates_dir, "%s/urls.py" % path) + + +def handle_command_line(): + parser = argparse.ArgumentParser() + parser.add_argument('command', type=str, + help='A valid command name') + (args, remaining) = parser.parse_known_args() + + try: + cmd = globals()["%sCommand" % args.command.capitalize()]() + except KeyError: + print >>sys.stderr, "Unknown command '%s'" % args.command + sys.exit(1) + + cmd.run(remaining) diff --git a/modoboa/core/templates/settings.py b/modoboa/core/templates/settings.py new file mode 100644 index 000000000..091b50511 --- /dev/null +++ b/modoboa/core/templates/settings.py @@ -0,0 +1,195 @@ +# Django settings for toto project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +MODOBOA_DIR = os.path.dirname(__file__) + +ADMINS = ( + # ('Your Name', 'your_email@example.com'), +) + +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. + }, + # "pfxadmin" : { + # "ENGINE" : "django.db.backends.", + # "NAME" : "", + # "USER" : "", + # "PASSWORD" : "" + # }, + # "amavis": { + # "ENGINE" : "django.db.backends.", + # "HOST" : "", + # "NAME" : "", + # "USER" : "", + # "PASSWORD" : "" + # } +} + +DATABASE_ROUTERS = ["modoboa.extensions.amavis.dbrouter.AmavisRouter"] + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = os.path.join(MODOBOA_DIR, 'media') + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '/media/' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = os.path.join(MODOBOA_DIR, 'sitestatic') + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/sitestatic/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = '{{ secret_key }}' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + # Uncomment the next line for simple clickjacking protection: + # 'django.middleware.clickjacking.XFrameOptionsMiddleware', + + 'modoboa.lib.middleware.AjaxLoginRedirect', + 'modoboa.lib.middleware.CommonExceptionCatcher', + 'modoboa.lib.middleware.ExtControlMiddleware', +) + +ROOT_URLCONF = 'urls' + +# Python dotted path to the WSGI application used by Django's runserver. +WSGI_APPLICATION = '{{ name }}.wsgi.application' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + # 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + + 'south', + 'modoboa', + 'modoboa.auth', + 'modoboa.lib', + 'modoboa.admin', + 'modoboa.userprefs', + + # Modoboa extensions here. + 'modoboa.extensions.limits', + 'modoboa.extensions.postfix_autoreply', + 'modoboa.extensions.webmail', + 'modoboa.extensions.stats', + 'modoboa.extensions.amavis', + 'modoboa.extensions.sievefilters', + + # Extra tools + # 'modoboa.tools.pfxadmin_migrate', +) + +AUTHENTICATION_BACKENDS = ( + 'modoboa.lib.authbackends.SimpleBackend', + 'django.contrib.auth.backends.ModelBackend', +) + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} diff --git a/modoboa/core/templates/urls.py b/modoboa/core/templates/urls.py new file mode 100644 index 000000000..1e2629e5f --- /dev/null +++ b/modoboa/core/templates/urls.py @@ -0,0 +1,18 @@ +from django.conf.urls import patterns, include, url + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +urlpatterns = patterns('', + # Examples: + # url(r'^$', 'toto.views.home', name='home'), + # url(r'^toto/', include('toto.foo.urls')), + + # Uncomment the admin/doc line below to enable admin documentation: + # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + # url(r'^admin/', include(admin.site.urls)), + url(r'', include('modoboa.urls')), +) diff --git a/setup.py b/setup.py index ced1f1bdb..78e8b08d0 100644 --- a/setup.py +++ b/setup.py @@ -50,7 +50,7 @@ def read(fname): return open(os.path.join(ROOT, fname)).read() setup(name="modoboa", - version='0.9.2', + version='0.9.3', url='http://modoboa.org/', license='MIT', description="Mail hosting made simple", @@ -59,6 +59,7 @@ setup(name="modoboa", author_email='tonio@ngyn.org', packages=find_packages(), include_package_data=True, + scripts=["modoboa/bin/modoboa-admin.py"], zip_safe=False, install_requires=parse_requirements(PIP_REQUIRES), dependency_links=parse_dependency_links(PIP_REQUIRES),