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