Explorar o código

Add HACKING docs and minor tweaks.

Brit Butler %!s(int64=11) %!d(string=hai) anos
pai
achega
e2e2704a26
Modificáronse 4 ficheiros con 187 adicións e 16 borrados
  1. 141 0
      docs/hacking.md
  2. 39 9
      docs/plugin-api.md
  3. 4 4
      src/coleslaw.lisp
  4. 3 3
      src/config.lisp

+ 141 - 0
docs/hacking.md

@@ -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.

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 39 - 9
docs/plugin-api.md


+ 4 - 4
src/coleslaw.lisp

@@ -78,13 +78,13 @@ Additional args to render CONTENT can be passed via RENDER-ARGS."
78 78
       (update-symlink curr new-build))))
79 79
 
80 80
 (defun main (&optional config-key)
81
-  "Load the user's config file, then compile and deploy the blog."
81
+  "Load the user's config file, then compile and deploy the site."
82 82
   (load-config config-key)
83 83
   (load-content)
84 84
   (compile-theme (theme *config*))
85
-  (let ((blog (staging-dir *config*)))
86
-    (compile-blog blog)
87
-    (deploy blog)))
85
+  (let ((dir (staging-dir *config*)))
86
+    (compile-blog dir)
87
+    (deploy dir)))
88 88
 
89 89
 (defun preview (path &optional (content-type 'post))
90 90
   "Render the content at PATH under user's configured repo and save it to

+ 3 - 3
src/config.lisp

@@ -9,7 +9,7 @@
9 9
    (plugins         :initarg :plugins        :accessor plugins)
10 10
    (repo            :initarg :repo           :accessor repo)
11 11
    (sitenav         :initarg :sitenav        :accessor sitenav)
12
-   (staging-dir     :initarg :staging-dir    :accessor staging-dir)
12
+   (staging-dir     :initarg :staging-dir    :accessor staging-dir    :initform "/tmp/coleslaw/")
13 13
    (posts-dir       :initarg :posts-dir      :accessor posts-dir      :initform "posts")
14 14
    (separator       :initarg :separator      :accessor separator      :initform ";;;;;")
15 15
    (page-ext        :initarg :page-ext       :accessor page-ext       :initform "html")
@@ -40,7 +40,7 @@ are in the plugins folder in coleslaw's source directory."
40 40
       (destructuring-bind (name &rest args) plugin
41 41
         (apply 'enable-plugin (plugin-path name) args)))))
42 42
 
43
-(defun discover-config-path (&optional (path ""))
43
+(defun discover-config-path (path)
44 44
   "Check the supplied PATH for a .coleslawrc and if one
45 45
 doesn't exist, use the .coleslawrc in the home directory."
46 46
   (let ((custom-path (rel-path path ".coleslawrc")))
@@ -48,7 +48,7 @@ doesn't exist, use the .coleslawrc in the home directory."
48 48
         custom-path
49 49
         (rel-path (user-homedir-pathname) ".coleslawrc"))))
50 50
 
51
-(defun load-config (config-key)
51
+(defun load-config (&optional (config-key ""))
52 52
   "Load the coleslaw configuration from DIR/.coleslawrc, using CONFIG-KEY
53 53
 if necessary. DIR is ~ by default."
54 54
   (with-open-file (in (discover-config-path config-key))