constance

Scripts for generating (an earlier obsolete version of) my personal web site
git clone https://code.djc.id.au/git/constance/
commit 4cc6b503efd55f7ead2e6c0ad7e48b93719dbaaa
parent ac080c4bb3ce3c9ed2d7dde3a144c208c328c4f5
Author: Dan Callaghan <djc@djc.id.au>
Date:   Fri,  5 Sep 2008 21:11:19 +1000

parse a config file using ConfigParser, rather than constants in config.py

--HG--
rename : config.py => config.defaults

Diffstat:
MTODO | 1-
Mapp.py | 21++++++++++++++++-----
Mblog.py | 2--
Aconfig.defaults | 33+++++++++++++++++++++++++++++++++
Mconfig.py | 17++++++++++-------
Mtemplates/_commonwrapper.xml | 4----
Mtemplates/_entry.xml | 8++++----
Mtemplates/multiple.xml | 4++--
Mtemplates/multiple_atom.xml | 8++++----
Mviewutils.py | 2--
10 files changed, 69 insertions(+), 31 deletions(-)
diff --git a/TODO b/TODO
@@ -14,5 +14,4 @@
   - entire templates
   ...
 - pings, e.g. http://www.technorati.com/developers/ping/
-- make covers configurable, instead of commented out
 - http://www.pell.portland.or.us/~orc/Code/markdown/ or http://github.com/jgm/peg-markdown/tree/master
diff --git a/app.py b/app.py
@@ -4,7 +4,7 @@
 import os
 import wsgiref.util
 from genshi.template import TemplateLoader
-from colubrid import RegexApplication, HttpResponse, execute
+from colubrid import RegexApplication, HttpResponse
 from colubrid.exceptions import PageNotFound, HttpFound
 from colubrid.server import StaticExports
 
@@ -27,7 +27,9 @@ class Constance(RegexApplication):
     def __init__(self, *args, **kwargs):
         super(Constance, self).__init__(*args, **kwargs)
         self.request.environ['APP_URI'] = wsgiref.util.application_uri(self.request.environ) # Colubrid ought to do this for us
-        self.entries = blog.Entries(config.ENTRIES_DIR, config.READINGLOG_FILE)
+        self.config = config.ConstanceConfigParser(self.request.environ['constance.config_filename'])
+        self.entries = blog.Entries(self.config.getunicode('blog', 'dir'), 
+                self.config.getunicode('readinglog', 'filename'))
 
     def index(self):
         offset = int(self.request.args.get('offset', 0))
@@ -35,6 +37,7 @@ class Constance(RegexApplication):
         format = self.request.args.get('format', 'html')
         if format == 'html':
             rendered = template_loader.load('multiple.xml').generate(
+                    config=self.config, 
                     environ=self.request.environ, 
                     title=None, 
                     sorted_entries=sorted_entries, 
@@ -43,10 +46,11 @@ class Constance(RegexApplication):
             return HttpResponse(rendered, [('Content-Type', 'text/html')], 200)
         elif format == 'atom':
             rendered = template_loader.load('multiple_atom.xml').generate(
+                    config=self.config, 
                     environ=self.request.environ, 
                     title=None, 
                     self_url='%s/' % self.request.environ['APP_URI'], 
-                    sorted_entries=sorted_entries[:config.ENTRIES_PER_PAGE], 
+                    sorted_entries=sorted_entries[:self.config.getint('global', 'entries_per_page')], 
                     feed_updated=sorted_entries[0].modified_date
                     ).render('xml')
             return HttpResponse(rendered, [('Content-Type', 'application/atom+xml')], 200)
@@ -58,6 +62,7 @@ class Constance(RegexApplication):
         try:
             entry = self.entries[id]
             rendered = template_loader.load('single.xml').generate(
+                    config=self.config, 
                     environ=self.request.environ, 
                     entry=entry
                     ).render('xhtml')
@@ -76,6 +81,7 @@ class Constance(RegexApplication):
         format = self.request.args.get('format', 'html')
         if format == 'html':
             rendered = template_loader.load('multiple.xml').generate(
+                    config=self.config, 
                     environ=self.request.environ, 
                     title=u'“%s” tag' % tag, 
                     sorted_entries=sorted_entries, 
@@ -84,10 +90,11 @@ class Constance(RegexApplication):
             return HttpResponse(rendered, [('Content-Type', 'text/html')], 200)
         elif format == 'atom':
             rendered = template_loader.load('multiple_atom.xml').generate(
+                    config=self.config, 
                     environ=self.request.environ, 
                     title=u'“%s” tag' % tag, 
                     self_url='%s/+tags/%s' % (self.request.environ['APP_URI'], tag.encode(self.charset)), 
-                    sorted_entries=sorted_entries[:config.ENTRIES_PER_PAGE], 
+                    sorted_entries=sorted_entries[:self.config.getint('global', 'entries_per_page')], 
                     feed_updated=sorted_entries[0].modified_date
                     ).render('xml')
             return HttpResponse(rendered, [('Content-Type', 'application/atom+xml')], 200)
@@ -96,6 +103,10 @@ class Constance(RegexApplication):
 
 
 if __name__ == '__main__':
+    import sys
+    import wsgiref.simple_server
     app = Constance
     app = StaticExports(app, {'/static': os.path.join(os.path.dirname(__file__), 'static')})
-    execute(app, hostname='0.0.0.0', port=8082)
+    server = wsgiref.simple_server.make_server('0.0.0.0', 8082, app)
+    server.base_environ['constance.config_filename'] = sys.argv[1]
+    server.serve_forever()
diff --git a/blog.py b/blog.py
@@ -5,8 +5,6 @@ import markdown
 import genshi
 import yaml
 
-import config
-
 
 def count(iterable):
     count = 0
diff --git a/config.defaults b/config.defaults
@@ -0,0 +1,33 @@
+[global]
+
+# The name of the blog. Appears at the end of page <title>s.
+name = Untitled
+
+# The name of the author of this blog.
+author = Anonymous
+
+# The author's e-mail address. Leave this blank if you don't want to publish an 
+# e-mail address.
+email = 
+
+# The maximum number of entries (of any kind) to be shown on each page.
+entries_per_page = 20
+
+[blog]
+
+# The directory containing blog entries.
+dir = ./entries
+
+[readinglog]
+
+# The name of the file containing a YAML stream of readinglog entries.
+filename = ./reading_log
+
+# Should LibraryThing covers be shown for readinglog entries?
+# See also librarything_devkey below.
+show_covers = False
+
+# If show_covers is True, you must supply a valid LibraryThing developer key to 
+# be included in cover URLs. You can leave this blank otherwise.
+# See http://www.librarything.com/services/keys.php
+librarything_devkey = 
diff --git a/config.py b/config.py
@@ -2,11 +2,14 @@
 # vim:encoding=utf-8
 
 import os
+from ConfigParser import SafeConfigParser
 
-ENTRIES_DIR = os.path.join(os.path.dirname(__file__), u'entries')
-READINGLOG_FILE = os.path.join(os.path.dirname(__file__), u'reading_log')
-BLOG_NAME = u'djc'
-BLOG_AUTHOR = u'djc'
-BLOG_EMAIL = None
-ENTRIES_PER_PAGE = 20
-LIBRARYTHING_DEVKEY = 'f6da4b15120267233430bb13cdaf1be9'
+class ConstanceConfigParser(SafeConfigParser):
+
+    def __init__(self, filename):
+        SafeConfigParser.__init__(self)
+        self.readfp(open(os.path.join(os.path.dirname(__file__), 'config.defaults'), 'r'))
+        self.readfp(open(filename, 'r'))
+
+    def getunicode(self, section, option):
+        return self.get(section, option).decode('utf8') # XXX make codec configurable?
diff --git a/templates/_commonwrapper.xml b/templates/_commonwrapper.xml
@@ -4,10 +4,6 @@
      xmlns:xi="http://www.w3.org/2001/XInclude"
      py:strip="True">
 
-<?python
-import config
-?>
-
 <span py:def="inline_sep()" class="inlinesep">·</span>
 <div py:def="block_sep()" class="blocksep">~</div>
 
diff --git a/templates/_entry.xml b/templates/_entry.xml
@@ -4,7 +4,7 @@
 	 py:def="show_entry(entry, show_comments=True)">
 
 <?python
-import blog, config
+import blog
 from viewutils import mini_markdown, tag_list
 ?>
 
@@ -59,9 +59,9 @@ from viewutils import mini_markdown, tag_list
 
 <div class="entry readinglog" py:if="isinstance(entry, blog.ReadingLogEntry)">
 
-    <!--img py:if="entry.isbn" class="cover"
-         src="http://covers.librarything.com/devkey/${config.LIBRARYTHING_DEVKEY}/small/isbn/${entry.isbn}" 
-         alt="Cover image for ${entry.title}" /-->
+    <img py:if="config.getboolean('readinglog', 'show_covers') and entry.isbn" class="cover"
+         src="http://covers.librarything.com/devkey/${config.get('readinglog', 'librarything_devkey')}/small/isbn/${entry.isbn}" 
+         alt="Cover image for ${entry.title}" />
 
     <h3 class="entrytitle" id="post-${entry.id}">
         <a py:strip="not entry.url" href="${entry.url}">${mini_markdown(entry.title)}</a>
diff --git a/templates/multiple.xml b/templates/multiple.xml
@@ -10,13 +10,13 @@
 	<title py:if="title">${title}</title>
     <link rel="alternate" type="application/atom+xml" title="Atom feed" href="?format=atom" />
     <link py:if="bool(offset)" rel="prev" href="?offset=${max(0, offset - 20)}" />
-    <link py:if="len(sorted_entries) > offset + config.ENTRIES_PER_PAGE" rel="next" href="?offset=${offset + 20}" />
+    <link py:if="len(sorted_entries) > offset + config.getint('global', 'entries_per_page')" rel="next" href="?offset=${offset + 20}" />
 </head>
 <body>
 
 <h2 class="archives" py:if="title">Archive for the ${title}</h2>
 
-<py:for each="entry in sorted_entries[offset:offset + config.ENTRIES_PER_PAGE]">
+<py:for each="entry in sorted_entries[offset:offset + config.getint('global', 'entries_per_page')]">
     ${show_entry(entry, show_comments=False)}
 </py:for>
 
diff --git a/templates/multiple_atom.xml b/templates/multiple_atom.xml
@@ -4,13 +4,13 @@
 	  xmlns:xi="http://www.w3.org/2001/XInclude">
 
 <?python
-import config, blog
+import blog
 from viewutils import tag_list
 ATOM_TIME_FORMAT = str('%Y-%m-%dT%H:%M:%S+10:00')
 ?>
 
 <id>${self_url}?format=atom</id>
-<title type="text">${config.BLOG_NAME}<py:if test="title"> (${title})</py:if></title>
+<title type="text">${config.getunicode('global', 'name')}<py:if test="title"> (${title})</py:if></title>
 <link rel="self" type="application/atom+xml" href="${self_url}?format=atom" />
 <link rel="alternate" href="${self_url}" />
 <generator>constance</generator>
@@ -21,8 +21,8 @@ ATOM_TIME_FORMAT = str('%Y-%m-%dT%H:%M:%S+10:00')
 	<published>${entry.publication_date.strftime(ATOM_TIME_FORMAT)}</published>
 	<updated>${entry.modified_date.strftime(ATOM_TIME_FORMAT)}</updated>
 	<author>
-		<name>${config.BLOG_AUTHOR}</name>
-		<email py:if="config.BLOG_EMAIL">${config.BLOG_EMAIL}</email>
+		<name>${config.getunicode('global', 'author')}</name>
+		<email py:with="email = config.getunicode('global', 'email')" py:if="email">${email}</email>
 	</author>
 	<category py:for="tag in entry.tags" scheme="${environ['APP_URI']}/+tags/" term="${tag}" />
 	<py:if test="isinstance(entry, blog.Entry)">
diff --git a/viewutils.py b/viewutils.py
@@ -2,8 +2,6 @@ import re
 import markdown
 import genshi
 
-import config
-
 def mini_markdown(s):
     # XXX find a more efficient way to do this?
     m = markdown.Markdown(extensions=['typography']).convert(s)