4 import os
, time
, datetime
5 from os
.path
import join
, abspath
7 from docutils
import core
8 from docutils
.parsers
import rst
9 from docutils
.writers
.html4css1
import Writer
, HTMLTranslator
11 from mako
.template
import Template
12 from mako
.lookup
import TemplateLookup
14 def envride(name
, default
):
15 return os
.environ
.get(name
, default
)
18 rst_dir
= abspath(envride('RSTDIR', './example/')),
19 templates_dir
= abspath(envride('TEMPLATESDIR', './example/')),
20 base_url
= envride('BASEURL', 'http://localhost:8080/') # ends with slash
23 def htmlpath(rst_path
):
24 """Return the .html path for the given .rst path"""
25 assert rst_path
.endswith('.rst'), '<%s> is not a rst path' % rst_path
26 return rst_path
[:-4] + '.html'
31 def __init__(self
, rst_path
):
32 self
.rst_path
= rst_path
34 writer
.translator_class
= DocInfoProxy
# see comment for `DocInfoProxy`
36 parts
= core
.publish_parts(
37 source
=open(rst_path
).read(),
38 source_path
=rst_path
, writer
=writer
)
39 self
.title
, self
.fragment
= parts
['title'], parts
['fragment']
40 self
.meta
= DocInfoProxy
.ITEMS
.copy()
43 path_info
= htmlpath(self
.rst_path
[len(conf
['rst_dir']):])
44 return conf
['base_url'] + path_info
49 if '|' in self
.meta
['date']:
50 format
= '%Y-%m-%d|%M:%S'
54 return datetime
.datetime(
55 *time
.strptime(self
.meta
['date'],
58 def __cmp__(self
, other
):
59 return cmp(self
.date(), other
.date())
62 return '<BlogPost "%s" on %s>' % (self
.title
, self
.date())
65 # This is a temporary hack - to extract the 'custom fields' from
66 # docutil's `docinfo` node.
68 # `HTMLTranslator` happens to process the docinfo tree and so we can steal
69 # the key,value pairs of custom fields from the `visit_field_name` function.
70 class DocInfoProxy(HTMLTranslator
):
74 def __init__(self
, *args
, **kwargs
):
75 HTMLTranslator
.__init
__(self
, *args
, **kwargs
)
76 DocInfoProxy
.ITEMS
= {}
79 # Custom fields are processed here (Tags and so on)
80 def visit_field_name(self
, node
):
81 key
= node
.astext().lower()
82 value
= node
.parent
.children
[1].astext() # from sibling
83 # print 'meta[%s] = {%s}' % (key, value)
84 DocInfoProxy
.ITEMS
[key
] = value
85 return HTMLTranslator
.visit_field_name(self
, node
)
87 # Standard fields are processed here (Date, Author and so on)
88 def visit_docinfo_item(self
, node
, name
, meta
=1):
90 value
= node
.parent
.children
[0].astext() # from sibling
91 # print '*meta[%s] = {%s}' % (key, value)
92 DocInfoProxy
.ITEMS
[key
] = value
93 return HTMLTranslator
.visit_docinfo_item(self
, node
, name
, meta
)
96 def rstfiles(directory
):
97 for dir, subdirs
, files
in os
.walk(directory
):
99 if file.endswith('.rst'):
100 yield abspath(join(dir, file))
103 templates
= TemplateLookup(directories
=[conf
['templates_dir']])
104 def render(name
, **kwargs
):
105 return templates
.get_template(name
).render(**kwargs
)
109 if __name__
== '__main__':
111 blog_path
= abspath(join(conf
['rst_dir'], 'blog'))
112 for f
in rstfiles(conf
['rst_dir']):
115 blog_posts
.append(page
)
120 open(htmlpath(f
), 'w').write(mako('page.mako', **locals()))
122 # generate blog index
125 print 'Blog index:', blog_posts
128 'blog', 'index.html'),
129 'w').write(mako('blog/index.mako', **locals()))