Skip to content
Browse files

Switched to an env-based configuration structure

  • Loading branch information...
1 parent 5b6d97c commit 923b1ff5e022b26b5c399a2729cfe12e7a2a48d4 @brutasse brutasse committed Mar 15, 2013
View
22 Makefile
@@ -1,37 +1,37 @@
proj = feedhq
-settings = --settings=$(proj).settings
-test_settings = --settings=$(proj).test_settings
+django = envdir $(CURDIR)/envdir django-admin.py
+testdjango = envdir $(CURDIR)/tests/envdir django-admin.py
test:
- @django-admin.py test $(test_settings) --failfast --noinput
+ @$(testdjango) test --failfast --noinput
run:
@foreman start
db:
- @django-admin.py syncdb --noinput $(settings)
+ @$(django) syncdb --noinput
user:
- @django-admin.py createsuperuser $(settings)
+ @$(django) createsuperuser
shell:
- @django-admin.py shell $(settings)
+ @$(django) shell
dbshell:
- @django-admin.py dbshell $(settings)
+ @$(django) dbshell
updatefeeds:
- @django-admin.py updatefeeds $(settings)
+ @$(django) updatefeeds
favicons:
- @django-admin.py favicons $(settings)
+ @$(django) favicons
makemessages:
- @cd $(proj) && django-admin.py makemessages -a $(settings)
+ @cd $(proj) && $(django) makemessages -a
compilemessages:
- @cd $(proj) && django-admin.py compilemessages $(settings)
+ @cd $(proj) && $(django) compilemessages
txpush:
@tx push -s
View
4 Procfile
@@ -1,5 +1,5 @@
-web: django-admin.py runserver --settings=$PROJ.settings 0.0.0.0:8000
+web: envdir envdir django-admin.py runserver 0.0.0.0:8000
compass: compass watch --force --no-line-comments --output-style compressed --require less --sass-dir $PROJ/$APP/static/$APP/css --css-dir $PROJ/$APP/static/$APP/css --image-dir /static/ $PROJ/$APP/static/$APP/css/screen.scss
-worker: rqworker high default low
+worker: envdir envdir rqworker high default low
View
135 README.rst
@@ -67,70 +67,62 @@ Getting the code::
Configuration
-------------
-Create ``feedhq/settings.py`` and put the minimal stuff in it::
-
- from .default_settings import *
-
- ADMINS = (
- ('Your name', 'email@example.com'),
- )
- MANAGERS = ADMINS
-
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql_psycopg2',
- 'NAME': 'feedhq',
- 'USER': 'postgres',
- },
- }
-
- SECRET_KEY = 'something secret'
-
- # For development, don't do cache-busting
- STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
-
- TIME_ZONE = 'Europe/Paris'
-
- EMAIL_HOST = 'mail.your_domain.com'
- EMAIL_SUBJECT_PREFIX = '[FeedHQ] '
-
-For Readability, Instapaper and Pocket support, you'll need a couple of
-additional settings::
-
- API_KEYS = {
- 'readitlater': 'your readitlater (pocket) key',
- }
-
- INSTAPAPER = {
- 'CONSUMER_KEY': 'yay isntappaper',
- 'CONSUMER_SECRET': 'secret',
- }
-
- READABILITY = {
- 'CONSUMER_KEY': 'yay readability',
- 'CONSUMER_SECRET': 'othersecret',
- }
+FeedHQ relies on environment variables for its configuration. The required
+environment variables are:
+
+* ``DJANGO_SETTINGS_MODULE``: set it to ``feedhq.settings``.
+* ``SECRET_KEY``: set to a long random string.
+* ``ALLOWED_HOSTS``: space-separated list of hosts which serve the web app.
+ E.g. ``www.feedhq.org feedhq.org``.
+* ``REDIS_URL``: a URL for configuring redis. E.g.
+ ``redis://localhost:6354/1``.
+* ``DATABASE_URL``: a heroku-like database URL. E.g.
+ ``postgres://user:password@host:port/database``.
+
+Optionally you can customize:
+
+* ``DEBUG``: set it to a non-empty value to enable the Django debug mode.
+* ``MEDIA_ROOT``: the absolute location where media files (user-generated) are
+ stored. This must be a public directory on your webserver available under
+ the ``/media/`` URL.
+* ``STATIC_ROOT``: the absolute location where static files (CSS/JS files) are
+ stored. This must be a public directory on your webserver available under
+ the ``/static/`` URL.
+* ``SENTRY_DSN``: a DSN to enable `Sentry`_ debugging.
+
+.. _Sentry: https://www.getsentry.com/
+
+For integration with external services:
+
+* ``READITLATER_API_KEY``: your `Pocket`_ API key.
+* ``INSTAPAPER_CONSUMER_KEY``, ``INSTAPAPER_CONSUMER_SECRET``: your
+ `Instapaper`_ API keys.
+* ``READABILITY_CONSUMER_KEY``, ``READABILITY_CONSUMER_SECRET``: your
+ `Readability`_ API keys.
+
+.. _Pocket: http://getpocket.com/
+.. _Instapaper: http://www.instapaper.com/
+.. _Readability: https://www.readability.com/
Then deploy the Django app using the recipe that fits your installation. More
documentation on the `Django deployment guide`_.
.. _Django deployment guide: http://docs.djangoproject.com/en/dev/howto/deployment/
-Once your application is deployed (you've run ``django-admin.py
-syncdb --settings=feedhq.settings`` to create the database tables and
-``django-admin.py collectstatic --settings=feedhq.settings`` to collect your
-static files), you can add users to the application. On the admin interface,
-add as many users as you want. Then add some some categories and feeds to
-your account using the regular interface,
+Once your application is deployed (you've run ``django-admin.py syncdb`` to
+create the database tables and ``django-admin.py collectstatic`` to collect
+your static files), you can add users to the application. On the admin
+interface, add as many users as you want. Then add some some categories and
+feeds to your account using the regular interface,
Crawl for updates::
- django-admin.py updatefeeds --settings=feedhq.settings
+ django-admin.py updatefeeds
Set up a cron job to update your feeds on a regular basis. This puts the
oldest-updated feeds in the update queue::
- */5 * * * * /path/to/env/django-admin.py updatefeeds --settings=feedhq.settings
+ */5 * * * * /path/to/env/django-admin.py updatefeeds
The ``updatefeeds`` command puts 1/9th of the feeds in the update queue. Feeds
won't update if they've been updated in the past 45 minutes, so the 5-minute
@@ -141,11 +133,11 @@ A cron job should also be set up for picking and updating favicons (the
``--all`` switch processes existing favicons in case they have changed, which
you should probably do every month or so)::
- @monthly /path/to/env/bin/django-admin.py favicons --all --settings=feedhq.settings
+ @monthly /path/to/env/bin/django-admin.py favicons --all
And a final one to purge expired sessions from the DB::
- @daily /path/to/env/bin/django-admin.py cleanup --settings=feedhq.settings
+ @daily /path/to/env/bin/django-admin.py cleanup
Development
-----------
@@ -162,35 +154,14 @@ Or if you want to run the tests with ``django-admin.py`` directly, make sure
you use ``feedhq.test_settings`` to avoid making network calls while running
the tests.
-If you want to contribute and need an environment more suited for development,
-you can use the ``settings.py`` file to alter default settings. For example,
-to enable the `django-debug-toolbar`_::
-
- from .default_settings import *
-
- # Your regular settings here
-
- MIDDLEWARE_CLASSES += (
- 'debug_toolbar.middleware.DebugToolbarMiddleware',
- )
-
- INTERNAL_IPS = ('127.0.0.1',)
-
- INSTALLED_APPS += (
- 'debug_toolbar',
- )
-
- DEBUG_TOOLBAR_CONFIG = {
- 'INTERCEPT_REDIRECTS': False,
- 'HIDE_DJANGO_SQL': False,
- }
-
-.. _django-debug-toolbar: https://github.com/django-debug-toolbar/django-debug-toolbar
+The Django debug toolbar is enabled when the ``DEBUG`` environment variable is
+true and the ``django-debug-toolbar`` package is installed.
`Foreman`_ is used in development to start a lightweight Django server, run
one `RQ`_ worker and interactively preprocess changes in SCSS files to CSS
-with `Compass`_. A running `Redis`_ server, Ruby, and `Bundler`_ are
-prerequisites for this workflow::
+with `Compass`_. Environment variables are managed using Daemontools'
+``envdir`` utility. A running `Redis`_ server, Ruby, `Bundler`_ and
+`Daemontools`_ are prerequisites for this workflow::
bundle install
make run
@@ -200,7 +171,11 @@ prerequisites for this workflow::
.. _Compass: http://compass-style.org/
.. _Redis: http://redis.io/
.. _Bundler: http://gembundler.com/
+.. _Daemontools: http://cr.yp.to/daemontools.html
When running ``django-admin.py updatefeeds`` on your development machine,
-make sure you have ``DEBUG = True`` in your settings to avoid making
+make sure you have the ``DEBUG`` environment variable present to avoid making
PubSubHubbub subscription requests without any valid callback URL.
+
+Environment variables for development are set in the ``envdir`` directory. For
+tests, they are located in the ``tests/envdir`` directory.
View
1 envdir/ALLOWED_HOSTS
@@ -0,0 +1 @@
+localhost 127.0.0.1
View
1 envdir/DATABASE_URL
@@ -0,0 +1 @@
+postgres://postgres:@localhost:5432/feedhq
View
1 envdir/DEBUG
@@ -0,0 +1 @@
+true
View
1 envdir/DJANGO_SETTINGS_MODULE
@@ -0,0 +1 @@
+feedhq.settings
View
1 envdir/REDIS_URL
@@ -0,0 +1 @@
+redis://localhost:6379/1
View
1 envdir/SECRET_KEY
@@ -0,0 +1 @@
+secret
View
126 feedhq/default_settings.py → feedhq/settings.py
@@ -1,41 +1,54 @@
-# Django settings for feedhq project.
+import dj_database_url
import os
+import urlparse
from django.core.urlresolvers import reverse_lazy
-HERE = os.path.dirname(__file__)
+BASE_DIR = os.path.dirname(__file__)
-DEBUG = False
+DEBUG = os.environ.get('DEBUG', False)
TEMPLATE_DEBUG = DEBUG
# Are we running the tests or a real server?
TESTS = False
TEST_RUNNER = 'discover_runner.DiscoverRunner'
-TEST_DISCOVER_TOP_LEVEL = os.path.join(HERE, os.pardir)
+TEST_DISCOVER_TOP_LEVEL = os.path.join(BASE_DIR, os.pardir)
TEST_DISCOVER_ROOT = os.path.join(TEST_DISCOVER_TOP_LEVEL, 'tests')
-ADMINS = ()
-MANAGERS = ADMINS
+ADMINS = MANAGERS = ()
-TIME_ZONE = 'America/Chicago'
+DATABASES = {
+ 'default': dj_database_url.config(
+ default='postgres://postgres@localhost:5432/feedhq',
+ ),
+}
-LANGUAGE_CODE = 'en-us'
+TIME_ZONE = 'UTC'
-SITE_ID = 1
+LANGUAGE_CODE = 'en-us'
USE_I18N = True
USE_L10N = True
USE_TZ = True
-MEDIA_ROOT = os.path.join(HERE, 'media')
+SITE_ID = 1
+
+MEDIA_ROOT = os.environ.get('MEDIA_ROOT', os.path.join(BASE_DIR, 'media'))
MEDIA_URL = '/media/'
-STATIC_ROOT = os.path.join(HERE, 'static')
+STATIC_ROOT = os.environ.get('STATIC_ROOT', os.path.join(BASE_DIR, 'static'))
STATIC_URL = '/static/'
-STATICFILES_STORAGE = ('django.contrib.staticfiles.storage.'
- 'CachedStaticFilesStorage')
+SECRET_KEY = os.environ['SECRET_KEY']
+
+ALLOWED_HOSTS = os.environ['ALLOWED_HOSTS'].split()
+
+if not DEBUG:
+ STATICFILES_STORAGE = ('django.contrib.staticfiles.storage.'
+ 'CachedStaticFilesStorage')
+
+EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
AUTHENTICATION_BACKENDS = (
'feedhq.backends.RateLimitMultiBackend',
@@ -47,6 +60,8 @@
'django.template.loaders.app_directories.Loader',
)),
)
+if DEBUG:
+ TEMPLATE_LOADERS = TEMPLATE_LOADERS[0][1]
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
@@ -58,6 +73,23 @@
'sekizai.context_processors.sekizai',
)
+parsed_redis = urlparse.urlparse(os.environ['REDIS_URL'])
+path, q, querystring = parsed_redis.path.partition('?')
+CACHES = {
+ 'default': {
+ 'BACKEND': 'redis_cache.RedisCache',
+ 'LOCATION': parsed_redis.netloc,
+ 'OPTIONS': {
+ 'DB': int(path[1:])
+ },
+ },
+}
+
+RQ = {
+ 'eager': bool(urlparse.parse_qs(querystring).get('eager', False)),
+}
+
+
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -66,27 +98,29 @@
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
- 'raven.contrib.django.middleware.Sentry404CatchMiddleware',
)
+if 'SENTRY_DSN' in os.environ:
+ MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + (
+ 'raven.contrib.django.middleware.Sentry404CatchMiddleware',
+ )
+
ROOT_URLCONF = 'feedhq.urls'
TEMPLATE_DIRS = (
- os.path.join(HERE, 'templates'),
+ os.path.join(BASE_DIR, 'templates'),
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
- 'django.contrib.sites',
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.messages',
'django_push.subscriber',
'floppyforms',
- 'raven.contrib.django',
'sekizai',
'django_rq_dashboard',
@@ -96,8 +130,13 @@
'password_reset',
)
+if 'SENTRY_DSN' in os.environ:
+ INSTALLED_APPS += (
+ 'raven.contrib.django',
+ )
+
LOCALE_PATHS = (
- os.path.join(HERE, 'locale'),
+ os.path.join(BASE_DIR, 'locale'),
)
LOGIN_URL = reverse_lazy('login')
@@ -157,3 +196,54 @@
},
},
}
+
+if 'READITLATER_API_KEY' in os.environ:
+ API_KEYS = {
+ 'readitlater': os.environ['READITLATER_API_KEY']
+ }
+
+if 'INSTAPAPER_CONSUMER_KEY' in os.environ:
+ INSTAPAPER = {
+ 'CONSUMER_KEY': os.environ['INSTAPAPER_CONSUMER_KEY'],
+ 'CONSUMER_SECRET': os.environ['INSTAPAPER_CONSUMER_SECRET'],
+ }
+
+if 'READABILITY_CONSUMER_KEY' in os.environ:
+ READABILITY = {
+ 'CONSUMER_KEY': os.environ['READABILITY_CONSUMER_KEY'],
+ 'CONSUMER_SECRET': os.environ['READABILITY_CONSUMER_SECRET'],
+ }
+
+try:
+ import debug_toolbar # noqa
+except ImportError:
+ pass
+else:
+ INTERNAL_IPS = (
+ '127.0.0.1',
+ )
+
+ INSTALLED_APPS += (
+ 'debug_toolbar',
+ )
+
+ MIDDLEWARE_CLASSES += (
+ 'debug_toolbar.middleware.DebugToolbarMiddleware',
+ )
+
+ DEBUG_TOOLBAR_CONFIG = {
+ 'INTERCEPT_REDIRECTS': False,
+ 'HIDE_DJANGO_SQL': False,
+ }
+
+ DEBUG_TOOLBAR_PANELS = (
+ 'debug_toolbar.panels.version.VersionDebugPanel',
+ 'debug_toolbar.panels.timer.TimerDebugPanel',
+ 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
+ 'debug_toolbar.panels.headers.HeaderDebugPanel',
+ 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
+ 'debug_toolbar.panels.template.TemplateDebugPanel',
+ 'debug_toolbar.panels.sql.SQLDebugPanel',
+ 'debug_toolbar.panels.signals.SignalDebugPanel',
+ 'debug_toolbar.panels.logger.LoggingPanel',
+ )
View
12 feedhq/test_settings.py
@@ -1,18 +1,10 @@
import warnings
warnings.simplefilter('always')
-from default_settings import * # noqa
+from .settings import * # noqa
SECRET_KEY = 'test secret key'
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql_psycopg2',
- 'NAME': 'feedhq',
- 'USER': 'postgres',
- },
-}
-
TESTS = True
PASSWORD_HASHERS = [
@@ -40,4 +32,4 @@
LOGGING['loggers']['feedupdater']['level'] = 'ERROR'
LOGGING['loggers']['ratelimitbackend']['level'] = 'ERROR'
-MEDIA_ROOT = os.path.join(HERE, 'test_media')
+MEDIA_ROOT = os.path.join(BASE_DIR, 'test_media')
View
1 requirements.txt
@@ -2,6 +2,7 @@ Django==1.5
Pillow==1.7.8
bleach==1.2.1
django-classy-tags==0.3.4.1
+dj-database-url==0.2.1
django-floppyforms==1.1
django-password-reset==0.4
django-push==0.4
View
1 tests/envdir/ALLOWED_HOSTS
@@ -0,0 +1 @@
+localhost 127.0.0.1
View
1 tests/envdir/DATABASE_URL
@@ -0,0 +1 @@
+postgres://postgres:@localhost:5432/feedhq
View
1 tests/envdir/DJANGO_SETTINGS_MODULE
@@ -0,0 +1 @@
+feedhq.test_settings
View
1 tests/envdir/REDIS_URL
@@ -0,0 +1 @@
+redis://localhost:6379/1?eager=true
View
1 tests/envdir/SECRET_KEY
@@ -0,0 +1 @@
+secret

0 comments on commit 923b1ff

Please sign in to comment.
Something went wrong with that request. Please try again.