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