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