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 • 9.86 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:
69
PostSlugs = PostSlugs + tuple( ("drafts", file) for file in ListDirectory("drafts") )
70
Posts = []
71
for dir, slug in PostSlugs:
72
print("Grabbing post list blog-posts/%s" % (slug))
73
with open(dir + "/" + slug, encoding="utf-8") as MDFile:
74
RawMD = MDFile.read()
75
PostHTML = RenderMarkdown(RawMD)
76
Item = PostHTML.metadata
77
Item["content"] = PostHTML
78
Item["raw-content"] = RawMD
79
Item["rss-content"] = PostHTML.replace("&", "&amp;").replace(">", "&gt;").replace("<", "&lt;")
80
Item["atom-content"] = RegReplace("</(?=.*)", "</xhtml:", RegReplace("<(?=[^\/].*)", "<xhtml:", PostHTML))
81
Item["rss-post-time"] = PostDateToDateObj(Item["date"]).strftime("%a, %d %b %Y") + " 00:00:00 GMT"
82
Item["atom-post-time"] = PostDateToDateObj(Item["date"]).strftime("%Y-%m-%d") + "T00:00:00Z"
83
Item["atom-update-time"] = Item["atom-post-time"]
84
if "updated" in Item:
85
Item["atom-update-time"] = PostDateToDateObj(Item["updated"]).strftime("%Y-%m-%d") + "T00:00:00Z"
86
Item["pathname"] = slug.replace(".md", ".html")
87
Item["plaintext"] = slug.replace(".md", ".txt")
88
Item["origin"] = slug
89
Item["is-draft"] = dir == "drafts"
90
Posts.append(Item)
91
PostsByDate = sorted(Posts, key=PostSortHelper, reverse=True)
92
return PostsByDate
93
94
PostList = []
95
96
97
def ListParseCategory(Obj, depth):
98
html = "<h%d id=\"%s\">%s</h%d>" % (2+depth, Obj["id"], Obj["title"], 2+depth)
99
if "paragraph" in Obj:
100
html += "<p>%s</p>" % Obj["paragraph"]
101
listType = "ul"
102
if "list-type" in Obj and Obj["list-type"] == "ordered":
103
listType = "ol"
104
html += "<%s>" % listType
105
for item in Obj["list"]:
106
html += "<li>" + LIST_PARSER_DICT[item["type"]](item, depth + 1) + "</li>"
107
html += "</%s>" % listType
108
return html
109
110
def ListParseLink(Obj, depth):
111
html = "<a href=\"%s\">" % Obj["href"]
112
text = Obj["text"]
113
if "text-type" in Obj and Obj["text-type"] == "text/markdown":
114
text = RenderMarkdown(text).replace("<p>", "").replace("</p>", "")
115
html += text + "</a>"
116
if "comment" in Obj:
117
html += "(%s)" % Obj["comment"]
118
return html
119
120
def ListParseText(Obj, depth):
121
text = Obj["text"]
122
# if "text-type" in Obj and Obj["text-type"] == "text/markdown":
123
# print(RenderMarkdown(text))
124
# text = RenderMarkdown(text) # this doesn't work???
125
if "comment" in Obj:
126
text += "(%s)" % Obj["comment"]
127
return text
128
129
LIST_PARSER_DICT = {
130
"category": ListParseCategory,
131
"link": ListParseLink,
132
"text": ListParseText,
133
}
134
135
def GetLists():
136
ListSlugs = ListDirectory("lists")
137
Lists = []
138
for slug in ListSlugs:
139
List = {
140
"title": "",
141
"content": "",
142
"filename": slug
143
}
144
with open("lists/" + slug) as ListYML:
145
ListDict = LoadYML(ListYML.read())
146
List["title"] = ListDict["title"]
147
if "paragraph" in ListDict:
148
List["content"] += "<p>%s</p>" % ListDict["paragraph"]
149
for item in ListDict["list"]:
150
List["content"] += LIST_PARSER_DICT[item["type"]](item, 0)
151
Lists.append(List)
152
sitemap.append(SITEMAP_HREF + "list/" + slug)
153
sitemap.append(SITEMAP_HREF + "list/")
154
return Lists
155
156
def RenderPosts():
157
global PostList
158
for post in PostList:
159
Revised = post["updated"] if "updated" in post else False
160
RenderedHTML = RenderTemplate(
161
"blog-post.html",
162
Revised=Revised,
163
Title=post["title"],
164
PostDate=post["date"],
165
Content=post["content"],
166
PostPath=post["pathname"],
167
PlaintextPath=post["plaintext"],
168
IsDraft=post["is-draft"],
169
)
170
print("Building blog-posts/%s to %s/blog/%s" % (post["origin"], BUILD_DIRECTORY, post["pathname"]))
171
with open(BUILD_DIRECTORY + "/blog/" + post["pathname"], "w", encoding="utf-8") as PostHTMLFile:
172
PostHTMLFile.write(RenderedHTML)
173
print("Copying blog-posts/%s to %s/blog/%s" % (post["origin"], BUILD_DIRECTORY, post["plaintext"]))
174
with open(BUILD_DIRECTORY + "/blog/" + post["plaintext"], "w", encoding="utf-8") as PostHTMLFile:
175
PostHTMLFile.write(post["raw-content"])
176
sitemap.append(SITEMAP_HREF + "blog/" + post["pathname"])
177
178
def RenderPage(PageInput: str, ContentDest: str, AllowSitemap: bool = True, **kwargs):
179
print("Building views/%s to %s/%s" % (PageInput, BUILD_DIRECTORY, ContentDest))
180
if AllowSitemap:
181
sitemap.append(SITEMAP_HREF + ContentDest)
182
with open(BUILD_DIRECTORY + "/" + ContentDest, "w", encoding="utf-8") as DestLocation:
183
DestLocation.write(RenderTemplate(PageInput, **kwargs))
184
185
def CreateJSONFeed():
186
global PostList
187
CreatedJSON = {
188
"version": "https://jsonfeed.org/version/1",
189
"title": "Steve0Greatness' Blog",
190
"home_page_url": "https://steve0greatness.github.io",
191
"feed_url": "https://steve0greatness.github.io/blog/feed.rss",
192
"language": "en-US",
193
"favicon": "https://steve0greatness.github.io/favicon.ico",
194
"description": "A blog by a human being.",
195
"authors": [
196
{
197
"name": "Steve0Greatness",
198
"url": "https://steve0greatness.github.io"
199
}
200
],
201
"items": []
202
}
203
for post in PostList:
204
CreatedJSON["items"].append({
205
"id": "https://steve0greatness.github.io/blog/" + post["pathname"],
206
"title": "JSON Feed version 1.1",
207
"icon": "https://steve0greatness.github.io/favicon.ico",
208
"content_html": post["content"],
209
"date_published": post["atom-post-time"],
210
"date_modified": post["atom-update-time"],
211
"url": "https://steve0greatness.github.io/blog/" + post["pathname"]
212
})
213
with open(BUILD_DIRECTORY + "/blog/feed.json", "w") as JSONFeedFile:
214
DumpJSON(CreatedJSON, JSONFeedFile)
215
216
def RenderLists():
217
Lists = GetLists()
218
CreateDirectory(BUILD_DIRECTORY + "/list/")
219
ListIndex = "<ul>"
220
for List in Lists:
221
FileLocation = "/list/" + List["filename"].replace(".yml", ".html")
222
Title = List["title"]
223
print("%s -> %s" % ("lists/" + List["filename"], BUILD_DIRECTORY + FileLocation))
224
with open(BUILD_DIRECTORY + FileLocation, "w") as file:
225
file.write(RenderTemplate("list.html", Content=List["content"], Title=Title, Location=FileLocation))
226
ListIndex += "<li><a href=\"%s\">%s</a></li>" % (FileLocation, Title)
227
ListIndex += "</ul>"
228
print("Building list index")
229
with open(BUILD_DIRECTORY + "/list/index.html", "w") as file:
230
file.write(RenderTemplate("list-index.html", Content=ListIndex))
231
232
def main():
233
global PostList
234
PostList = GetBlogList()
235
print("Wiping directory")
236
WipeFinalDir()
237
print("Creating blog holder")
238
CreateDirectory(BUILD_DIRECTORY + "/blog")
239
print("Rendering posts")
240
RenderPosts()
241
CreateJSONFeed()
242
print("Copying static directory")
243
CopyDirectory("static", BUILD_DIRECTORY)
244
print("Creating lists")
245
RenderLists()
246
247
print("Building pages")
248
for file, path in PAGES.items():
249
AllowSitemap = file not in DISALLOWED_SITEMAP
250
RenderPage(file, path, AllowSitemap, PostList=PostList)
251
252
print("Building redirects")
253
for OldLocation, NewLocation in REDIRECTS.items():
254
RenderPage("redirect.html", OldLocation, False, redirect=NewLocation, old=OldLocation)
255
256
with open(BUILD_DIRECTORY + "/sitemap.txt", "w") as SitemapFile:
257
SitemapFile.write("\n".join(sitemap))
258
259
if __name__ == "__main__":
260
main()