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