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