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