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