Migrate config system to YamlSettings

This commit is contained in:
Noah 2015-07-09 22:46:51 -07:00
parent a994d37a9e
commit dcba91c0c1
5 changed files with 185 additions and 226 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Don't check in site specific settings. # Don't check in site specific settings.
settings.ini settings.ini
settings.yml
# Compiled Python # Compiled Python
*.pyc *.pyc

View File

@ -1,195 +0,0 @@
# Default configuration settings for Rophako - DO NOT EDIT THIS FILE!
#
# To configure your site, create a new file named "settings.ini" and override
# settings defined in this file. Your settings.ini is masked on top of the
# settings in defaults.ini.
#
# String values can substitute the following special variables:
# %(_basedir): The absolute path to the root of this git repository, such that
# ./rophako/app.py exists.
# %(_year): inserts the current year (for the RSS feed copyright setting)
#
# You can also define custom global variables in the [DEFAULT] section.
# Variables in this section are injected into ALL other sections, so it's
# recommended to prefix these with an underscore to avoid any conflicting names.
#
# See the Python documentation for ConfigParser if you have any questions
# on the syntax of this file.
# Constants that may be useful in this file.
[DEFAULT]
_admin_email = root@localhost
_date_format = %A, %B %d %Y @ %I:%M:%S %p
# "Weekday, Month dd yyyy @ hh:mm:ss AM"
#------------------------------------------------------------------------------#
# General Website Settings #
#------------------------------------------------------------------------------#
[site]
# Debug mode for development only!
debug = false
# Unique name of your site, e.g. "kirsle.net"
site_name = example.com
# Path to your site's HTML root. Whenever Rophako tries to render a
# template, it will check in your site's root for the template first before
# defaulting to the default fallback pages in the rophako/www folder. All
# of the core Rophako pages, e.g. for account, blog, photo albums and so on,
# have templates in the default site. You can override those templates by
# creating files with the same paths in your site's HTML folder.
site_root = %(_basedir)s/site/www
# E-mail address for site notifications (e.g. new comments and exceptions)
notify_address = %(_admin_email)s
# Where to save temp files for photo uploads etc.
tempdir = /tmp
#------------------------------------------------------------------------------#
# Database settings #
#------------------------------------------------------------------------------#
[db]
# Rophako uses a flat file JSON database system, and a Redis server sits
# between Rophako and the filesystem. The db_root is the path on the
# filesystem to store documents in (can be relative, default "./db")
db_root = db
redis_host = localhost
redis_port = 6379
redis_db = 0
redis_prefix = rophako:
#------------------------------------------------------------------------------#
# Security Settings #
#------------------------------------------------------------------------------#
[security]
# Set this value to true to force SSL/TLS use on your web app. Turning
# this on will do the following:
# - Send HTTP Strict-Transport-Security header
# - Use secure session cookies
force_ssl = false
# Secret key used for session cookie signing. Make this long and hard to
# guess.
#
# Tips for creating a strong secret key:
# $ python
# >>> import os
# >>> os.urandom(24)
# '\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
#
# Then take that whole quoted string and paste it right in as the secret
# key! Do NOT use that one. It was just an example! Make your own.
secret_key = for the love of Arceus, change this key!
# Password strength: number of iterations for bcrypt password.
bcrypt_iterations = 12
#------------------------------------------------------------------------------#
# Mail Settings #
#------------------------------------------------------------------------------#
[mail]
# method = smtp or sendmail (not yet implemented)
method = smtp
server = localhost
port = 25
sender = Rophako CMS <no-reply@rophako.kirsle.net>
#------------------------------------------------------------------------------#
# Plugin Configurations #
#------------------------------------------------------------------------------#
###
# Emoticons
###
# Emoticon theme used for blog posts and comments. Should exist at the URL
# "/static/smileys" from your document root, and have a file named
# "emoticons.json" inside. If you add a custom theme to your private site
# folder, then also change EMOTICON_ROOT_PRIVATE to look there instead.
[emoticons]
theme = tango
root_private = %(_basedir)s/rophako/www/static/smileys
###
# Blog
###
[blog]
default_category = Uncategorized
default_privacy = public
time_format = %(_date_format)s
allow_comments = true
entries_per_page = 5
# RSS feed settings.
title = Rophako CMS Blog
link = http://rophako.kirsle.net/
language = en
description = The web blog of the Rophako CMS.
copyright = Copyright %(_year)s
webmaster = %(_admin_email)s
image_title = Rophako CMS Blog
image_url = //www.kirsle.net/static/avatars/default.png
image_width = 100
image_height = 100
image_description = Rophako CMS
entries_per_feed = 5
###
# Photo
###
[photo]
# The path to where uploaded photos will be stored.
# The PRIVATE path is from the perspective of the server file system.
# The PUBLIC path is from the perspective of the web browser via HTTP.
root_private = %(_basedir)s/site/www/static/photos
root_public = /static/photos
default_album = My Photos
time_format = %(_date_format)s
# Max widths for photo sizes
width_large = 800
width_thumb = 256
width_avatar = 96
###
# Comment
###
[comment]
time_format = %(_date_format)s
# We use Gravatar for comments if the user provides an e-mail address.
# Specify the URL to a fallback image to use in case they don't have
# a gravatar.
default_avatar =
###
# Wiki
###
[wiki]
default_page = Main Page
time_format = %(_date_format)s
#------------------------------------------------------------------------------#
# List of Enabled Plugins #
#------------------------------------------------------------------------------#
[plugins]
# Which plugins to enable? List each plugin by module name. The plugins
# will be assumed to be blueprints that can be attached to the main app
# object. If you instead want to load an arbitrary Python module (i.e. to
# define custom routes at the app layer, not in a blueprint) list those
# under the "custom" section (remove the empty array [] and list them
# like shown in the plugins section).
blueprints =
rophako.modules.blog
rophako.modules.wiki
rophako.modules.photo
rophako.modules.comment
rophako.modules.emoticons
rophako.modules.contact
# rophako.modules.tracking
custom =

161
defaults.yml Normal file
View File

@ -0,0 +1,161 @@
# Default configuration settings for Rophako -- DO NOT EDIT THIS FILE!
#
# To configure your site, create a new file named "settings.yml" and override
# settings defined in this file. Your settings.yml is masked on top of the
# settings in defaults.yml.
rophako:
###
# General Website Settings
###
site:
debug: false
# Unique name of your site, e.g. "kirsle.net"
site_name: example.com
# Path to your site's HTML root. Whenever Rophako tries to render a
# template, it will check in your site's root for the template first
# before defaulting to the fallback pages in the rophako/www folder.
# All of the core Rophako pages, e.g. for account, blog, photo albums
# and so on, have templates in the default site. You can override those
# templates by creating files with the same paths in your site's root.
site_root: "{basedir}/site/www"
# E-mail address for site notifications (e.g. new comments and errors)
notify_address: &ADMIN_EMAIL root@localhost
# Default date/time format (not used by the Rophako app but referenced
# by other spots in this config file, for easy overriding).
_date_format: &DATE_FORMAT '%A, %B %d %Y @ %I:%M:%S %p'
# Where to save temp files for photo uploads etc.
tempdir: /tmp
###
# Database settings
###
db:
# Rophako uses a flat file JSON database system, and a Redis server sits
# between Rophako and the filesystem. The db_root is the path on the
# filesystem to store documents in (can be relative, default "./db")
db_root: db
# Redis connection settings
redis_host: localhost
redis_port: 6379
redis_db: 0
redis_prefix: "rophako:"
###
# Security Settings
###
security:
# Set this value to true to force SSL/TLS on your web app. Turning this on
# will do the following:
# - Send HTTP Strict-Transport-Security header
# - Use secure session cookies (SSL-only)
force_ssl: true
# Secret key used for session cookie signing. Make this long and hard to
# guess.
#
# Tips for creating a strong secret key:
# $ python
# >>> import os
# >>> os.urandom(24)
# '\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
#
# Then take that whole quoted string and paste it right in as the secret
# key. Do NOT use that one, it was just an example. Make your own!
secret_key: 'for the love of Arceus, change this key!'
# Password strength: number of iterations for bcrypt password.
bcrypt_iterations: 12
###
# Mail Settings
###
mail:
method: smtp # or sendmail (not implemented yet)
server: localhost
port: 25
sender: Rophako CMS <no-reply@rophako.kirsle.net>
###
# Plugin Configurations
###
emoticons:
# Emoticon theme used for blog posts and comments. Should exist at the URL
# "/static/smileys" from your document root, and have a file named
# "emoticons.json" inside. If you add a custom theme to your private site
# folder, then also change the root_private to look there instead.
theme: tango
root_private: "{basedir}/rophako/www/static/smileys"
blog:
default_category: Uncategorized
default_privacy: public
time_format: *DATE_FORMAT
allow_comments: true
entries_per_page: 5
# RSS feed settings
title: Rophako CMS Blog
link: http://rophako.kirsle.net/
language: en
description: The web blog of the Rophako CMS.
copyright: "Copyright {year}"
webmaster: *ADMIN_EMAIL
image_title: Rophako CMS Blog
image_url: https://www.kirsle.net/static/avatars/default.png
image_width: 100
image_height: 100
image_description: Rophako CMS
entries_per_feed: 5
photo:
# The path to where the uploaded photos will be stored.
# The PRIVATE path is from the perspective of the server file system.
# The PUBLIC path is from the perspective of the web browser via HTTP.
root_private: "{basedir}/site/www/static/photos"
root_public: /static/photos
default_album: My Photos
time_format: *DATE_FORMAT
# Max widths for photo sizes
width_large: 800
width_thumb: 256
width_avatar: 96
comment:
time_format: *DATE_FORMAT
# We use Gravatar for comments if the user provides an e-mail address.
# Specify the URL to a fallback image to use in case they don't have
# a gravatar.
default_avatar:
wiki:
default_page: Main Page
time_format: *DATE_FORMAT
###
# List of Enabled Plugins
###
# Which plugins to enable? List each plugin by module name. The plugins
# will be assumed to be blueprints that can be attached to the main app
# object. If you instead want to load an arbitrary Python module (i.e. to
# define custom routes at the app layer, not in a blueprint) list those
# under the "custom" section.
blueprints:
- rophako.modules.blog
- rophako.modules.wiki
- rophako.modules.photo
- rophako.modules.comment
- rophako.modules.emoticons
- rophako.modules.contact
# If adding custom scripts, remove the empty array and define a list like
# in the above blueprints example.
custom: []

View File

@ -8,3 +8,4 @@ Markdown
Pygments Pygments
attrdict attrdict
gunicorn gunicorn
yamlsettings

View File

@ -5,58 +5,49 @@ import os
import datetime import datetime
from attrdict import AttrDict from attrdict import AttrDict
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from yamlsettings import YamlSettings
from rophako.plugin import load_plugin from rophako.plugin import load_plugin
# Get the base directory of the git root. # Get the base directory of the git root.
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)) basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
# https://github.com/bcj/AttrDict/issues/20
if not hasattr(AttrDict, "copy"):
setattr(AttrDict, "copy", lambda self: self._mapping.copy())
class ConfigHandler(object): class ConfigHandler(object):
settings = None settings = None
def load_settings(self): def load_settings(self):
"""Load the settings files and make them available in the global config.""" """Load the settings and make them available in the global config."""
self.settings = ConfigParser(dict_type=AttrDict) settings_file = os.environ.get("ROPHAKO_SETTINGS", "settings.yml")
project_settings = YamlSettings("defaults.yml", settings_file,
default_section="rophako")
self.settings = project_settings.get_settings()
# Set dynamic default variables. # Extrapolate {basedir} in certain keys.
self.settings.set("DEFAULT", "_basedir", basedir) # TODO: find a better way...
self.settings.set("DEFAULT", "_year", str(datetime.datetime.now().strftime("%Y"))) self.site.site_root = self.site.site_root.format(basedir=basedir)
self.emoticons.root_private = self.emoticons.root_private.format(
# Read the defaults and then apply the custom settings on top. basedir=basedir
settings_file = os.environ.get("ROPHAKO_SETTINGS", "settings.ini") )
self.settings.read(["defaults.ini", settings_file]) self.photo.root_private = self.photo.root_private.format(basedir=basedir)
def print_settings(self): def print_settings(self):
"""Pretty-print the contents of the configuration as JSON.""" """Pretty-print the contents of the configuration."""
for section in self.settings.sections(): print self.settings
print "[{}]".format(section)
for opt in self.settings.options(section):
print "{} = {}".format(opt, repr(self.settings.get(section, opt)))
print ""
def load_plugins(self): def load_plugins(self):
"""Load all the plugins specified by the config file.""" """Load all the plugins specified by the config file."""
for plugin in self.plugins.blueprints.split("\n"): for plugin in self.blueprints:
plugin = plugin.strip() plugin = plugin.strip()
if not plugin: if not plugin: continue
continue
load_plugin(plugin) load_plugin(plugin)
for custom in self.plugins.custom.split("\n"): for custom in self.custom:
custom = custom.strip() custom = custom.strip()
if not custom: if not custom: continue
continue
load_plugin(custom, as_blueprint=False) load_plugin(custom, as_blueprint=False)
def __getattr__(self, section): def __getattr__(self, section):
"""Attribute access for the config object. """Attribute accessor for the config object. Acts as a simple pass-thru
to YamlSettings."""
You can access config settings via Config.<section>.<name>, for example return getattr(self.settings, section)
Config.site.notify_email and Config.blog.posts_per_page. All results are
returned as strings per ConfigParser, so cast them if you need to."""
return AttrDict(dict(self.settings.items(section)))
Config = ConfigHandler() Config = ConfigHandler()