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.98 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
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
List["content"] += "<ul>"
150
for item in ListDict["list"]:
151
List["content"] += "<li>" + LIST_PARSER_DICT[item["type"]](item, 0) + "</li>"
152
List["content"] += "</ul>"
153
Lists.append(List)
154
sitemap.append(SITEMAP_HREF + "list/" + slug)
155
sitemap.append(SITEMAP_HREF + "list/")
156
return Lists
157
158
def RenderPosts():
159
global PostList
160
for post in PostList:
161
Revised = post["updated"] if "updated" in post else False
162
RenderedHTML = RenderTemplate(
163
"blog-post.html",
164
Revised=Revised,
165
Title=post["title"],
166
PostDate=post["date"],
167
Content=post["content"],
168
PostPath=post["pathname"],
169
PlaintextPath=post["plaintext"],
170
IsDraft=post["is-draft"],
171
)
172
print("Building blog-posts/%s to %s/blog/%s" % (post["origin"], BUILD_DIRECTORY, post["pathname"]))
173
with open(BUILD_DIRECTORY + "/blog/" + post["pathname"], "w", encoding="utf-8") as PostHTMLFile:
174
PostHTMLFile.write(RenderedHTML)
175
print("Copying blog-posts/%s to %s/blog/%s" % (post["origin"], BUILD_DIRECTORY, post["plaintext"]))
176
with open(BUILD_DIRECTORY + "/blog/" + post["plaintext"], "w", encoding="utf-8") as PostHTMLFile:
177
PostHTMLFile.write(post["raw-content"])
178
sitemap.append(SITEMAP_HREF + "blog/" + post["pathname"])
179
180
def RenderPage(PageInput: str, ContentDest: str, AllowSitemap: bool = True, **kwargs):
181
print("Building views/%s to %s/%s" % (PageInput, BUILD_DIRECTORY, ContentDest))
182
if AllowSitemap:
183
sitemap.append(SITEMAP_HREF + ContentDest)
184
with open(BUILD_DIRECTORY + "/" + ContentDest, "w", encoding="utf-8") as DestLocation:
185
DestLocation.write(RenderTemplate(PageInput, **kwargs))
186
187
def CreateJSONFeed():
188
global PostList
189
CreatedJSON = {
190
"version": "https://jsonfeed.org/version/1",
191
"title": "Steve0Greatness' Blog",
192
"home_page_url": "https://steve0greatness.github.io",
193
"feed_url": "https://steve0greatness.github.io/blog/feed.rss",
194
"language": "en-US",
195
"favicon": "https://steve0greatness.github.io/favicon.ico",
196
"description": "A blog by a human being.",
197
"authors": [
198
{
199
"name": "Steve0Greatness",
200
"url": "https://steve0greatness.github.io"
201
}
202
],
203
"items": []
204
}
205
for post in PostList:
206
CreatedJSON["items"].append({
207
"id": "https://steve0greatness.github.io/blog/" + post["pathname"],
208
"title": "JSON Feed version 1.1",
209
"icon": "https://steve0greatness.github.io/favicon.ico",
210
"content_html": post["content"],
211
"date_published": post["atom-post-time"],
212
"date_modified": post["atom-update-time"],
213
"url": "https://steve0greatness.github.io/blog/" + post["pathname"]
214
})
215
with open(BUILD_DIRECTORY + "/blog/feed.json", "w") as JSONFeedFile:
216
DumpJSON(CreatedJSON, JSONFeedFile)
217
218
def RenderLists():
219
Lists = GetLists()
220
CreateDirectory(BUILD_DIRECTORY + "/list/")
221
ListIndex = "<ul>"
222
for List in Lists:
223
FileLocation = "/list/" + List["filename"].replace(".yml", ".html")
224
Title = List["title"]
225
print("%s -> %s" % ("lists/" + List["filename"], BUILD_DIRECTORY + FileLocation))
226
with open(BUILD_DIRECTORY + FileLocation, "w") as file:
227
file.write(RenderTemplate("list.html", Content=List["content"], Title=Title, Location=FileLocation))
228
ListIndex += "<li><a href=\"%s\">%s</a></li>" % (FileLocation, Title)
229
ListIndex += "</ul>"
230
print("Building list index")
231
with open(BUILD_DIRECTORY + "/list/index.html", "w") as file:
232
file.write(RenderTemplate("list-index.html", Content=ListIndex))
233
234
def main():
235
global PostList
236
PostList = GetBlogList()
237
print("Wiping directory")
238
WipeFinalDir()
239
print("Creating blog holder")
240
CreateDirectory(BUILD_DIRECTORY + "/blog")
241
print("Rendering posts")
242
RenderPosts()
243
CreateJSONFeed()
244
print("Copying static directory")
245
CopyDirectory("static", BUILD_DIRECTORY)
246
print("Creating lists")
247
RenderLists()
248
249
print("Building pages")
250
for file, path in PAGES.items():
251
AllowSitemap = file not in DISALLOWED_SITEMAP
252
RenderPage(file, path, AllowSitemap, PostList=PostList)
253
254
print("Building redirects")
255
for OldLocation, NewLocation in REDIRECTS.items():
256
RenderPage("redirect.html", OldLocation, False, redirect=NewLocation, old=OldLocation)
257
258
with open(BUILD_DIRECTORY + "/sitemap.txt", "w") as SitemapFile:
259
SitemapFile.write("\n".join(sitemap))
260
261
if __name__ == "__main__":
262
main()