Skip to content

decklin/ennepe

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Introduction
============

Ennepe is a simple blogging system which generates static files. You
provide it with some entries, which are stored in an ordinary Maildir, a
layout, which is a directory tree indicating where these entries should
go, and some styles, which are Kid templates that the layout can use to
put pages together.

The layout tree may contain ordinary files, such as images, stylesheets,
or constant pages, and Python scripts, which will be used to generate
variable pages, XML feeds, or anything else you want.

Requirements
============

* Python, at least version 2.5. Ennepe was originally written using 2.3
  and is currently being developed on 2.7. It will be ported to Python 3
  in the future.

* If you want to use reStructuredText to format entries as HTML,
  docutils. This is the default configuration, but you could also
  replace this with PyMarkdown, PyTextile, or nothing at all.

* Kid, available at http://kid.lesscode.org/. This could probably be
  replaced as well, but it would be more work than swapping out reST.

* Something that will allow you to create, add to and edit your Maildir.
  I use procmail and Mutt.

Configuration
=============

An Ennepe blog starts with a configuration file, which is a Python
script. The example provided in ``examples/simple/config.py`` explains
what it can do and what variables can be set. By default, Ennepe looks
for this file in ``~/.ennepe/config.py``.

Usage
=====

To regenerate your blog, simply run ``ennepe``, or, if your config lives
in a different location, ``ennepe path/to/config.py``. By default, only
pages for which the applicable entries or layout have been changed since
the page was last written will be evaluated; you can override this and
rebuild the entire blog with the ``--force`` option. (At the moment,
this is your only recourse if you change your styles.)

Layout
======

Layout scripts are also written in Python; any file with the executable
bit set will be executed and its output will be used to produce the
corresponding output file. Apart from any local variables defined in the
blog's configuration, layouts will be given the following:

* ``muse``: a ``ennepe.mousa.Muse`` object, the thing that generates the
  blog. It contains these attributes (among others, of course, but you
  can safely ignore the rest):

  - ``muse.entries``: the list of all entries in the blog, not just the
    ones you are considering for this page.

  - ``muse.template(name, ...)``: a method that will look up the
    style ``name.kid`` in your configuration's style directory and
    initialize it for you with any keyword arguments provided; in almost
    all cases, you will want to give the style all your local variables
    by specifying ``**locals()``.

* ``entries``: the subset of entries that apply to the particular file
  being generated. In an archive page, for example, this would be only
  the entries in that particular year, week, or whatever. This means all
  such entries, so you will want to choose a subset of them in most
  cases.

Files in the top level directory of your layout will be evaluated with
all the entries in the blog. However, you can create files or
directories with a name like ``__year__``, and it will produce files (or,
in this case, directories) named ``2006``, ``2007``, etc, which will be
evaluated in turn with only the entries for that year.

You can do the same thing for attributes which have multiple values, as
well: for example, a directory named ``__tags__`` will be evaluated for
each tag that appears on an entry, even if the tags are stored as a
list. The directory tree in ``examples/simple/layout`` illustrates how
to do each of these, and a basic Atom feed; you can of course be more
creative.

Entries
=======

The values for all these expansions come from the attributes of ennepe's
Entry class. Several useful ones, such as ``subject`` and ``tags``, are
provided by default: if you wish to define more, you may add a mixin
class to your configuration, with some specially-named methods.
Attributes may be calculated at initialization or only when needed.

When generating file or directory names, the attributes' repr() is used,
so that dates, subject lines, and so on may be appropriately formatted
and linked to. The ``ennepe.utils`` module provides the functions
``clean`` and ``cook``, to make creating useful values easier. This is
just a matter of convention; it is not required, but it does ensure that
all the formatting logic is in one place.

Entry Details
=============

For each entry ``e``, the following attributes (plus any you define) are
available:

* ``msg``: the message that the entry was created from. Initially, only
  the headers have been read; the rest is read when you access
  ``e.content``.

* ``date``: a time-tuple indicating the date on the Date: header.

* ``mtime``: a time-tuple indicating when the message's Maildir file was
  created. This is not the mtime of the file itself! Messing with
  Maildirs by hand is not recommended. To edit an entry, open the
  Maildir in mutt and hit the "e" key on its message.

* ``content``: the body of the entry, processed with reStructuredText.
  Its repr() is the first 100 characters of the unprocessed body
  (suitable for perhaps a summary feed).

* ``subject``: The contents of the Subject header. Its repr() is a
  URL-cleaned (at most 3 words) version of same, with a number appended
  to make each one unique within a given day: 'subject', 'subject-1',
  'subject-2', etc. These are calculated on startup in chronological
  order so that they are always the same.

* ``id``: The Message-Id: header. Its repr() is a tag: URL suitable for
  an Atom feed, as described in
  http://diveintomark.org/archives/2004/05/28/howto-atom-id.

* ``author``: Name from the From: header. Its repr() is the URL-cleaned
  version, in case you want to categorize a multi-author blog by author
  name.

* ``email``: Email address from the From: header. Its repr() is
  something like 'decklin at red dash bean dot com'.

* ``tags``: A list of the contents of the X-Tags: header, split by
  commas. URL-cleaned repr()s for tag categorization.

* ``year``, ``month``, ``day``: What the names imply. The values are
  ints; the repr()s are formatted with ``time.strftime``.

Updating
========

The ``contrib`` directory contains some small scripts to facilitate
updating your blog, and an example of how to put them together so that
your blog can pick up PGP-signed mail at a public email address (or
perhaps ordinary mail at an address internal to your own network) and
automatically rebuild itself upon receipt.

Future and Caveats
==================

I intend to write an SQLite backend once someone complains that it takes
too long to load their 10,000 entries. Be loquacious. At the moment,
however, Ennepe depends on the Maildir really being a Maildir (for
reliable modification times) and the standard ``email`` and ``mailbox``
modules, which are not perfect.

A lot of the more magic stuff may not be particularly good style; where
some clarity or brevity in Ennepe itself could be sacrificed to make the
layout and styles easier to work with, it has been.

About the Name
==============

The word "ennepe" (ἔννεπε) is Ancient Greek for "tell". In the first
line of the Odyssey, "moi ennepe Mousa" ("tell me, Muse") is IMHO most
evocatively translated by Lombardo as "Speak, Memory—"; for this reason,
Ennepe was originally called Mnemosyne (the muse of memory). However,
this name was taken by another free software program which proved to be
more popular.

Author and Copyright
====================

Copyright 2006-2012 Decklin Foster <decklin@red-bean.com>. This program
is free software; please see LICENSE for terms and conditions.

About

Static Python/Kid weblog generator with Maildir store

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages