├── django_config_gen
├── models.py
├── tests
│ ├── __init__.py
│ └── test.py
├── management
│ ├── commands
│ │ ├── __init__.py
│ │ ├── example_templates
│ │ │ ├── django.wsgi
│ │ │ ├── apache_via_nginx
│ │ │ ├── basic_apache
│ │ │ ├── apache_via_nginx_ports
│ │ │ └── nginx
│ │ ├── print_settings.py
│ │ └── config_gen.py
│ ├── __init__.py
│ └── defaults.py
└── __init__.py
├── django_config_gen_test_project
├── __init__.py
├── runtests.py
├── urls.py
└── settings.py
├── setup.cfg
├── AUTHORS
├── .gitignore
├── MANIFEST.in
├── manage.py
├── tox.ini
├── .travis.yml
├── LICENSE
├── setup.py
└── README.rst
/django_config_gen/models.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_config_gen/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_config_gen_test_project/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [wheel]
2 | universal = 1
3 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Seán Hayes
2 | Mikail Porokhovnichenko
3 |
--------------------------------------------------------------------------------
/django_config_gen/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.pyo
3 | .settings/
4 | *.pid
5 | *.log
6 | .pydevproject
7 | .project
8 | *~
9 | dist/
10 | *.egg-info/
11 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include django_config_gen/management/commands/example_templates/*
2 | include AUTHORS
3 | include LICENSE
4 | include README
5 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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_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-3efx=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 |
--------------------------------------------------------------------------------