boop.py 4.31 KB
Newer Older
1
2
3
#!/bin/env python3

import os
4
import sys
5
import shutil
6
import distutils.dir_util
7
import locale
8

9
10
import markdown

11
12
13
14
15
import boopsy


locale.setlocale(locale.LC_ALL, "fr_FR.utf8")

16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class ProgramError(Exception):
    """Exception raised during the program execution.

    Examples:

    >>> try:
    ...     raise ProgramError("Oops")
    ... except ProgramError as e:
    ...     print(e.args[0])
    Oops
    """

    pass


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def dir_tree(path):
    """List all the tree directory under the given path.
    """
    for filename in os.listdir(path):
        full_path = os.path.join(path, filename)
        if os.path.isdir(full_path):
            for sub_filename in dir_tree(full_path):
                yield os.path.join(filename, sub_filename)
        else:
            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)


51
52
53
54
55
56
57
58
59
60
61
62
63
64
def convert_meta_to_article_vars(meta):
    """Convert Markdown Meta to vars for article layout.
    """
    article_vars = {}
    for key, values in meta.items():
        article_key = f"ARTICLE_{key.upper()}"
        # The Markdown's meta extension extract all the values in arrays, even
        # if there is only one value. Because there is no iteration system in
        # the template system, for the moment we just get the first value of
        # the array.
        article_vars[article_key] = values[0]
    return article_vars


65
def main():
66
    # Make sure ./site folder is empty
berumuron's avatar
berumuron committed
67
    output_path = os.path.join(os.curdir, "site")
68
    if os.path.isdir(output_path):
69
        # it should be a directory...
70
        shutil.rmtree(output_path)
71
72
73
    elif os.path.exists(output_path):
        # ... but it also can be a simple file if user created it manually!
        os.remove(output_path)
74
75
76
77
78
79
80
81
82
    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)

83
84
85
86
87
88
    # 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)

89
90
91
    # Check that articles directory exists on the filesystem
    articles_path = os.path.join(os.curdir, "articles")
    if not os.path.isdir(articles_path):
92
93
        # If not, just stop here
        return
94

95
    md = markdown.Markdown(extensions=["meta", "fenced_code", "attr_list"])
96

97
98
    # And copy the files from ./articles to ./site
    for filepath in dir_tree(articles_path):
99
        base, ext = os.path.splitext(filepath)
100
        content_filepath = os.path.join(articles_path, filepath)
101
        output_filepath = os.path.join(output_path, filepath)
102
103
        if ext == ".md":
            output_filepath = os.path.join(output_path, f"{base}.html")
104
105
106
107

        # First we need to create all the parent directories for our file
        mkdirs_for_file(output_filepath)

108
109
110
111
112
        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())

113
114
115
116
117
118
119
120
121
122
            # 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
123
            with open(output_filepath, "w") as output_file:
124
                output_file.write(template.render(article_vars))
125
126
127
        else:
            # ... else, we simply copy the file to the output directory
            shutil.copyfile(content_filepath, output_filepath)
128
129
130


if __name__ == "__main__":
131
132
133
134
135
    try:
        main()
        print("Boop!")
    except ProgramError as e:
        print(e.args[0], file=sys.stderr)