A mirror of my website's source code.

By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

 build.py

View raw Download
text/x-script.python • 10.5 kiB
Python script, Unicode text, UTF-8 text executable
        
            
1
from Renderers import RenderTemplate, RenderMarkdown
2
from sys import argv
3
from shutil import rmtree as DeleteDirectory
4
from os import mkdir as CreateDirectory, listdir as ListDirectory, unlink as DeleteFile
5
from os.path import isfile as IsFile, exists as PathExists
6
from distutils.dir_util import copy_tree as CopyDirectory
7
from datetime import datetime
8
from json import dump as DumpJSON
9
from yaml import safe_load as LoadYML
10
from re import sub as RegReplace
11
from typing import Literal
12
13
DEPLOY_BUILD_DIR = {
14
"gh-pages-deploy": "build",
15
"gl-pages-deploy": "public"
16
} # Separate because this site is built with an action that won't work if they aren't
17
LOCAL_BUILD_DIR = "build"
18
19
PAGES_DEPLOY = argv[1] if len(argv) > 1 else None
20
BUILD_DIRECTORY = DEPLOY_BUILD_DIR[PAGES_DEPLOY] if PAGES_DEPLOY is not None else LOCAL_BUILD_DIR
21
22
PAGES = {
23
"index.html": "index.html",
24
"blog-list.html": "blog/index.html",
25
"blog-feed.rss": "blog/feed.rss",
26
"blog-feed.atom": "blog/feed.atom",
27
"404.html": "404.html",
28
}
29
30
DISALLOWED_SITEMAP = {
31
"404.html",
32
"blog-feed.rss",
33
"blog-feed.atom",
34
"blog-list.html",
35
"index.html",
36
}
37
38
REDIRECTS = {
39
"link-tree.html": "list/link-tree.html", # Old location -> new location
40
}
41
42
SITEMAP_HREF = "https://steve0greatness.github.io/"
43
sitemap = [
44
SITEMAP_HREF + "blog/",
45
SITEMAP_HREF,
46
]
47
48
def EscapeHTMLForRSS(HTML: str) -> str:
49
values = {
50
"&": "&", # this is here for a reason, do not change order.
51
"<": "&lt;",
52
">": "&gt;",
53
"§": "&#xa7;",
54
}
55
RssHtml = HTML
56
for old, new in values.items():
57
RssHtml = RssHtml.replace(old, new)
58
return RssHtml
59
60
def WipeFinalDir():
61
if not PathExists(BUILD_DIRECTORY):
62
print("Directory didn't existing, creating it...")
63
CreateDirectory(BUILD_DIRECTORY)
64
return
65
print("Directory exists, wiping it...")
66
for item in ListDirectory(BUILD_DIRECTORY):
67
path = BUILD_DIRECTORY + "/" + item
68
if IsFile(path):
69
DeleteFile(path)
70
continue
71
DeleteDirectory(path)
72
73
def PostDateToDateObj(Date):
74
return datetime.strptime(Date, "%Y %b %d")
75
76
def PostSortHelper(Post):
77
return PostDateToDateObj(Post["date"])
78
79
def GetBlogList():
80
print("Grabbing post list")
81
PostSlugs: tuple[tuple[Literal["blog-posts", "drafts"], str], ...] = tuple( ("blog-posts", file) for file in ListDirectory("blog-posts") )
82
if not PAGES_DEPLOY and PathExists("drafts"):
83
PostSlugs = PostSlugs + tuple( ("drafts", file) for file in ListDirectory("drafts") )
84
Posts = []
85
for dir, slug in PostSlugs:
86
if not slug.endswith(".md"):
87
continue
88
print("Grabbing post list blog-posts/%s" % (slug))
89
with open(dir + "/" + slug, encoding="utf-8") as MDFile:
90
RawMD = MDFile.read()
91
PostHTML = RenderMarkdown(RawMD)
92
Item = PostHTML.metadata
93
Item["content"] = PostHTML
94
Item["raw-content"] = RawMD
95
Item["rss-content"] = EscapeHTMLForRSS(PostHTML)
96
Item["rss-post-time"] = PostDateToDateObj(Item["date"]).strftime("%a, %d %b %Y") + " 00:00:00 GMT"
97
Item["atom-post-time"] = PostDateToDateObj(Item["date"]).strftime("%Y-%m-%d") + "T00:00:00Z"
98
Item["opengraph-date"] = PostDateToDateObj(Item["date"]).strftime("%Y-%m-%d")
99
Item["opengraph-update"] = Item["opengraph-date"]
100
Item["atom-update-time"] = Item["atom-post-time"]
101
if "updated" in Item:
102
Item["atom-update-time"] = PostDateToDateObj(Item["updated"]).strftime("%Y-%m-%d") + "T00:00:00Z"
103
Item["opengraph-update"] = PostDateToDateObj(Item["updated"]).strftime("%Y-%m-%d")
104
Item["pathname"] = slug.replace(".md", ".html")
105
Item["plaintext"] = slug.replace(".md", ".txt")
106
Item["origin"] = slug
107
Item["is-draft"] = dir == "drafts"
108
Posts.append(Item)
109
PostsByDate = sorted(Posts, key=PostSortHelper, reverse=True)
110
return PostsByDate
111
112
PostList = []
113
114
115
def ListParseCategory(Obj, depth):
116
html = "<h%d id=\"%s\">%s</h%d>" % (2+depth, Obj["id"], Obj["title"], 2+depth)
117
if "paragraph" in Obj:
118
html += "<p>%s</p>" % Obj["paragraph"]
119
listType = "ul"
120
if "list-type" in Obj and Obj["list-type"] == "ordered":
121
listType = "ol"
122
html += "<%s>" % listType
123
for item in Obj["list"]:
124
html += "<li>" + LIST_PARSER_DICT[item["type"]](item, depth + 1) + "</li>"
125
html += "</%s>" % listType
126
return html
127
128
def ListParseLink(Obj, depth):
129
html = "<a href=\"%s\">" % Obj["href"]
130
text = Obj["text"]
131
if "text-type" in Obj and Obj["text-type"] == "text/markdown":
132
text = RenderMarkdown(text).replace("<p>", "").replace("</p>", "")
133
html += text + "</a>"
134
if "comment" in Obj:
135
html += "(%s)" % Obj["comment"]
136
return html
137
138
def ListParseText(Obj, depth):
139
text = Obj["text"]
140
# if "text-type" in Obj and Obj["text-type"] == "text/markdown":
141
# print(RenderMarkdown(text))
142
# text = RenderMarkdown(text) # this doesn't work???
143
if "comment" in Obj:
144
text += "(%s)" % Obj["comment"]
145
return text
146
147
LIST_PARSER_DICT = {
148
"category": ListParseCategory,
149
"link": ListParseLink,
150
"text": ListParseText,
151
}
152
153
def GetLists():
154
ListSlugs = ListDirectory("lists")
155
Lists = []
156
for slug in ListSlugs:
157
List = {
158
"title": "",
159
"content": "",
160
"filename": slug
161
}
162
with open("lists/" + slug) as ListYML:
163
ListDict = LoadYML(ListYML.read())
164
List["title"] = ListDict["title"]
165
if "paragraph" in ListDict:
166
List["content"] += "<p>%s</p>" % ListDict["paragraph"]
167
List["content"] += "<ul>"
168
for item in ListDict["list"]:
169
List["content"] += "<li>" + LIST_PARSER_DICT[item["type"]](item, 0) + "</li>"
170
List["content"] += "</ul>"
171
Lists.append(List)
172
sitemap.append(SITEMAP_HREF + "list/" + slug)
173
sitemap.append(SITEMAP_HREF + "list/")
174
return Lists
175
176
def RenderPosts():
177
global PostList
178
for post in PostList:
179
Revised = post["updated"] if "updated" in post else False
180
RenderedHTML = RenderTemplate(
181
"blog-post.html",
182
Revised=Revised,
183
Title=post["title"],
184
PostDate=post["date"],
185
Content=post["content"],
186
PostPath=post["pathname"],
187
PlaintextPath=post["plaintext"],
188
IsDraft=post["is-draft"],
189
OpenGraphDate=post["opengraph-date"],
190
post=post
191
)
192
print("Building blog-posts/%s to %s/blog/%s" % (post["origin"], BUILD_DIRECTORY, post["pathname"]))
193
with open(BUILD_DIRECTORY + "/blog/" + post["pathname"], "w", encoding="utf-8") as PostHTMLFile:
194
PostHTMLFile.write(RenderedHTML)
195
print("Copying blog-posts/%s to %s/blog/%s" % (post["origin"], BUILD_DIRECTORY, post["plaintext"]))
196
with open(BUILD_DIRECTORY + "/blog/" + post["plaintext"], "w", encoding="utf-8") as PostHTMLFile:
197
PostHTMLFile.write(post["raw-content"])
198
sitemap.append(SITEMAP_HREF + "blog/" + post["pathname"])
199
200
def RenderPage(PageInput: str, ContentDest: str, AllowSitemap: bool = True, **kwargs):
201
print("Building views/%s to %s/%s" % (PageInput, BUILD_DIRECTORY, ContentDest))
202
if AllowSitemap:
203
sitemap.append(SITEMAP_HREF + ContentDest)
204
with open(BUILD_DIRECTORY + "/" + ContentDest, "w", encoding="utf-8") as DestLocation:
205
DestLocation.write(RenderTemplate(PageInput, **kwargs))
206
207
def CreateJSONFeed():
208
global PostList
209
CreatedJSON = {
210
"version": "https://jsonfeed.org/version/1",
211
"title": "Steve0Greatness' Blog",
212
"home_page_url": "https://steve0greatness.github.io",
213
"feed_url": "https://steve0greatness.github.io/blog/feed.rss",
214
"language": "en-US",
215
"favicon": "https://steve0greatness.github.io/favicon.ico",
216
"description": "A blog by a human being.",
217
"authors": [
218
{
219
"name": "Steve0Greatness",
220
"url": "https://steve0greatness.github.io"
221
}
222
],
223
"items": []
224
}
225
for post in PostList:
226
CreatedJSON["items"].append({
227
"id": "https://steve0greatness.github.io/blog/" + post["pathname"],
228
"title": "JSON Feed version 1.1",
229
"icon": "https://steve0greatness.github.io/favicon.ico",
230
"content_html": post["content"],
231
"date_published": post["atom-post-time"],
232
"date_modified": post["atom-update-time"],
233
"url": "https://steve0greatness.github.io/blog/" + post["pathname"]
234
})
235
with open(BUILD_DIRECTORY + "/blog/feed.json", "w") as JSONFeedFile:
236
DumpJSON(CreatedJSON, JSONFeedFile)
237
238
def RenderLists():
239
Lists = GetLists()
240
CreateDirectory(BUILD_DIRECTORY + "/list/")
241
ListIndex = "<ul>"
242
for List in Lists:
243
FileLocation = "/list/" + List["filename"].replace(".yml", ".html")
244
Title = List["title"]
245
print("%s -> %s" % ("lists/" + List["filename"], BUILD_DIRECTORY + FileLocation))
246
with open(BUILD_DIRECTORY + FileLocation, "w") as file:
247
file.write(RenderTemplate("list.html", Content=List["content"], Title=Title, Location=FileLocation))
248
ListIndex += "<li><a href=\"%s\">%s</a></li>" % (FileLocation, Title)
249
ListIndex += "</ul>"
250
print("Building list index")
251
with open(BUILD_DIRECTORY + "/list/index.html", "w") as file:
252
file.write(RenderTemplate("list-index.html", Content=ListIndex))
253
254
def main():
255
global PostList
256
PostList = GetBlogList()
257
print("Wiping directory")
258
WipeFinalDir()
259
print("Creating blog holder")
260
CreateDirectory(BUILD_DIRECTORY + "/blog")
261
print("Rendering posts")
262
RenderPosts()
263
CreateJSONFeed()
264
print("Copying static directory")
265
CopyDirectory("static", BUILD_DIRECTORY)
266
print("Creating lists")
267
RenderLists()
268
269
print("Building pages")
270
for file, path in PAGES.items():
271
AllowSitemap = file not in DISALLOWED_SITEMAP
272
RenderPage(file, path, AllowSitemap, PostList=PostList)
273
274
print("Building redirects")
275
for OldLocation, NewLocation in REDIRECTS.items():
276
RenderPage("redirect.html", OldLocation, False, redirect=NewLocation, old=OldLocation)
277
278
with open(BUILD_DIRECTORY + "/sitemap.txt", "w") as SitemapFile:
279
SitemapFile.write("\n".join(sitemap))
280
281
if __name__ == "__main__":
282
main()
283
284