├── .gitignore ├── .travis.yml ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── README.rst ├── django_config_gen ├── __init__.py ├── management │ ├── __init__.py │ ├── commands │ │ ├── __init__.py │ │ ├── config_gen.py │ │ ├── example_templates │ │ │ ├── apache_via_nginx │ │ │ ├── apache_via_nginx_ports │ │ │ ├── basic_apache │ │ │ ├── django.wsgi │ │ │ └── nginx │ │ └── print_settings.py │ └── defaults.py ├── models.py └── tests │ ├── __init__.py │ └── test.py ├── django_config_gen_test_project ├── __init__.py ├── runtests.py ├── settings.py └── urls.py ├── manage.py ├── setup.cfg ├── setup.py └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | .settings/ 4 | *.pid 5 | *.log 6 | .pydevproject 7 | .project 8 | *~ 9 | dist/ 10 | *.egg-info/ 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: python 4 | 5 | python: 6 | - "2.7" 7 | - "3.5" 8 | 9 | env: 10 | - DJANGO_VERSION=dj17 11 | - DJANGO_VERSION=dj18 12 | - DJANGO_VERSION=dj19 13 | - DJANGO_VERSION=djdev 14 | 15 | matrix: 16 | allow_failures: 17 | - env: DJANGO_VERSION=djdev 18 | exclude: 19 | - python: "3.5" 20 | env: DJANGO_VERSION=dj17 21 | 22 | cache: 23 | directories: 24 | - $HOME/.cache/pip 25 | 26 | before_cache: 27 | - rm -f $HOME/.cache/pip/log/debug.log 28 | 29 | install: 30 | - pip install -U pip 31 | - pip install -U wheel virtualenv 32 | - pip install tox coveralls 33 | - python setup.py install 34 | 35 | after_success: 36 | - coveralls 37 | 38 | script: 39 | - coverage erase 40 | - tox -e py${TRAVIS_PYTHON_VERSION/./}-${DJANGO_VERSION} 41 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Seán Hayes 2 | Mikail Porokhovnichenko 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Some code in django_config_gen/management/commands/config_gen.py was taken from the file django/template/context.py in Django, which is under a BSD license and is the copyright of the Django Software Foundation. 2 | 3 | Copyright (c) 2010, 2011 Seán Hayes 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the name of Seán Hayes nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include django_config_gen/management/commands/example_templates/* 2 | include AUTHORS 3 | include LICENSE 4 | include README 5 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ================= 2 | django-config-gen 3 | ================= 4 | 5 | **Maintenance/updates now handled by brillgen/django-config-gen:** https://github.com/brillgen/django-config-gen 6 | 7 | .. image:: https://travis-ci.org/greyside/django-config-gen.svg 8 | :target: https://travis-ci.org/greyside/django-config-gen 9 | :alt: CI 10 | 11 | .. image:: https://coveralls.io/repos/greyside/django-config-gen/badge.svg?service=github 12 | :target: https://coveralls.io/github/greyside/django-config-gen 13 | :alt: Code Coverage 14 | 15 | .. image:: https://img.shields.io/pypi/v/django-config-gen.svg 16 | :target: https://pypi.python.org/pypi/django-config-gen 17 | :alt: Version 18 | 19 | .. image:: https://img.shields.io/pypi/dm/django-config-gen.svg 20 | :target: https://pypi.python.org/pypi/django-config-gen 21 | :alt: Downloads 22 | 23 | Generates configuration files for Apache, Nginx, etc. using values in 24 | settings.py and the Django template system. You can write your own templates 25 | for whatever text based config file you need. 26 | 27 | Install 28 | ======= 29 | 30 | Requires: 31 | --------- 32 | 33 | * Python 2.7+ or Python 3.4+ 34 | * Django 1.7 through Django 1.9 35 | 36 | 1. `pip install django-config-gen` 37 | 38 | 2. Add 'django_config_gen' to your `INSTALLED_APPS`. 39 | 40 | Usage 41 | ===== 42 | 43 | Run './manage.py config_gen' on the command line in your project directory. 44 | 45 | Templates for your config files go in: 46 | /config/templates/ 47 | 48 | All text files in that directory are loaded with the Django template system 49 | using values from settings.py as Context. The output of each file is saved with 50 | the same filename but in the following directory: 51 | /config/generated/ 52 | 53 | These output directories can be customized using CONFIG_GEN_TEMPLATES_DIR and CONFIG_GEN_GENERATED_DIR in settings.py. 54 | 55 | Example templates are provided in 'django-config-gen/django_config_gen/management/commands/example_templates'. If the folder specified by CONFIG_GEN_TEMPLATES_DIR is empty then these will be copied there and used for generating templates. 56 | 57 | Default Variables 58 | ================= 59 | 60 | Some default variables are used in the Context used to render the config files, 61 | and they can be manually overridden in settings.py. 62 | 63 | PROJECT_ROOT 64 | The absolute path to the directory your manage.py is in. 65 | 66 | LOG_DIR 67 | A directory called 'logs/' within your PROJECT_ROOT. 68 | 69 | CONFIG_GEN_TEMPLATES_DIR 70 | A directory called 'config/templates/' in your PROJECT_ROOT. 71 | 72 | CONFIG_GEN_GENERATED_DIR 73 | A directory called 'config/generated/' in your PROJECT_ROOT. 74 | 75 | CONFIG_GEN_CONTEXT_PROCESSORS 76 | A list of custom context processors that are to be used when rendering config 77 | files. Example: 78 | 79 | settings.py: 80 | 81 | .. code:: python 82 | 83 | CONFIG_GEN_CONTEXT_PROCESSORS = ['myapp.config_context_processors.foo'] 84 | 85 | myapp/config_context_processors.py: 86 | 87 | .. code:: python 88 | 89 | def foo(*args, **kwargs): 90 | return {'foo': 'bar'} 91 | 92 | Nothing is currently passed in to the context processors but that may change in 93 | the future, so using *args and **kwargs in the method signature will help 94 | ensure forward compatibility. 95 | 96 | HOST 97 | The hostname specified in your database for the current Site. If 98 | `./manage.py syncdb` hasn't been run yet, the value 'localhost' is used. 99 | 100 | Contributing 101 | ============ 102 | 103 | You can fork this project on GitHub: http://github.com/greyside/django-config-gen. 104 | 105 | License 106 | ======= 107 | 108 | This project is licensed under the BSD License. 109 | http://www.opensource.org/licenses/bsd-license.php 110 | 111 | Links 112 | ===== 113 | 114 | https://github.com/greyside/django-config-gen 115 | http://pypi.python.org/pypi/django-config-gen 116 | http://djangopackages.com/packages/p/django-config-gen/ 117 | -------------------------------------------------------------------------------- /django_config_gen/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #Copyright (C) 2010, 2011 Seán Hayes 3 | # 4 | #Licensed under a BSD 3-Clause License. See LICENSE file. 5 | 6 | VERSION = (1, 1, 0) 7 | 8 | __version__ = "".join([".".join(map(str, VERSION[0:3])), "".join(VERSION[3:])]) 9 | -------------------------------------------------------------------------------- /django_config_gen/management/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #Copyright (C) 2010, 2011 Seán Hayes 3 | # 4 | #Licensed under a BSD 3-Clause License. See LICENSE file. 5 | 6 | from django.conf import settings 7 | import os 8 | from . import defaults 9 | 10 | 11 | _names = { 12 | 'PROJECT_ROOT': 'PROJECT_ROOT', 13 | 'PROJECT_PARENT_DIR': 'PROJECT_ROOT', 14 | 'LOG_DIR': 'LOG_DIR', 15 | 'CONFIG_GEN_TEMPLATES_DIR': 'TEMPLATES_DIR', 16 | 'CONFIG_GEN_GENERATED_DIR': 'GENERATED_DIR', 17 | 'CONFIG_GEN_CONTEXT_PROCESSORS': 'CONTEXT_PROCESSORS', 18 | 'HOST': 'HOST', 19 | } 20 | 21 | 22 | def patch_settings(): 23 | for setting, default in _names.items(): 24 | if not hasattr(settings, setting): 25 | setattr(settings, setting, getattr(defaults, default)) 26 | -------------------------------------------------------------------------------- /django_config_gen/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greyside/django-config-gen/9eb1da55d6fc45481ca4472ba297cdcf64b7e3ec/django_config_gen/management/commands/__init__.py -------------------------------------------------------------------------------- /django_config_gen/management/commands/config_gen.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #Copyright (C) 2010, 2011 Seán Hayes 3 | # 4 | #Licensed under a BSD 3-Clause License. See LICENSE file. 5 | 6 | from django.core.management.base import BaseCommand, CommandError 7 | from django.conf import settings 8 | from django.template import Template, Context 9 | from django.core.exceptions import ImproperlyConfigured 10 | 11 | try: 12 | from django.utils.importlib import import_module 13 | except ImportError: 14 | from importlib import import_module 15 | 16 | from .. import patch_settings 17 | import os 18 | import shutil 19 | import logging 20 | 21 | 22 | logger = logging.getLogger(__name__) 23 | 24 | 25 | patch_settings() 26 | 27 | 28 | TEMPLATES_DIR = settings.CONFIG_GEN_TEMPLATES_DIR 29 | GENERATED_DIR = settings.CONFIG_GEN_GENERATED_DIR 30 | CONTEXT_PROCESSORS = settings.CONFIG_GEN_CONTEXT_PROCESSORS 31 | 32 | 33 | class Command(BaseCommand): 34 | help = 'Generates configuration files for Apache, Nginx, etc. using values in settings.py and the Django template system.' 35 | ctx = None 36 | 37 | def handle(self, **options): 38 | # get all templates in TEMPLATES_DIR, parse them, and output files in GENERATED_DIR 39 | # logging.debug(settings) 40 | self.ctx = Context(settings._wrapped.__dict__) 41 | 42 | # run context processors 43 | for path in CONTEXT_PROCESSORS: 44 | logger.debug('Processing Context Processor: %s' % path) 45 | # these next 10 lines were taken from Django (file: django/template/context.py), which is under a BSD license 46 | i = path.rfind('.') 47 | module, attr = path[:i], path[i+1:] 48 | try: 49 | mod = import_module(module) 50 | except ImportError as e: 51 | raise ImproperlyConfigured('Error importing config processor module %s: "%s"' % (module, e)) 52 | try: 53 | func = getattr(mod, attr) 54 | except AttributeError: 55 | raise ImproperlyConfigured('Module "%s" does not define a "%s" callable request processor' % (module, attr)) 56 | 57 | d = func() 58 | logger.debug(d) 59 | self.ctx.update(d) 60 | 61 | if not os.path.exists(TEMPLATES_DIR): 62 | os.makedirs(TEMPLATES_DIR) 63 | 64 | if not os.path.exists(GENERATED_DIR): 65 | os.makedirs(GENERATED_DIR) 66 | 67 | dir_list=os.listdir(TEMPLATES_DIR) 68 | # if no templates are present, populate template directory with the examples 69 | 70 | if len(dir_list) is 0: 71 | logger.debug('%s was empty' % TEMPLATES_DIR) 72 | example_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'example_templates') 73 | for filename in os.listdir(example_dir): 74 | shutil.copy2(os.path.join(example_dir, filename), TEMPLATES_DIR) 75 | dir_list=os.listdir(TEMPLATES_DIR) 76 | 77 | logger.debug(self.ctx) 78 | self.create_nodes(TEMPLATES_DIR) 79 | 80 | def render_template(self, source, target): 81 | fi = open(source, 'r') 82 | t = Template(fi.read()) 83 | fi.close() 84 | 85 | fo = open(target, 'wb') 86 | generated_text = t.render(self.ctx).encode('utf-8') 87 | fo.write(generated_text) 88 | fo.close() 89 | 90 | def create_nodes(self, path): 91 | for root, dirs, files in os.walk(path): 92 | for dirname in dirs: 93 | source = os.path.join(root, dirname) 94 | target = source.replace(TEMPLATES_DIR, GENERATED_DIR) 95 | 96 | if not os.path.exists(target): 97 | os.makedirs(target) 98 | 99 | for filename in files: 100 | source = os.path.join(root, filename) 101 | target = source.replace(TEMPLATES_DIR, GENERATED_DIR) 102 | dirname = os.path.dirname(source) 103 | 104 | if not os.path.exists(dirname): 105 | os.makedirs(dirname) 106 | self.render_template(source, target) 107 | -------------------------------------------------------------------------------- /django_config_gen/management/commands/example_templates/apache_via_nginx: -------------------------------------------------------------------------------- 1 | # Based on http://lincolnloop.com/django-best-practices/deployment/servers.html 2 | 3 | ServerName {{HOST}} 4 | ServerAdmin webmaster@{{HOST}} 5 | ErrorLog {{LOG_DIR}}/apache2_error.log 6 | CustomLog {{LOG_DIR}}/apache2_access.log combined 7 | 8 | WSGIDaemonProcess {{HOST}} display-name=%{GROUP} maximum-requests=10000 9 | WSGIProcessGroup {{HOST}} 10 | 11 | WSGIScriptAlias / {{CONFIG_GEN_GENERATED_DIR}}/django.wsgi 12 | 13 | 14 | Order deny,allow 15 | Allow from all 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /django_config_gen/management/commands/example_templates/apache_via_nginx_ports: -------------------------------------------------------------------------------- 1 | #use to replace /etc/apache2/ports.conf 2 | # If you just change the port or add more ports here, you will likely also 3 | # have to change the VirtualHost statement in 4 | # /etc/apache2/sites-enabled/000-default 5 | # This is also true if you have upgraded from before 2.2.9-3 (i.e. from 6 | # Debian etch). See /usr/share/doc/apache2.2-common/NEWS.Debian.gz and 7 | # README.Debian.gz 8 | 9 | NameVirtualHost *:9000 10 | Listen 9000 11 | 12 | #HTTPS is handled by Nginx 13 | # 14 | # If you add NameVirtualHost *:443 here, you will also have to change 15 | # the VirtualHost statement in /etc/apache2/sites-available/default-ssl 16 | # to 17 | # Server Name Indication for SSL named virtual hosts is currently not 18 | # supported by MSIE on Windows XP. 19 | # Listen 443 20 | # 21 | 22 | # 23 | # Listen 443 24 | # 25 | -------------------------------------------------------------------------------- /django_config_gen/management/commands/example_templates/basic_apache: -------------------------------------------------------------------------------- 1 | 2 | ServerAdmin {{ADMINS.0.1}} 3 | 4 | Alias /robots.txt {{MEDIA_ROOT}}/robots.txt 5 | Alias /favicon.ico {{MEDIA_ROOT}}/favicon.ico 6 | 7 | Alias {{MEDIA_URL}} {{MEDIA_ROOT}}/ 8 | Alias {{ADMIN_MEDIA_PREFIX}} {{PROJECT_ROOT}}{{ADMIN_MEDIA_PREFIX}} 9 | 10 | 11 | Order deny,allow 12 | Allow from all 13 | 14 | 15 | WSGIScriptAlias / {{CONFIG_GEN_GENERATED_DIR}}/django.wsgi 16 | 17 | 18 | Order allow,deny 19 | Allow from all 20 | 21 | 22 | ErrorLog {{LOG_DIR}}/apache2_error.log 23 | 24 | # Possible values include: debug, info, notice, warn, error, crit, 25 | # alert, emerg. 26 | LogLevel debug 27 | 28 | CustomLog {{LOG_DIR}}/apache2_access.log combined 29 | 30 | 31 | -------------------------------------------------------------------------------- /django_config_gen/management/commands/example_templates/django.wsgi: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.stdout = sys.stderr 5 | 6 | sys.path.append('{{PROJECT_PARENT_DIR}}') 7 | os.environ['DJANGO_SETTINGS_MODULE'] = '{{SETTINGS_MODULE}}' 8 | 9 | import django.core.handlers.wsgi 10 | application = django.core.handlers.wsgi.WSGIHandler() 11 | 12 | -------------------------------------------------------------------------------- /django_config_gen/management/commands/example_templates/nginx: -------------------------------------------------------------------------------- 1 | # Based on http://lincolnloop.com/django-best-practices/deployment/servers.html 2 | # Apache server 3 | upstream django { 4 | server {{HOST}}:9000; 5 | } 6 | 7 | # Redirect all requests on the www subdomain to the root domain 8 | server { 9 | listen 80; 10 | server_name www.{{HOST}}; 11 | rewrite ^/(.*) http://{{HOST}}/$1 permanent; 12 | } 13 | 14 | # Serve static files and redirect any other request to Apache 15 | server { 16 | listen 80; 17 | server_name {{HOST}}; 18 | access_log {{LOG_DIR}}/nginx_access.log; 19 | error_log {{LOG_DIR}}/nginx_error.log warn; 20 | 21 | proxy_redirect off; 22 | proxy_set_header Host $host; 23 | proxy_set_header X-Real-IP $remote_addr; 24 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 25 | 26 | location / { 27 | proxy_pass http://django; 28 | } 29 | 30 | location {{MEDIA_URL}} { 31 | root {{PROJECT_ROOT}}; 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /django_config_gen/management/commands/print_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #Copyright (C) 2010, 2011 Seán Hayes 3 | # 4 | #Licensed under a BSD 3-Clause License. See LICENSE file. 5 | 6 | from django.core.management.base import BaseCommand, CommandError 7 | from django.conf import settings 8 | from .. import patch_settings 9 | import json 10 | import copy 11 | import logging 12 | 13 | 14 | logger = logging.getLogger(__name__) 15 | 16 | 17 | class NullHandler(logging.Handler): 18 | def emit(self, record): 19 | pass 20 | 21 | 22 | patch_settings() 23 | 24 | 25 | class Command(BaseCommand): 26 | help = 'Prints out settings serialized as JSON.' 27 | 28 | def handle(self, **options): 29 | #remove logging statements from output 30 | l = logging.getLogger('') 31 | for h in l.handlers: 32 | l.removeHandler(h) 33 | l.addHandler(NullHandler()) 34 | 35 | d = {} 36 | s_d = settings._wrapped.__dict__ 37 | for key in settings._wrapped.__dict__: 38 | val = s_d[key] 39 | logger.debug('%s: %s' % (key, val)) 40 | try: 41 | #if settings has something like "import django.conf.global_settings as DEFAULT_SETTINGS" 42 | #in it, then json encoding will throw and error. Copying makes 43 | #sure modules don't get included. 44 | d[key] = copy.copy(val) 45 | except Exception as e: 46 | logger.error(e) 47 | print(json.dumps(d, indent=4, sort_keys=True)) 48 | -------------------------------------------------------------------------------- /django_config_gen/management/defaults.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #Copyright (C) 2010, 2011 Seán Hayes 3 | # 4 | #Licensed under a BSD 3-Clause License. See LICENSE file. 5 | 6 | import __main__ 7 | import os 8 | from django.contrib.sites.models import Site 9 | from django.db import transaction 10 | 11 | 12 | PROJECT_ROOT = os.path.abspath(os.path.dirname(__main__.__file__)) 13 | LOG_DIR = os.path.join(PROJECT_ROOT, 'logs') 14 | 15 | _config_dir = os.path.join(PROJECT_ROOT, 'config') 16 | TEMPLATES_DIR = os.path.join(_config_dir, 'templates') 17 | GENERATED_DIR = os.path.join(_config_dir, 'generated') 18 | 19 | CONTEXT_PROCESSORS = [] 20 | 21 | 22 | # Error is thrown when running "./manage.py syncdb" for the first time and this app is installed. 23 | try: 24 | HOST = Site.objects.get_current().domain.split(':')[0] 25 | except: 26 | # try/except to avoid "django.db.transaction.TransactionManagementError: This code isn't under transaction management" 27 | try: 28 | transaction.rollback() 29 | except: 30 | pass 31 | HOST = 'localhost' 32 | -------------------------------------------------------------------------------- /django_config_gen/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greyside/django-config-gen/9eb1da55d6fc45481ca4472ba297cdcf64b7e3ec/django_config_gen/models.py -------------------------------------------------------------------------------- /django_config_gen/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greyside/django-config-gen/9eb1da55d6fc45481ca4472ba297cdcf64b7e3ec/django_config_gen/tests/__init__.py -------------------------------------------------------------------------------- /django_config_gen/tests/test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #Copyright (C) 2010, 2011 Seán Hayes 3 | # 4 | #Licensed under a BSD 3-Clause License. See LICENSE file. 5 | 6 | import os 7 | import shutil 8 | import tempfile 9 | 10 | from django.conf import settings 11 | from django.core.management import call_command 12 | from django.test import override_settings, TestCase 13 | 14 | from django_config_gen.management import patch_settings 15 | 16 | 17 | try: 18 | FileNotFoundError 19 | except NameError: 20 | FileNotFoundError = IOError 21 | 22 | 23 | config_dir = os.path.join(tempfile.gettempdir(), 'config') 24 | 25 | 26 | @override_settings( 27 | CONFIG_GEN_TEMPLATES_DIR=os.path.join(config_dir, 'templates'), 28 | CONFIG_GEN_GENERATED_DIR=os.path.join(config_dir, 'generated') 29 | ) 30 | class CallCommandTestCase(TestCase): 31 | def setUp(self): 32 | self.tmp_files = [] 33 | 34 | def tearDown(self): 35 | for tmp_file in self.tmp_files: 36 | try: 37 | os.remove(tmp_file) 38 | except FileNotFoundError: 39 | pass 40 | 41 | shutil.rmtree(config_dir) 42 | 43 | def test_handles_unicode_in_file_contents(self): 44 | "Make sure unicode is supported in file contents." 45 | 46 | test_file_name = 'test_file' 47 | test_file_template_path = os.path.join(settings.CONFIG_GEN_TEMPLATES_DIR, test_file_name) 48 | test_file_generated_path = os.path.join(settings.CONFIG_GEN_GENERATED_DIR, test_file_name) 49 | self.tmp_files.append(test_file_template_path) 50 | self.tmp_files.append(test_file_generated_path) 51 | 52 | if not os.path.exists(settings.CONFIG_GEN_TEMPLATES_DIR): 53 | os.makedirs(settings.CONFIG_GEN_TEMPLATES_DIR) 54 | 55 | config_template = u""" 56 | This is some text with unicode! 57 | -Seán Hayes 58 | """.encode('utf-8') 59 | 60 | fo = open(test_file_template_path, 'wb') 61 | fo.write(config_template) 62 | fo.close() 63 | 64 | self.assertTrue(os.path.exists(test_file_template_path)) 65 | self.assertFalse(os.path.exists(test_file_generated_path)) 66 | 67 | call_command('config_gen') 68 | 69 | fi = open(test_file_generated_path, 'rb') 70 | generated_text = fi.read() 71 | fi.close() 72 | 73 | self.assertTrue(os.path.exists(test_file_generated_path)) 74 | #make sure the unicode didn't get silently mangled 75 | self.assertEqual(config_template, generated_text) 76 | 77 | 78 | def test_copies_sub_folder_contents(self): 79 | "Make sure unicode is supported in file contents." 80 | os.makedirs(os.path.join(settings.CONFIG_GEN_TEMPLATES_DIR, 'foo', 'bar')) 81 | 82 | test_file_name = 'test_file' 83 | test_file_template_path = os.path.join(settings.CONFIG_GEN_TEMPLATES_DIR, 'foo', 'bar', test_file_name) 84 | test_file_generated_path = os.path.join(settings.CONFIG_GEN_GENERATED_DIR, 'foo', 'bar', test_file_name) 85 | self.tmp_files.append(test_file_template_path) 86 | self.tmp_files.append(test_file_generated_path) 87 | 88 | if not os.path.exists(settings.CONFIG_GEN_TEMPLATES_DIR): 89 | os.makedirs(settings.CONFIG_GEN_TEMPLATES_DIR) 90 | 91 | config_template = u""" 92 | This is some text with unicode! 93 | -Seán Hayes 94 | """.encode('utf-8') 95 | 96 | fo = open(test_file_template_path, 'wb') 97 | fo.write(config_template) 98 | fo.close() 99 | 100 | self.assertTrue(os.path.exists(test_file_template_path)) 101 | self.assertFalse(os.path.exists(test_file_generated_path)) 102 | 103 | call_command('config_gen') 104 | 105 | fi = open(test_file_generated_path, 'rb') 106 | generated_text = fi.read() 107 | fi.close() 108 | 109 | self.assertTrue(os.path.exists(test_file_generated_path)) 110 | #make sure the unicode didn't get silently mangled 111 | self.assertEqual(config_template, generated_text) 112 | -------------------------------------------------------------------------------- /django_config_gen_test_project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greyside/django-config-gen/9eb1da55d6fc45481ca4472ba297cdcf64b7e3ec/django_config_gen_test_project/__init__.py -------------------------------------------------------------------------------- /django_config_gen_test_project/runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os, sys 3 | from . import settings 4 | from django.core.management import call_command 5 | import django 6 | 7 | os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % settings.PROJECT_MODULE 8 | sys.path.insert(0, settings.PROJECT_PARENT_DIR) 9 | 10 | def runtests(): 11 | django.setup() 12 | call_command('test', 'django_config_gen') 13 | sys.exit() 14 | 15 | if __name__ == '__main__': 16 | runtests() 17 | -------------------------------------------------------------------------------- /django_config_gen_test_project/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for django_config_gen_test_project project. 2 | 3 | import os 4 | import django.conf.global_settings as DEFAULT_SETTINGS 5 | 6 | PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) 7 | PROJECT_PARENT_DIR = os.path.dirname(PROJECT_ROOT) 8 | 9 | PROJECT_MODULE = __name__[:__name__.rfind('.')] if '.' in __name__ else PROJECT_ROOT.split(os.sep)[-1] 10 | 11 | DEBUG = True 12 | TEMPLATE_DEBUG = DEBUG 13 | 14 | ADMINS = ( 15 | # ('Your Name', 'your_email@example.com'), 16 | ) 17 | 18 | MANAGERS = ADMINS 19 | 20 | DATABASES = { 21 | 'default': { 22 | 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 23 | 'NAME': '', # Or path to database file if using sqlite3. 24 | 'USER': '', # Not used with sqlite3. 25 | 'PASSWORD': '', # Not used with sqlite3. 26 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 27 | 'PORT': '', # Set to empty string for default. Not used with sqlite3. 28 | } 29 | } 30 | 31 | # Local time zone for this installation. Choices can be found here: 32 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 33 | # although not all choices may be available on all operating systems. 34 | # On Unix systems, a value of None will cause Django to use the same 35 | # timezone as the operating system. 36 | # If running in a Windows environment this must be set to the same as your 37 | # system time zone. 38 | TIME_ZONE = 'America/Chicago' 39 | 40 | # Language code for this installation. All choices can be found here: 41 | # http://www.i18nguy.com/unicode/language-identifiers.html 42 | LANGUAGE_CODE = 'en-us' 43 | 44 | SITE_ID = 1 45 | 46 | # If you set this to False, Django will make some optimizations so as not 47 | # to load the internationalization machinery. 48 | USE_I18N = True 49 | 50 | # If you set this to False, Django will not format dates, numbers and 51 | # calendars according to the current locale 52 | USE_L10N = True 53 | 54 | # Absolute filesystem path to the directory that will hold user-uploaded files. 55 | # Example: "/home/media/media.lawrence.com/media/" 56 | MEDIA_ROOT = '' 57 | 58 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 59 | # trailing slash. 60 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" 61 | MEDIA_URL = '' 62 | 63 | # Absolute path to the directory static files should be collected to. 64 | # Don't put anything in this directory yourself; store your static files 65 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 66 | # Example: "/home/media/media.lawrence.com/static/" 67 | STATIC_ROOT = '' 68 | 69 | # URL prefix for static files. 70 | # Example: "http://media.lawrence.com/static/" 71 | STATIC_URL = '/static/' 72 | 73 | # URL prefix for admin static files -- CSS, JavaScript and images. 74 | # Make sure to use a trailing slash. 75 | # Examples: "http://foo.com/static/admin/", "/static/admin/". 76 | ADMIN_MEDIA_PREFIX = '/static/admin/' 77 | 78 | # Additional locations of static files 79 | STATICFILES_DIRS = ( 80 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 81 | # Always use forward slashes, even on Windows. 82 | # Don't forget to use absolute paths, not relative paths. 83 | ) 84 | 85 | # List of finder classes that know how to find static files in 86 | # various locations. 87 | STATICFILES_FINDERS = ( 88 | 'django.contrib.staticfiles.finders.FileSystemFinder', 89 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 90 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 91 | ) 92 | 93 | # Make this unique, and don't share it with anybody. 94 | SECRET_KEY = ')v)jqp7voco+%3-9&75)i=u_j8u)+q1-3e&#fx=y#n+jk=!hxt' 95 | 96 | # List of callables that know how to import templates from various sources. 97 | TEMPLATE_LOADERS = ( 98 | 'django.template.loaders.filesystem.Loader', 99 | 'django.template.loaders.app_directories.Loader', 100 | # 'django.template.loaders.eggs.Loader', 101 | ) 102 | 103 | MIDDLEWARE_CLASSES = ( 104 | 'django.middleware.common.CommonMiddleware', 105 | 'django.contrib.sessions.middleware.SessionMiddleware', 106 | 'django.middleware.csrf.CsrfViewMiddleware', 107 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 108 | 'django.contrib.messages.middleware.MessageMiddleware', 109 | ) 110 | 111 | ROOT_URLCONF = 'django_config_gen_test_project.urls' 112 | 113 | TEMPLATE_DIRS = ( 114 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 115 | # Always use forward slashes, even on Windows. 116 | # Don't forget to use absolute paths, not relative paths. 117 | ) 118 | 119 | INSTALLED_APPS = ( 120 | 'django.contrib.auth', 121 | 'django.contrib.contenttypes', 122 | 'django.contrib.sessions', 123 | 'django.contrib.sites', 124 | 'django.contrib.messages', 125 | 'django.contrib.staticfiles', 126 | # Uncomment the next line to enable the admin: 127 | # 'django.contrib.admin', 128 | # Uncomment the next line to enable admin documentation: 129 | # 'django.contrib.admindocs', 130 | 131 | #app that we want to test 132 | 'django_config_gen', 133 | ) 134 | 135 | # A sample logging configuration. The only tangible logging 136 | # performed by this configuration is to send an email to 137 | # the site admins on every HTTP 500 error. 138 | # See http://docs.djangoproject.com/en/dev/topics/logging for 139 | # more details on how to customize your logging configuration. 140 | LOGGING = { 141 | 'version': 1, 142 | 'disable_existing_loggers': False, 143 | 'handlers': { 144 | 'mail_admins': { 145 | 'level': 'ERROR', 146 | 'class': 'django.utils.log.AdminEmailHandler' 147 | } 148 | }, 149 | 'loggers': { 150 | 'django.request': { 151 | 'handlers': ['mail_admins'], 152 | 'level': 'ERROR', 153 | 'propagate': True, 154 | }, 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /django_config_gen_test_project/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import patterns, include, url 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # Examples: 9 | # url(r'^$', 'django_config_gen_test_project.views.home', name='home'), 10 | # url(r'^django_config_gen_test_project/', include('django_config_gen_test_project.foo.urls')), 11 | 12 | # Uncomment the admin/doc line below to enable admin documentation: 13 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | # url(r'^admin/', include(admin.site.urls)), 17 | ) 18 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_config_gen_test_project.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | from setuptools import setup 6 | import django_config_gen 7 | 8 | 9 | package_name = 'django_config_gen' 10 | test_package_name = '%s_test_project' % package_name 11 | 12 | 13 | def get_packages(package): 14 | """ 15 | Return root package and all sub-packages. 16 | """ 17 | return [dirpath 18 | for dirpath, dirnames, filenames in os.walk(package) 19 | if os.path.exists(os.path.join(dirpath, '__init__.py'))] 20 | 21 | 22 | setup(name='django-config-gen', 23 | version=django_config_gen.__version__, 24 | description="Generates configuration files for Apache, Nginx, etc. using values in settings.py and the Django template system. You can write your own templates for whatever text based config file you need.", 25 | author='Seán Hayes', 26 | author_email='sean@seanhayes.name', 27 | classifiers=[ 28 | "Development Status :: 5 - Production/Stable", 29 | "Framework :: Django", 30 | "Intended Audience :: Developers", 31 | "Intended Audience :: System Administrators", 32 | "License :: OSI Approved :: BSD License", 33 | "Operating System :: OS Independent", 34 | "Programming Language :: Python", 35 | "Programming Language :: Python :: 2.6", 36 | "Topic :: Internet :: WWW/HTTP :: Dynamic Content", 37 | "Topic :: Internet :: WWW/HTTP :: Site Management", 38 | "Topic :: Software Development :: Build Tools", 39 | "Topic :: Software Development :: Code Generators", 40 | "Topic :: Software Development :: Libraries", 41 | "Topic :: Software Development :: Libraries :: Python Modules" 42 | ], 43 | keywords='django configuration generator', 44 | url='http://seanhayes.name/', 45 | download_url='https://github.com/SeanHayes/django-config-gen', 46 | license='BSD', 47 | packages=get_packages('django_config_gen'), 48 | package_data={'django_config_gen': ['management/commands/example_templates/*']}, 49 | include_package_data=True, 50 | install_requires=['Django>=1.2',], 51 | test_suite='%s.runtests.runtests' % test_package_name, 52 | ) 53 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3 | py{35,27}-djdev, 4 | py{35,27}-dj19, 5 | py{35,27}-dj18, 6 | py27-dj17, 7 | skipsdist=True 8 | 9 | [testenv] 10 | usedevelop=True 11 | test-executable = 12 | {envbindir}/coverage run --append --source=django_config_gen 13 | commands = 14 | {[testenv]test-executable} setup.py test 15 | basepython = 16 | py27: python2.7 17 | py35: python3.5 18 | deps = 19 | dj17: Django>=1.7,<1.8 20 | dj18: Django>=1.8,<1.9 21 | dj19: Django>=1.9,<1.10 22 | djdev: https://github.com/django/django/archive/master.tar.gz 23 | coverage 24 | --------------------------------------------------------------------------------