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