Source of the website http://joequery.me
Python C CSS TeX JavaScript Shell Arduino
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
joequery
.gitignore
LICENSE
README.md
genfeed.py
requirements.txt
restart.sh
runserver.py
uwsgi.ini

README.md

joequery.me source mirror

This repo holds the source of the site http://joequery.me. The site is written in Python2.7 with the aid of the Flask framework.

About this repo: notes on quality

This repo reflects my ideal workflow. The way I like to go about creating articles, storing metadata, or anything else could be completely different than your preferences. My system is not perfect, but it is perfect for me. The code may be of mediocre quality, simply because I would rather spend time writing articles than work on the thing that lets me write articles.

Site features

  • Easy to create static pages
  • File based blogging platform
    • Markdown
    • Static home page/category index pages for speed
    • Automatic sitemap.xml generation
    • Automatic rss feed generation
  • Code snippets can be pulled into articles from files
    • Links to raw snippet sources automatically generated (See example)

Requirements

  • Python2.7
  • virtualenv
  • libxml2-dev
  • libxslt-dev

How to use the site

Installation

$ git://github.com/joequery/joequery.me.git
$ cd joequery.me
$ virtualenv env
$ . env/bin/activate
(env) $ pip install -r requirements.txt

If you recieve any errors during the installation of PyQuery, ensure that libxml2-dev and libxslt-dev are installed on your system.

Now generate the blog index pages and the home page (we explain this later)

(env) $ python genfeed.py
Generated rss.txt
Generated static rss feed
Generated static blog pages
Generated sample posts for the home page
Generated xml sitemap
Generated related posts.txt files
Generated tag index pages
Generated series index pages
(env) $ python runserver.py
* Running on http://0.0.0.0:5000/
* Restarting with reloader

Now head to http://localhost:5000

Creating articles

Posts are located in joequery/blog/posts/. To create an article, copy the template located at joequery/blog/posts/template to one of the article categories (currently code, math, or screencast), and rename it to be the post slug. For example,

$ cd joequery/blog/posts
$ cp -r template code/how-to-use-javascript

You can then visit http://localhost:5000/code/how-to-use-javascript and you will see a generic article. You will not see this newly created article appear on the home page yet, but we will get to that later.

Move to the newly copied directory and examine the meta.txt file.

$ cd code/how-to-use-javascript
$ cat meta.txt
[post]
title: Post Title
description: Post description
time: 2012-12-07 Fri 09:53 PM

The [post] tag must remain on top of the meta.txt file. The title is the post title, the description is the excerpt that will be displayed on the home page and blog index pages. Note: If you want your description to span multiple lines, every line after the first needs to be indented: Example. The time is the publish time, and the time format you see above is the required format. If you're a vim user, you can place the following in your ~/.vimrc to have the F3 key generate a timestamp for you:

" Insert timestamp
nmap <F3> a<C-R>=strftime("%Y-%m-%d %a %I:%M %p")<CR><Esc>
imap <F3> <C-R>=strftime("%Y-%m-%d %a %I:%M %p")<CR>

If you examine the body.html file of the directory we created, you'll see

{% from "macros" import img, blogimg, snippet %} {% set p = post %}
{% extends "templates/post.html" %} {% block post %} {% filter markdown %}

{% endfilter %} {% endblock post %}

You start writing your article in the line left blank. For example,

{% from "macros" import img, blogimg, snippet %} {% set p = post %}
{% extends "templates/post.html" %} {% block post %} {% filter markdown %}

Headline level 2
----------------

This is some content.

### Headline level 3

More content

{% endfilter %} {% endblock post %}

Generating the home page and blog index pages

Since I didn't feel like using a database for the site, I needed a way to have the home page and blog index pages display the most recent articles without reading through the file system every time the home page is requested. My solution was to create a script I would run after

  • Creating a new artile
  • Adding tags/series to an article (will explain soon)
  • Editing a publish time of an article

This script is called genfeed.py, and it's located in the top level directory of the project. To use it, simply make sure the virtualenv is activated and run

(env) $ python genfeed.py

genfeed.py also creates an XML sitemap which can be reached at http://localhost:5000/sitemap as well as an RSS feed which can be reached at http://localhost:5000/feed

Series and tags

Posts can have multiple tags separated by commas specified in their meta.txt files. Currently, tags can only be one word long, but dashes and underscores are okay. For example,

[post]
title: Debugging failed compilations with apt-file
description: A quick tutorial on using apt-file on Ubuntu to solve failed make
    compilations due to missing files.
time: 2012-12-28 Fri 07:05 PM
tags: ubuntu, utilities

The ubuntu and utilities directories need to exist in the /joequery/blog/posts/tags/ directory. We need these directories to be versioned, so I add a .gitkeep file to the tag directories and commit them.

$ cd joequery/blog/posts/tags
$ mkdir ubuntu
$ touch ubuntu/.gitkeep

Posts with tags will automatically list the tags at the bottom of the article. Additionally, every tag has its own index page generated by genfeed.py, such as http://localhost:5000/tag/ubuntu

These tag index pages have the most recent articles on top.

A series is like a tag except a post can only have one series and the series page is ordered with the oldest articles on top. This is useful if you're writing related tutorials that are to be read in a specific order.

A post can have a series and have tags. For example,

[post]
title: Programming Language Design Issues
description: We begin studying programming language design and implementations
    by examining the history of programming languages, the role of programming
    languages, and the details on programming environments.
time: 2013-02-14 Thu 11:22 PM
series: programming-languages-4th-edition
tags: computer-science

For this example, it's necessary to have the directory joequery/blog/posts/series/programming-languages-4th-edition exist, versioned with a .gitkeep file.

Blog images

Suppose we have an article easy-math in the math category. So the path to our article would be joequery/blog/posts/math/easy-math. If we want to include images in our article, we would do the following:

$ cd joequery
$ cd static/images
$ mkdir -p math/easy-math

Now we can place images in the static/math/easy-math directory. Suppose we have "img1.png", "hello.jpg" in the directory, and now we want to have those images appear in our post.

Somewhere in the joequery/blog/posts/math/easy-math/body.html file, we would write

{{blogimg(g,p, "img1.png")|safe}}

This would produce the image tag

<img src="/static/images/math/easy-math/img1.png />

How it works (if you care)

The above is a bit cryptic, so I'll explain what it does. blogimg is what's known as a macro in Jinja2, the default templating system used by Flask. The purpose of this custom macro is to generate an img tag. Jinja2 forces us to declare the returned string of a macro safe to render as html, hence the safe at the end. The first argument, g, represents Flask's global object that we're free to populate with anything. In my case, I populated it with a property called assets. That way I can specify different places for Flask to look for images and static files on production, such as Amazon S3 (Currently I have g.assets set to the joequery/static directory both on development and production, but you can see the joequery/settings.py file where that can easily be changed). The second parameter, p, is a dictionary holding a lot of information about the current post. The last parameter is the name of the file.

Code snippets

What I believe is the most useful feature of my site is the ability to easily embed source files into a post. Very simple code snippets can be written directly to the post just by indenting four spaces. However, when you want to create complex programming examples, it gets cumbersome to extract code you've written on your article, go compile it, edit it, paste it back, and repeat as you find issues. Here was my solution:

Suppose you're working on an article in joequery/blog/posts/code/learn-python. You make an example python file, say learn-lists.py. Place that in the post directory, and then you can call that source file into the post via

{{ snippet(p, "learn-lists.py")|safe}}

Additionally, a link to a plain-text version of the source file (similar to Github's Raw) is automatically generated for you and linked to in the source. This is extremely convenient for people who wish to wget your code snippet onto a server.

In order to avoid worrying about cleaning up .o or .pyc files, an extension whitelist is located in the display_raw_source_file() function in the joequery/blog/routes.py file. I do recommend adding any type of object/bytecode file to your .gitignore, though.

Notes on genfeed.py

No files generated by genfeed.py are versioned. If you're pushing your repo to a production server, be sure to have genfeed.py run afterwards.

Notes on cropping the Jarnal template for blogs:

Resize image: 850xwhatever Canvas size: 675x950