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

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

8
9
10
import boop.environment as environment
import boop.configuration as config
import boop.utils as utils
berumuron's avatar
berumuron committed
11
from boop.feed import Feed
12
13


14
locale.setlocale(locale.LC_ALL, "")
15

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
def main(environment):
    # Make sure ./site folder is empty
    output_path = os.path.join(os.curdir, "site")
35
    utils.init_output_folder(output_path)
36
37
38

    # Load the configuration (it can be overidden by a configuration.yml file)
    configuration_path = os.path.join(os.curdir, "configuration.yml")
39
    configuration = config.load(configuration_path, environment, output_path)
40

41
42
43
    # STEP 1: we load all the Articles and Pages
    pages = []
    articles = []
berumuron's avatar
berumuron committed
44
    articles_by_series = {}
45
46

    # Check that index file exists
47
48
49
    index_filepath = os.path.join(os.curdir, "index.html")
    if not os.path.exists(index_filepath):
        raise ProgramError("./index.html file does not exist")
50

51
52
53
54
    index_page = utils.build_page_from_filepath(
        index_filepath, configuration, basename=os.curdir
    )
    pages.append(index_page)
55
56

    # Check that pages directory exists and load Pages from it
berumuron's avatar
berumuron committed
57
58
    pages_path = os.path.join(os.curdir, "pages")
    if os.path.isdir(pages_path):
59
        for filename in utils.dir_tree(pages_path, only=["html"]):
berumuron's avatar
berumuron committed
60
            page_filepath = os.path.join(pages_path, filename)
61
62
63
64
            page = utils.build_page_from_filepath(
                page_filepath, configuration, basename=pages_path
            )
            pages.append(page)
65

66
67
68
    # Check that articles directory exists and load Articles from it
    articles_path = os.path.join(os.curdir, "articles")
    if os.path.isdir(articles_path):
69
70
71
        # We iterate on the directories of articles dir. If they contain
        # "serie.html" file, it means they contain a serie. Otherwise, we list
        # articles as usual.
72
        dirs_with_articles = list(utils.list_dirs(articles_path)) + ["."]
73
74
75
        for dirname in dirs_with_articles:
            dirpath = os.path.realpath(os.path.join(articles_path, dirname))

76
77
            serie_filepath = os.path.join(dirpath, "serie.html")
            serie = None
78
            if dirname != "." and os.path.exists(serie_filepath):
79
80
81
                # We have a serie Page! Each article of the directory must be
                # considered part of the serie.
                slug = f"serie/{dirname}"
82
83
84
85
86
                serie = utils.build_page_from_filepath(
                    serie_filepath, configuration, slug=slug
                )
                pages.append(serie)
                articles_by_series[serie] = []
berumuron's avatar
berumuron committed
87

88
            for filename in utils.list_files(dirpath, only=["md"]):
89
                article_filepath = os.path.join(dirpath, filename)
90
                article = utils.build_article_from_filepath(
91
92
93
94
95
                    article_filepath, configuration, serie
                )
                articles.append(article)
                if serie:
                    articles_by_series[serie].append(article)
96

97
    # We want to sort the articles by publication date first
98
    articles.sort(key=lambda article: article.date(), reverse=True)
berumuron's avatar
berumuron committed
99
100
    for serie_articles in articles_by_series.values():
        serie_articles.sort(key=lambda article: article.date(), reverse=True)
101

berumuron's avatar
berumuron committed
102
103
104
105
106
107
108
109
110
111
112
    # Load a "blog" page which has access to the list of articles
    blog_template_filepath = os.path.join("templates", "blog.html")
    if os.path.exists(blog_template_filepath):
        blog_page = utils.build_blog_page(articles, configuration)
        pages.append(blog_page)

    # STEP 2: we write all the pages and articles
    for page in pages:
        utils.write_content(page, output_path)
        print(f"Written page: {page.url()}")

113
    for article in articles:
114
        utils.write_content(article, output_path)
115
        print(f"Written article: {article.url()}")
116

berumuron's avatar
berumuron committed
117
    # STEP 3: we write also the Atom feeds (the main one + the series').
berumuron's avatar
berumuron committed
118
119
    # We start by collecting the different feeds
    feeds = []
120
    if len(articles) > 0:
berumuron's avatar
berumuron committed
121
122
123
        # The main one...
        feed = Feed("feeds/all", articles, configuration=configuration)
        feeds.append(feed)
124

berumuron's avatar
berumuron committed
125
    for serie, serie_articles in articles_by_series.items():
berumuron's avatar
berumuron committed
126
127
128
129
130
131
132
133
134
135
136
        # And the series' ones
        if len(serie_articles) == 0:
            continue

        slug = f"feeds/{os.path.basename(serie.slug())}"
        feed_title = f"{serie.title()} - {configuration['SITE_TITLE']}"
        feed = Feed(
            slug,
            serie_articles,
            {"title": feed_title, "site_link": serie.url()},
            configuration=configuration,
berumuron's avatar
berumuron committed
137
        )
berumuron's avatar
berumuron committed
138
139
140
141
142
143
144
145
        feeds.append(feed)

    if len(feeds) > 0:
        # If we have collected feeds (i.e. we have at least one article), we
        # write them.
        for feed in feeds:
            utils.write_feed(feed, output_path)
            print(f"Written feed: {feed.url()}")
berumuron's avatar
berumuron committed
146

147
148
149
150
151
    # STEP 4: and we finish by copying the static folder.
    static_dirpath = os.path.join(os.curdir, "static")
    if os.path.isdir(static_dirpath):
        distutils.dir_util.copy_tree(static_dirpath, output_path)
        print(f"Static files copied")
152

153
154

if __name__ == "__main__":
155
    environment = environment.load_from_argv(sys.argv)
156
    try:
157
        main(environment)
158
159
160
        print("Boop!")
    except ProgramError as e:
        print(e.args[0], file=sys.stderr)