Ramblings of General Geekery

Article drafts in PieCrust

A common feature of a blog engine is to let the user work on an article for a while before actually publishing it. Thanks to pagination filtering, it’s pretty easy to do in PieCrust.

All you have to do is add the following to your blog’s home page’s configuration header:

posts_filters:
    not:
        has_tags: draft

This will skip any post that has the draft tag.

You will probably need to add some similar filtering to other pages such as the _tag or _category pages.

Edit: as Keilaron mentioned in the comment, you can’t modify the filters on a tag or category listing page, because their filters are preset to, well, filtering posts with a specific tag or category. This means that, unfortunately, you should not actually tag/categorize your drafts.

Edit 2: as of PieCrust 1.0, it’s possible to use a posts_filters on the _tag or _category pages, so it’s all good!


Fresh PieCrust available

I just pushed version 0.1.2 of PieCrust, the lovely static website generator that powers this blog, and most of my other websites.

Pie, anyone?

Yep, the version was bumped from 0.0.4 to 0.1.2. The main reason is that I very heavily refactored the code to make it a lot more readable and maintanable. This also means a whole new batch of bugs are lurking in the dark!

The main change for users is that there’s no _chef directory anymore. It’s all a lot cleaner, with everything living in _piecrust. Just be sure to delete your old directories before getting the new ones, so you don’t have old junk lying around. This also means that you need to (slightly) change your bootstraping code for running PieCrust. If you didn’t customize anything, you can just grab the new index.php from the sample website and overwrite your own. If not, you may want to check out the updated documentation on PieCrust bootstraping.

Among the new features, you’ll find:

If you want to see what’s planned in the future, there’s also a brand new public
Trello project board
.

Finally, check out the slightly redesigned and reorganized PieCrust website!


New PieCrust features

After several release candidates1 , I finally updated PieCrust to version 0.0.4.

Pie

There are quite a few nice new things in it:

  • pattern-based ability to skip files from baking
  • pagination filtering
  • multi-tag pages
  • multi-blog support
  • various bug fixes and optimizations

More details after the break.

“Skip patterns” for the baker

As part of the ongoing PieCrust cookbook, I blogged about previewing a baked site in IIS or Apache. Back then I mentioned how just one piece was missing to make it simpler: the ability to specify a pattern for files to exclude from baking. Well, I did just that.

Now, in your site configuration, you can specify an array of skip_patterns in the baker category. See the documentation for more info.

Pagination filtering

If you have a page that displays a list of posts, you can now do some custom filtering for those posts. In that page’s configuration header, add a section called posts_filters like such:

posts_filters:
    has_tags: piecrust
    has_tags: cookbook

This will only list blog posts that have both the “piecrust” and “cookbook” tags. This is useful for example if you only want to display important annoucements on your homepage, and have a separate “news” page with all the posts.

For more info, check out the documentation on pagination.

Multi-tag pages

Edit: in PieCrust 1.0RC and above, the multi-tags syntax changed!

PieCrust can generate tag pages, like for example the page listing all my posts related to PieCrust. However, if you want to generate a page that shows all the posts related to the PieCrust cookbook, you would have to specify two tags ("piecrust" and “cookbook”)… that is, assuming you really didn’t want to create specific “piecrust-cookbook” tag.

This is now possible by separating tags with a / like so: cookbook/piecrust. Try it!

If you’re using Twig, the default template engine, or Dwoo, one of the optional ones, it means you can use the pctagurl like so:

{{ pctagurl('cookbook/piecrust') }}

The only limitation is when you bake your site: only tag combinations that you insert with the Twig or Dwoo pctagurl functions will be baked. Since you should always insert links with the pc* functions, it should be all right, but you may want to link to a tag combination from outside your website. If that’s the case, you can specify custom tag combinations to be baked. Check the documentation for more details.

Multi-blog support

PieCrust now also supports multiple blogs in the same website. I debated with myself for quite a long time before adding this feature. On one hand, it felt a bit too complicated for a system that’s supposed to feel simple and natural, but on the other hand, well, I needed it. And after much pondering, I figured out a way to make it rather simple to the user. I think. Maybe. Hopefully.

Anyway, if you have a single-blog site, you don’t have to change anything (yay!). If you want more than one blog… go check out the documentation on multi-blog sites!

Other changes

Other changes include a more clever cache validation mechanism, some new debugging features, and many bug fixes.


  1. a.k.a: Ludovic doesn’t test his shit enough before applying a version tag. ↩︎


Using Mercurial to publish a PieCrust website

These days, all the cool hipster kids want to deploy stuff by pushing a Git or Mercurial repository up to their server.

And that’s pretty cool indeed, because you basically update your website by doing something like:

hg push myserver

So here’s how you can do it with PieCrust (although 90% of this article has nothing to do with PieCrust):

  1. Installing Git/Mercurial/whatever on your server
  2. Setting up your SSH keys
  3. Pushing your repository
  4. Defining hooks/triggers

Keep reading for the meaty details…

I’m going to use Dreamhost as the hosting provider in this pseudo-tutorial, but most of the information would be valid for another provider.

Installing the DSCM on your server

As far as I can tell, Git is installed on most servers at Dreamhost, so that’s already taken care of.

For Mercurial, they seem to have a super old version so you may want to install a more recent one yourself. It’s actually pretty easy since the steps are described on their community wiki. In my case, it boiled down to:

  1. mkdir -p ~/srcs
  2. cd ~/srcs
  3. wget http://mercurial.selenic.com/release/mercurial-1.7.5.tar.gz
  4. tar xvzf mercurial-1.7.5.tar.gz
  5. cd mercurial-1.7.5
  6. make local
  7. make install-home-bin

And then adding the new paths to my ~/.bash_profile and ~/.bashrc:

export PYTHONPATH=~/lib/python
export PATH=~/bin:$PATH

Setting up your SSH keys

If you’re using BitBucket or GitHub, you probably already have some SSH keys lying around somewhere. If not, then, well, create an account at either one (depending on whether you use Mercurial or Git). Not only are those websites super useful, but they can also help you (somewhat) with setting up an SSH access:

The Git help pages are way better than the Mercurial ones, so even if you don’t like Git you may want to check them out if you’re lost.

If your SSH access works with Git/Mercurial, then enable password-less login on your Dreamhost account (you basically just need to copy/paste your public key into an ~/.ssh/authorized_keys file… this should work on any other Unix-based host). This will make things super smooth in the future.

Pushing your repository to Dreamhost

Create a directory in your Dreamhost home to store your repository. For example, with Mercurial:

  1. mkdir -p ~/hg/myproject
  2. cd ~/hg/myproject
  3. hg init .

Now back on your local machine, in your local repository, edit the .hg/hgrc file with:

[paths]
dreamhost = ssh://yourlogin@yourdomain.ext/hg/myproject

If you type hg push dreamhost, it should all work! If not… well… go back to the beginning and start again.

Things would look very similar with Git, and you should be able to do it yourself since you’re already a Git user!

Setting up hooks/triggers

Now’s the time to do actual work. The idea is to run a custom script on your server when you push updates to the repository you have up there.

For example, on the Dreamhost server and using Mercurial, you can edit the ~/hg/myproject/.hg/hgrc file and add:

[hooks]
changegroup = ~/scripts/bake_site.sh

Now you only need to write the actual script bake_site.sh! You probably want something that does:

  1. Export the repository into a temporary folder.
  2. Bake your site in that temporary folder.
  3. If all went well, copy the baked site into your home.
  4. Clean up.

This would look something like:

#!/bin/sh

set -e

HG_REPO_DIR=~/hg/myproject
ARCHIVE_DIR=~/tmp/hg_archival
PUBLIC_DIR=~/yourdomain.com

# Archive (export) the repo.
echo "Archiving repository to ${ARCHIVE_DIR}"
if [ -d ${ARCHIVE_DIR} ]; then
    rm -fr ${ARCHIVE_DIR}
fi
mkdir -p ${ARCHIVE_DIR}
hg archive -r tip ${ARCHIVE_DIR}

# Bake your website
mkdir -p ${ARCHIVE_DIR}/baked
${ARCHIVE_DIR}/_piecrust/chef bake -r http://yourdomain.com/ -o ${ARCHIVE_DIR}/baked ${ARCHIVE_DIR}/mywebsite

# Move baked website into the public directory.
echo "Copying website to ${PUBLIC_DIR}"
cp -R ${ARCHIVE_DIR}/baked/* ${PUBLIC_DIR}

# Clean up.
echo "Cleaning up"
rm -fr ${ARCHIVE_DIR}

But don’t use that script!

Obviously it won’t work for you unless you change a lot of directory names, tweak the options for chef, etc. But it should be a good starting point.

  • I recommend you test your script by first running it manually while logged in via SSH, and after changing the PUBLIC_DIR to some temporary directory. You’ll probably get it wrong a couple times at first, especially if you’re quite rusty with Bash syntax like me.
  • When it’s working as expected, do a repository push and check that the script is baking everything correctly in the temporary directory.
  • If that’s all good, then you can revert PUBLIC_DIR back to its intended path.

Now you can enjoy your new coolness: hg push dreamhost!


Enabling Disqus’ developer mode

This is the second post of a series of things I learned while using PieCrust.

From the Disqus documentation:

[You can tell] the Disqus service that you are testing the system on an inaccessible website, e.g. secured staging server or a local environment. If disqus_developer is off or undefined, Disqus’ default behavior will be to attempt to read the location of your page and validate the URL. If unsuccessful, Disqus will not load. Use this variable to get around this restriction while you are testing on an inaccessible website.

Assuming you will be baking your final website, you basically want this disqus_developer variable to be enabled if you’re not baking (i.e. you let PieCrust server each page dynamically), or if you’re baking from the chef server. And because both the baker and the server define variables you can access from your templates and pages, you can write this:

{% if not baker.is_baking or server.is_hosting %}{{ disqus.dev() }}{% endif %}

That’s assuming you’re using the default template engine (Twig), and that you have a disqus.dev macro defined somewhere in your template paths with the following code:

{% macro dev() %}
<script type="text/javascript">
    var disqus_developer = 1;
</script>
{% endmacro %}

Previewing a baked site in IIS/Apache

This is the first post of a series of things I learned while using PieCrust.

If you’re using PieCrust as a static website generator, you know you can use the built-in development server to preview your site as you’re modifying it. This is all pretty nice but there are plenty of good reasons to not go that way, the top ones being:

  1. The development server doesn’t run any custom scripts you may have.
  2. IIS, Apache and all the other well-known web-servers are faster and more robust.
  3. You can’t use special features like .htaccess or web.config settings.

If you went with the recommended directory structure for your site, you will have all your content in a _kitchen directory ready to be baked into your final website. But this _kitchen directory really looks a lot like a regular PieCrust website when PieCrust is used as a lightweight CMS. The only difference is that there’s no main index.php file, and that you may be using some file processors.

If you create an index.php file to bootstrap the _kitchen website, it would get deployed to your export directory when you bake your site, so you need to do one of the following:

  • Write some PHP wrapper to the chef baking utility to exclude that file from baking (you can pass a “skip_pattern” parameter to the baker class). I’ll try to make it easier to add exclude rules to chef in the near future, but at the moment you would need to write some code. Not ideal.
  • Rename the bootstrap file _index.php, since all files or directories with a leading underscore in their names are excluded. Now, however, you will need to edit your .htaccess or web.config to add _index.php as a default document, but that’s really just one line of text or a couple clicks. That’s the solution I use.

If you use file processors, you may have to work around them, which may not be possible. I myself only use the LESS CSS processor, and it’s easy to avoid it because LESS comes with a client-side Javascript processor. The trick is now to switch between the client and server side processors, which can be done with a few Twig macros:

{% macro stylesheet(baker, path, media) %}
{% if baker.is_baking %}
<link rel="stylesheet" href="{{ path }}.css" type="text/css" media="{{ media|default('all') }}" />
{% else %}
<link rel="stylesheet/less" href="{{ path }}.less" type="text/css" media="{{ media|default('all') }}" />
{% endif %}
{% endmacro %}

This macro emits a reference to a stylesheet that points to the standard CSS file if the website is currently being baked (which means the server-side processor will run to generate that CSS file), or points to the LESS file itself otherwise (which means the processor will run on the client).

{% macro less_js(baker, site_root) %}
{% if not baker.is_baking %}
<script src="{{ site_root }}js/less-1.0.41.min.js" type="text/javascript"></script>
{% endif %}
{% endmacro %}

This second macro adds the client-side processor to your page if the baker is not running.

Now you just need to call those macros from your template file(s):

{{ less.stylesheet(baker, site.root ~ 'styles/my-awesome-stylesheet', 'screen, projection') }}
{{ less.less_js(baker, site.root) }}

Update (PieCrust >= 0.0.3)

Recent versions of PieCrust have, at last, the ability to define which files should be excluded from baking. This means you can rename the bootstrap file back to index.php if you wish, and exclude it from the bake along with any .htaccess or web.config:

baker:
    skip_patterns:
        - /^_/
        - index.php
        - .htaccess
        - web.config

This is much better!


Working with Disqus

Since I’ve migrated this blog to PieCrust and all its comments to Disqus I’ve run into a few problems that took me some time to figure out (although I got help from the nice Disqus guys). Those problems come down to the following information which was not quite clear to me even after reading their documentation several times:

  • The disqus_identifier value gives a unique name to a thread.
  • The disqus_location value indicates the URL(s) at which a given thread can be found.
  • A thread can be used by several URLs, but no URL can be used by more than one thread.

The first 2 points are pretty straightforward, but that last one was the tricky one. Basically (at the time of this writing, obviously) if you have 2 threads with 2 correctly unique identifiers that were created both with the same URL, your page at that URL will show all kinds of weird behaviours, from never loading any comments (you get the “Disqus loading” icon animation) to loading one of the thread regardless of what disqus_identifier you specified on that page. You would think that identifier would, well, identify exactly what thread you wanted to display, but no, the URL from which it is loaded apparently also plays an important role.

This means, for example, that you can’t display more than one thread on a single page, although the Disqus guys told me this limitation will be removed in a few months.

Another little thing to look for is the subtle distinction between http://example.com/some/url and http://example.com/some/url/ (note the trailing slash character at the end of the second URL). Those URLs are effectively different, as far as Disqus is concerned. This is especially important for statically generated websites since the actual URL of a page or post is http://example.com/some/url/index.html, so there could be at least 3 correct ways to access the same page. Hopefully, as long as you don’t have some weird address collision, you won’t run into the problem mentioned above (which I ran into because I was messing around with the very handy Disqus Python bindings to batch rename and re-identify my threads).

Hopefully this will save somebody some head-scratching.


Announcing PieCrust

You may have noticed that this blog has changed its look, and has migrated its comments to Disqus. You may also see at the bottom of the page something about some pie crust baking… here’s what’s happening.

I have a few websites around and most of them don’t have much in them (e.g. I use the domain name for other things). There’s clearly not enough content to use a proper CMS, but there’s a bit too much repetition for my tastes if I write HTML files by hand. Also, I wanted to take advantage of libraries like Markdown or SmartyPants to make my text look nice with no effort. Basically, I needed some micro-CMS that would handle some basic layout and formatting.

Then there was the issue of this blog. It was running with WordPress, which I’m very happy with usually, but it wasn’t geeky enough. Also, syntax highlighting for code snippets felt dirty and over-complicated. I stumbled upon the whole “static site generation” underground scene and figured I could find something in between: a micro-CMS (for my small sites) that could also bake its own contents into static HTML files (for this blog).

Enter PieCrust.

There was already a shitload of static website generators, but none that could also work as a “dynamic” micro-CMS. Also, I’m a programmer geek, so it’s kind of my duty to not be happy with existing solutions and write one myself (“this one uses curly braces, but I want to use brackets instead! Surely now I have to write my own!). Anyway, isn’t the whole point of home projects to write stuff for yourself, to learn something new or just have fun with a new subject, regardless of whether it’s productive? I was bored, too.

I ended up writing PieCrust in PHP not because I like PHP (it mostly sucks), but because it’s still the most widely used web application language out there. And also because I’ve already got other home projects aimed at having fun with Python and Ruby.

So there you have it, go check out PieCrust. The code is on BitBucket, and mirrored on GitHub.