|
@@ -0,0 +1,141 @@
|
|
1
|
+## Coleslaw: A Hacker's Guide
|
|
2
|
+
|
|
3
|
+Here we'll provide an overview of key concepts and technical decisions
|
|
4
|
+in *coleslaw* and a few suggestions about future directions. Please
|
|
5
|
+keep in mind that *coleslaw* was written on a lark when 3 friends had
|
|
6
|
+the idea to each complete their half-dreamed wordpress replacement in
|
|
7
|
+a week. Though it has evolved considerably since it's inception, like
|
|
8
|
+any software some mess remains.
|
|
9
|
+
|
|
10
|
+## Core Concepts
|
|
11
|
+
|
|
12
|
+### Data and Deployment
|
|
13
|
+
|
|
14
|
+**Coleslaw** is pretty fundamentally tied to the idea of git as both a
|
|
15
|
+backing data store and a deployment method (via `git push`). The
|
|
16
|
+consequence is that you need a bare repo somewhere with a post-recieve
|
|
17
|
+hook. That post-recieve hook
|
|
18
|
+([example](https://github.com/redline6561/coleslaw/blob/master/examples/example.post-receive))
|
|
19
|
+will checkout the repo to a **$TMPDIR** and call `(coleslaw:main $TMPDIR)`.
|
|
20
|
+
|
|
21
|
+It is then coleslaw's job to load all of your content, your config and
|
|
22
|
+templates, and render the content to disk. Deployment is done by
|
|
23
|
+updating a symlink and the default install assumes your webserver will
|
|
24
|
+be configured to serve from that symlink. However, there are plugins
|
|
25
|
+for deploying to Heroku, S3, and Github Pages.
|
|
26
|
+
|
|
27
|
+### Blogs vs Sites
|
|
28
|
+
|
|
29
|
+**Coleslaw** is blogware. When I designed it, I only cared that it
|
|
30
|
+could replace my server's wordpress install. As a result, the code is
|
|
31
|
+still structured in terms of POSTs and INDEXes. Roughly speaking, a
|
|
32
|
+POST is a blog entry and an INDEX is a collection of POSTs or other
|
|
33
|
+content. An INDEX really only serves to group a set of content objects
|
|
34
|
+on a page, it isn't content itself.
|
|
35
|
+
|
|
36
|
+This isn't ideal if you're looking for a full-on static site
|
|
37
|
+generator. Content Types were added in 0.8 as a step towards making
|
|
38
|
+*coleslaw* suitable for more use cases but still have some
|
|
39
|
+limitations. Chiefly, the association between Content Types, their
|
|
40
|
+template, and their inclusion in an INDEX is presently ad-hoc.
|
|
41
|
+
|
|
42
|
+### Templates and Theming
|
|
43
|
+
|
|
44
|
+User configs are allowed to specify a theme, otherwise the default is
|
|
45
|
+used. A theme consists of a directory under "themes/" containing css,
|
|
46
|
+images, and at least 3 templates: Base, Index, and Post.
|
|
47
|
+
|
|
48
|
+**Coleslaw** exclusively uses
|
|
49
|
+[cl-closure-template](https://github.com/archimag/cl-closure-template)
|
|
50
|
+for templating which is a well documented CL implementation of
|
|
51
|
+Google's Closure Templates. Each template file should be in a
|
|
52
|
+namespace like `coleslaw.theme.theme-name`.
|
|
53
|
+
|
|
54
|
+Each template creates a lisp function in the theme's package when
|
|
55
|
+loaded. These functions take a property list (or plist) as an argument
|
|
56
|
+and return rendered HTML. **Coleslaw** defines a helper called
|
|
57
|
+`theme-fn` for easy access to the template functions.
|
|
58
|
+
|
|
59
|
+### The Lifecycle of a Page
|
|
60
|
+
|
|
61
|
+- `(load-content)`
|
|
62
|
+
|
|
63
|
+A page starts, obviously, with a file. When
|
|
64
|
+*coleslaw* loads your content, it iterates over a list of content
|
|
65
|
+types (i.e. subclasses of CONTENT). For each content type, it
|
|
66
|
+iterates over all files in the repo with a matching extension,
|
|
67
|
+e.g. ".post" for POSTs. Objects of the appropriate class are created
|
|
68
|
+from each matching file and inserted into the `*content*` hash-table.
|
|
69
|
+
|
|
70
|
+- `(compile-blog dir)`
|
|
71
|
+
|
|
72
|
+Compilation starts by ensuring the staging directory (`/tmp/coleslaw/`
|
|
73
|
+by default) exists, cd'ing there, and copying over any necessary theme
|
|
74
|
+assets. Then *coleslaw* iterates over the content types, calling the
|
|
75
|
+`publish` method on each one. Publish creates any non-INDEX pages for
|
|
76
|
+the objects of that content type by iterating over the objects in an
|
|
77
|
+appropriate fashion, rendering them, and passing the result to
|
|
78
|
+`write-page` (which should probably just be renamed to `write-file`).
|
|
79
|
+
|
|
80
|
+After this, `render-indices` and `render-feeds` are called, and an
|
|
81
|
+'index.html' symlink is created to point to the first reverse
|
|
82
|
+chronological index.
|
|
83
|
+
|
|
84
|
+- `(deploy dir)`
|
|
85
|
+
|
|
86
|
+Finally, we move the staging directory to a timestamped path under the
|
|
87
|
+the config's `:deploy-dir`, delete the directory pointed to by the old
|
|
88
|
+'.prev' symlink, point '.curr' at '.prev', and point '.curr' at our
|
|
89
|
+freshly built site.
|
|
90
|
+
|
|
91
|
+## Areas for Improvement
|
|
92
|
+
|
|
93
|
+### Better Content Types
|
|
94
|
+
|
|
95
|
+Creating a new content type should be both straightforward and doable
|
|
96
|
+as a plugin. All that is really required is a subclass of CONTENT with
|
|
97
|
+any needed slots, a template, a `render` method to call the template
|
|
98
|
+with any needed options, a `page-url` method for layout, and a
|
|
99
|
+`publish` method.
|
|
100
|
+
|
|
101
|
+Unfortunately, this does not solve:
|
|
102
|
+
|
|
103
|
+1. The issue of compiling the template at load-time and making sure it
|
|
104
|
+ was installed in the theme package. The plugin would need to do
|
|
105
|
+ this itself or the template would need to be included in 'core'.
|
|
106
|
+2. More seriously, there is no formal relationship between content
|
|
107
|
+ types and indices. Indices include *ALL* objects in the `*content*`
|
|
108
|
+ hash table. This may be undesirable and doesn't permit indices
|
|
109
|
+ dedicated to particular content types.
|
|
110
|
+
|
|
111
|
+### Layouts and Paths
|
|
112
|
+
|
|
113
|
+Defining a page-url for every content-object and index seems a bit
|
|
114
|
+silly. It also spreads information about the site layout throughout
|
|
115
|
+the codebase, it might be better to have a slot in the config that
|
|
116
|
+defines this information with a key to go with each format string.
|
|
117
|
+Adding a new content-type as a plugin could then provide a default
|
|
118
|
+by banging on the config or specify the path in its `enable` options.
|
|
119
|
+
|
|
120
|
+### Incremental Compilation
|
|
121
|
+
|
|
122
|
+Incremental compilation is doable, even straightforward if you ignore
|
|
123
|
+indices. It is also preferable to building the site in parallel as
|
|
124
|
+avoiding work is better than using more workers. Moreover, being
|
|
125
|
+able to determine (and expose) what files just changed enables new
|
|
126
|
+functionality such as plugins that cross-post to tumblr.
|
|
127
|
+
|
|
128
|
+Git's post-receieve hook is supposed to get a list of refs on $STDIN.
|
|
129
|
+A brave soul could update our post-receive script to figure out the
|
|
130
|
+original hash and pass that along to `coleslaw:main`. We could then
|
|
131
|
+use it to run `git diff --name-status $HASH HEAD` to find changed
|
|
132
|
+files and act accordingly.
|
|
133
|
+
|
|
134
|
+This is a cool project and the effects are far reaching. Among other
|
|
135
|
+things the existing deployment model would not work as it involves
|
|
136
|
+rebuilding the entire site. In all likelihood we would want to update
|
|
137
|
+the site 'in-place'. Atomicity of filesystem operations would be a
|
|
138
|
+reasonable concern. Also, every numbered INDEX would have to be
|
|
139
|
+regenerated along with any tag or month indices matching the
|
|
140
|
+modified files. If incremental compilation is a goal, simply
|
|
141
|
+disabling the indices may be appropriate for certain users.
|