diff --git a/README.md b/README.md index f041151b2b1b6cf8e42e64cb766881388ed8c431..c8a525dc9cb39eb114766e50fca7da1924653b59 100644 --- a/README.md +++ b/README.md @@ -32,60 +32,66 @@ $ source ~/.bashrc ## Usage -First, create a project directory: +First, create a project and execute the Boop! command: ```console $ mkdir my-website && cd my-website -``` - -Create a `./content` folder and execute the Boop! command: - -```console -$ mkdir content -$ echo '

Welcome!

' > content/index.html +$ echo '

Welcome!

' > index.html $ boop.py Boop! ``` -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. ```console $ 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: ```console $ mkdir theme $ echo '{{ ARTICLE_CONTENT }} 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: ```console -$ echo '# Welcome!' > content/markdown-index.md +$ mkdir articles +$ echo '# My first article' > articles/my-article.md $ boop.py -$ echo output/markdown-index.html -

Welcome!

+$ tree +. +├── articles +│   └── my-article.md +├── site +│   ├── index.html +│   ├── my-article.html +├── theme +│   └── article.html +└── index.html +$ echo site/my-article.html +

My first article

``` +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: ```markdown --- -title: Welcome! +title: An article author: Marien --- @@ -113,10 +119,10 @@ It will produce the following file: ```html - Welcome! + An article -

Welcome!

+

An article

By Marien

This is my article.

@@ -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: + +```console +$ tree +. +├── articles +│   └── my-article.md +├── 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 diff --git a/boop.py b/boop.py index 0632b2a24c5804e6405bcec8e3b1d43b666cb347..e3b48ac3079ee15474538dbabb2a3064444c8871 100755 --- a/boop.py +++ b/boop.py @@ -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,53 +56,63 @@ 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... shutil.rmtree(output_path) elif os.path.exists(output_path): # ... but it also can be a simple file if user created it manually! os.remove(output_path) + 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 + return 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") - - # First we need to create all the parent directories for our file - mkdirs_for_file(output_filepath) - - if ext == ".md": - # Then, if it is a Markdown file, we convert it - with open(content_filepath, "r") as content_file: - html = md.convert(content_file.read()) - - # We initialize the template - article_template_filepath = os.path.join("theme", "article.html") - template = boopsy.Template(article_template_filepath) - - # We get the local variables from the Markdown file (metadata) - # which will be accessible in the article template - article_vars = convert_meta_to_article_vars(md.Meta) - article_vars["ARTICLE_CONTENT"] = html - - # And we write the content in the output file - with open(output_filepath, "w") as output_file: - output_file.write(template.render(article_vars)) - else: - # ... else, we simply copy the file to the output directory - shutil.copyfile(content_filepath, output_filepath) + # 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 + next + + article_filepath = os.path.join(articles_path, filename) + output_filepath = os.path.join(output_path, f"{base}.html") + + # We convert the file's content into HTML + with open(article_filepath, "r") as article_file: + html = md.convert(article_file.read()) + + # We initialize the template + article_template_filepath = os.path.join("theme", "article.html") + template = boopsy.Template(article_template_filepath) + + # We get the local variables from the Markdown file (metadata) + # which will be accessible in the article template + article_vars = convert_meta_to_article_vars(md.Meta) + article_vars["ARTICLE_CONTENT"] = html + + # And we write the content in the output file + with open(output_filepath, "w") as output_file: + output_file.write(template.render(article_vars)) if __name__ == "__main__":