--- /dev/null
+
+===========
+|ForestCMS|
+===========
+
+|ForestCMS| stands for "Filesystem_-Oriented reST_ CMS_" (or
+"Filesystem_-Oriented reStructuredText_ `Content Management System`_" for long
+;).
+
+It's a `Web CMS`_ inspired in the ideas brought by the Hooks_ PHP_ framework
+for content managements and it's intended to make easy to publish contents in
+a filesystem_-oriented way (i.e. use the hierarchical nature of the filesystem_
+to build a tree-like content database). This makes very easy to manage contents
+without a web interface (by just editing files in the filesystem_). A web
+interface can come in the future, though, it just have to manage files in the
+filesystem_ instead of rows in a relational database.
+
+|ForestCMS| is written in Python_, and the content is written in
+reStructuredText_ instead of HTML_. Why? Just because reStructuredText_ is
+great for writing content, and if you *really* need to do some nasty HTML_
+tricks, you can always use the `raw directive`_.
+
+
+
+Quick Test
+==========
+
+If you want to quickly try ForestCMS just run::
+
+ python fcms.py
+
+And point your browser to http://localhost:8000/README to see this very same
+file rendered as HTML_.
+
+
+
+.. |ForestCMS| replace:: **ForestCMS**
+
+.. _PHP: http://www.php.net/
+.. _Python: http://www.python.org/
+.. _reStructuredText:
+.. _reST: http://docutils.sourceforge.net/rst.html
+.. _Hooks: http://hooks.gforge.lug.fi.uba.ar/hooks/docs/html/
+.. _HTML: http://en.wikipedia.org/wiki/HTML
+.. _Filesystem: http://en.wikipedia.org/wiki/Filesystem
+.. _Content Management System:
+.. _CMS: http://en.wikipedia.org/wiki/Content_Management_System
+.. _Web CMS: http://en.wikipedia.org/wiki/Web_Content_Management_System
+.. _raw directive: http://docutils.sourceforge.net/docs/ref/rst/directives.html#raw-data-pass-through
+
--- /dev/null
+# forestcms - Filesystem-Oriented reST CMS
+# Or, for long, Filesystem-Oriented reStrcuturedText Content Management System
+
+from __future__ import with_statement
+
+import errno
+from os import path
+from wsgiref.simple_server import make_server
+from pprint import pprint
+from StringIO import StringIO
+from docutils.core import publish_parts
+import threading
+
+local = threading.local()
+
+class Conf:
+ pass
+
+conf = Conf()
+conf.docroot = '.' # 'docroot'
+conf.sysroot = 'sysroot'
+
+STATUS = {
+ 200: 'OK',
+ 404: 'Not Found',
+}
+
+class HttpError (Exception):
+ def __init__(self, status):
+ self.status = status
+
+def page2fname(page):
+ if not page or page == '/':
+ page = '/index'
+ return path.join(conf.docroot, page[1:]) + '.rst'
+
+def status2rstfile(status):
+ return path.join(conf.sysroot, str(status)) + '.rst'
+
+def render_rst(rst, whole=True):
+ what = 'whole' if whole else 'html_body'
+ content = publish_parts(rst, writer_name="html")[what]
+ return content.encode('utf-8')
+
+def render_file(fname, whole=True):
+ try:
+ with file(fname) as f:
+ rst = f.read()
+ except IOError, e:
+ if e.errno == errno.ENOENT:
+ raise HttpError(404)
+ return render_rst(rst, whole)
+
+def render_page(page, whole=True):
+ fname = page2fname(page)
+ return render_file(fname, whole)
+
+def forestcms(environ, start_response):
+ local.page = environ['PATH_INFO']
+ local.env = environ
+ local.headers = [('Content-type', 'text/html; charset=utf-8')]
+ output = ''
+ try:
+ status = 200
+ output = render_page(local.page)
+ except HttpError, e:
+ status = e.status
+ output = render_file(status2rstfile(status))
+ status = '%s %s' % (status, STATUS[status])
+ start_response(status, local.headers)
+ return [output]
+
+httpd = make_server('', 8000, forestcms)
+httpd.serve_forever()
+