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