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