Commit c37fe01d authored by Marien Fressinaud's avatar Marien Fressinaud

tec: Reorganize the file structure

parents 5d2ca30d 9eb9c2a8
......@@ -32,60 +32,66 @@ $ source ~/.bashrc
## Usage
First, create a project directory:
First, create a project and execute the Boop! command:
$ mkdir my-website && cd my-website
Create a `./content` folder and execute the Boop! command:
$ mkdir content
$ echo '<h1>Welcome!</h1>' > content/index.html
$ echo '<h1>Welcome!</h1>' > index.html
Now, you should have your "production-ready" website under a `./output` folder.
For example, if your website consists in a single `index.html` page, you should
obtain the following structure:
Now, you should have your "production-ready" website under a `./site` folder
that you can upload on your server.
$ tree
├── content
│   └── index.html
└── output
├── index.html
└── site
└── index.html
Boop! basically just copied `content` files under a `output` directory. But it
can convert Markdown files in HTML too. For that, you'll need a template file
for articles:
Well OK, Boop! basically just copied the `index.html` file under the `site`
directory. Let's write an article then.
For that, you'll need a template file under a `./theme` folder:
$ mkdir theme
$ echo '<html><body>{{ ARTICLE_CONTENT }}</body></html' > theme/article.html
Then, you can create your Markdown file as you did with the HTML one:
Then, you can create a Markdown file under a `./articles` folder:
$ echo '# Welcome!' > content/
$ mkdir articles
$ echo '# My first article' > articles/
$ echo output/markdown-index.html
$ tree
├── articles
│   └──
├── site
│   ├── index.html
│   ├── my-article.html
├── theme
│   └── article.html
└── index.html
$ echo site/my-article.html
<html><body><h1>My first article</h1></body></html>
Please note that `./articles` folder only accepts Markdown files (i.e.
extension is `.md`).
You can define meta variables in the Markdown file which will be accessible
then in the template. Variables are uppercased and prepended by `ARTICLE_`. For
example, for the following Markdown file:
title: Welcome!
title: An article
author: Marien
......@@ -113,10 +119,10 @@ It will produce the following file:
<title>An article</title>
<h1>An article</h1>
<p>By Marien</p>
<p>This is my article.</p>
......@@ -128,6 +134,25 @@ For now, you can use any valid Python expression between `{{ }}`, you have
access to the variables defined in the meta header, the Python builtin
functions and the `datetime` module.
The `./theme` folder can contain a `static` folder as well. Its content will be
copied under the `./site` folder:
$ tree
├── articles
│   └──
├── site
│   ├── index.html
│   ├── my-article.html
│   └── style.css
├── theme
│   ├── static
│   │   └── style.css
│   └── article.html
└── index.html
## Tests
There are some tests (i.e. doctests) that can be run to check that everything
......@@ -3,6 +3,7 @@
import os
import sys
import shutil
import distutils.dir_util
import locale
import markdown
......@@ -40,13 +41,6 @@ def dir_tree(path):
yield filename
def mkdirs_for_file(filepath):
"""Create parent directories for a given file.
path = os.path.dirname(filepath)
os.makedirs(path, exist_ok=True)
def convert_meta_to_article_vars(meta):
"""Convert Markdown Meta to vars for article layout.
......@@ -62,37 +56,50 @@ def convert_meta_to_article_vars(meta):
def main():
# Check that content directory exists on the filesystem
content_path = os.path.join(os.curdir, "content")
if not os.path.isdir(content_path):
raise ProgramError("./content directory does not exist")
# Make sure output dir doesn't exist
output_path = os.path.join(os.curdir, "output")
# Make sure ./site folder is empty
output_path = os.path.join(os.curdir, "site")
if os.path.isdir(output_path):
# it should be a directory...
elif os.path.exists(output_path):
# ... but it also can be a simple file if user created it manually!
os.makedirs(output_path, exist_ok=True)
# Check that index file exists and copy it under the ./site folder
index_filepath = os.path.join(os.curdir, "index.html")
if not os.path.exists(index_filepath):
raise ProgramError("./index.html file does not exist")
index_output_filepath = os.path.join(output_path, "index.html")
shutil.copyfile(index_filepath, index_output_filepath)
# Check that a ./theme/static folder exists and copy its content under the
# ./site folder
static_dirpath = os.path.join(os.curdir, "theme", "static")
if os.path.isdir(static_dirpath):
distutils.dir_util.copy_tree(static_dirpath, output_path)
# Check that articles directory exists on the filesystem
articles_path = os.path.join(os.curdir, "articles")
if not os.path.isdir(articles_path):
# If not, just stop here
md = markdown.Markdown(extensions=["meta", "fenced_code", "attr_list"])
# And copy the files from ./content to ./output
for filepath in dir_tree(content_path):
base, ext = os.path.splitext(filepath)
content_filepath = os.path.join(content_path, filepath)
output_filepath = os.path.join(output_path, filepath)
if ext == ".md":
output_filepath = os.path.join(output_path, f"{base}.html")
# And copy the files from ./articles to ./site
for filename in dir_tree(articles_path):
base, ext = os.path.splitext(filename)
if ext != ".md":
# Don't consider files which are not Markdown
# First we need to create all the parent directories for our file
article_filepath = os.path.join(articles_path, filename)
output_filepath = os.path.join(output_path, f"{base}.html")
if ext == ".md":
# Then, if it is a Markdown file, we convert it
with open(content_filepath, "r") as content_file:
html = md.convert(
# We convert the file's content into HTML
with open(article_filepath, "r") as article_file:
html = md.convert(
# We initialize the template
article_template_filepath = os.path.join("theme", "article.html")
......@@ -106,9 +113,6 @@ def main():
# And we write the content in the output file
with open(output_filepath, "w") as output_file:
# ... else, we simply copy the file to the output directory
shutil.copyfile(content_filepath, output_filepath)
if __name__ == "__main__":
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment