SiteGenerator/gsitegen/generate.py

255 lines
7.7 KiB
Python
Raw Normal View History

2022-01-22 09:26:09 +00:00
from html5tagger import Document, E, HTML
2022-02-01 16:36:30 +00:00
import shutil
2022-01-24 10:09:04 +00:00
import markdown
import html
2022-01-26 10:03:25 +00:00
from pathlib import Path
2022-01-21 10:16:26 +00:00
2022-02-07 12:18:31 +00:00
def parseLink(link, pagetitle, homepage):
if link.strip() == pagetitle + ".page":
return "#"
elif link.strip() == homepage + ".page":
return "/"
else:
destination = link.replace(" ", "-").replace(".page", "").lower()
#Start local links with / symbol
if link.strip().endswith(".page"):
return "/" + destination
return destination
2022-02-03 13:34:15 +00:00
def generateNavigationBar(lines, pagetitle):
2022-01-22 09:54:31 +00:00
global navbar
navbar = E
2022-01-25 14:05:07 +00:00
rawhtml = False
htmlstring = ""
dropdown = False
2022-01-24 13:20:08 +00:00
for id, line in enumerate(lines):
2022-01-24 10:35:29 +00:00
2022-01-25 14:05:07 +00:00
#parse raw HTML
rawhtml, navbar, htmlstring = parseRawHTML(navbar, line, htmlstring, rawhtml, id, len(lines))
2022-02-03 13:34:15 +00:00
#parse navigation bar (custom format)
2022-01-25 14:05:07 +00:00
if not rawhtml:
if ";" in line:
title, link = line.split(";", 1)
if line.strip().endswith("|"):
dropdown = True
2022-02-07 12:18:31 +00:00
link = link.strip()[:len(link.strip())-1]
dphtml = E
2022-02-07 12:18:31 +00:00
#some duplicate logic as normal navbar entries get, to make dropdown button in itself act like a normal clickable navbar entry
link = parseLink(link, pagetitle, homepage)
if link.strip() == "#":
dphtml = dphtml(HTML("<div class='dropdown'><div class='dropbutton'><div class='active'><a href='" + link.strip() + "'>" + title + "</a></div></div><div class='dropdown-content'>"))
else:
dphtml = dphtml(HTML("<div class='dropdown'><div class='dropbutton'><a href='" + link.strip() + "'>" + title + "</a></div><div class='dropdown-content'>"))
continue
elif dropdown:
if line.startswith(" "):
2022-02-07 12:18:31 +00:00
link = parseLink(link, pagetitle, homepage)
if link.strip() == "#":
dphtml = dphtml(HTML("<div class='active'><a href='" + link.strip() + "'>" + title + "</a></div>"))
else:
dphtml = dphtml(HTML("<a href='" + link.strip() + "'>" + title + "</a>"))
#handle end of indentation (if indented line is the last line of page or next line is not indented)
if len(lines) - id == 1 or lines[id + 1].startswith(" ") is False:
dphtml = dphtml(HTML("</div></div>"))
navbar = navbar.li(dphtml)
dropdown = False
continue
2022-02-07 12:18:31 +00:00
2022-02-03 13:34:15 +00:00
#mark currently open tab as active when it is open
2022-02-07 12:18:31 +00:00
link = parseLink(link, pagetitle, homepage)
if link.strip() == "#":
navbar = navbar.li(HTML("<div class='active'>" + "<a href='" + link.strip() + "'>" + title + "</a></div>"))
2022-02-07 12:18:31 +00:00
continue
navbar = navbar.li(HTML("<a href='" + link.strip() + "'>" + title + "</a>"))
2022-02-03 14:35:28 +00:00
else:
print("Error: invalid navbar entry, line " + str(id + 1) + " content: " + line)
exit()
2022-02-03 13:34:15 +00:00
return navbar
2022-02-07 12:18:31 +00:00
def generateFooter(lines):
global footer
footer = E
rawhtml = False
htmlstring = ""
for id, line in enumerate(lines):
#parse raw HTML
rawhtml, footer, htmlstring = parseRawHTML(footer, line, htmlstring, rawhtml, id, len(lines))
#parse markdown
if not rawhtml:
footer = footer.li(HTML(parseMarkdown(footer, line)))
2022-01-24 13:20:08 +00:00
def parseRawHTML(doc, line, htmlstring, rawhtml, id, maxlines):
2022-01-26 10:36:59 +00:00
#raw html start
if line.strip() == ">":
rawhtml = True
htmlstring = ""
#parse indented raw html
elif rawhtml:
if line.startswith(" "):
#experimental markdown inside HTML support
htmlstring = htmlstring + html.unescape(markdown.markdown(html.escape(line.strip())))
2022-01-24 13:20:08 +00:00
#if indented html was the last line, this is needed for it to not be ignored
2022-01-24 14:06:16 +00:00
#since this is the end of the file, we will not set rawhtml to False.
2022-01-24 13:20:08 +00:00
if maxlines - id == 1:
doc.div(HTML(htmlstring))
else:
rawhtml = False
2022-01-24 13:20:08 +00:00
doc.div(HTML(htmlstring))
htmlstring = ""
return rawhtml, doc, htmlstring
def parseMarkdown(doc, line):
2022-01-26 10:36:59 +00:00
2022-01-26 10:03:25 +00:00
#do not allow HTML in markdown
line = html.escape(line.strip())
return markdown.markdown(line)
2022-01-22 14:06:25 +00:00
def generateLines(title, lines):
title = title.replace(".page", "")
doc = Document(title, lang="en")
2022-01-24 10:09:04 +00:00
rawhtml = False
htmlstring = ""
2022-01-24 13:20:08 +00:00
for id, line in enumerate(lines):
2022-01-24 10:09:04 +00:00
#parse raw HTML
2022-01-24 13:20:08 +00:00
rawhtml, doc, htmlstring = parseRawHTML(doc, line, htmlstring, rawhtml, id, len(lines))
2022-01-24 10:09:04 +00:00
#parse markdown
if not rawhtml:
doc = doc(HTML(parseMarkdown(doc, line)))
2022-01-24 10:09:04 +00:00
generatePage(title, doc)
2022-01-22 14:06:25 +00:00
def generatePage(title, doc):
2022-01-26 10:03:25 +00:00
global pages
global titles
if 'pages' not in globals():
pages = []
if 'titles' not in globals():
titles = []
2022-01-26 10:08:19 +00:00
2022-02-03 13:34:15 +00:00
navbarfile = Path(__file__).parent.joinpath('navbar')
if navbarfile.exists():
with navbarfile.open('r') as navbarfile:
navbar = generateNavigationBar(navbarfile.readlines(), title)
if 'footer' in globals():
pages.append(str(E.ul(navbar)) + str(doc) + str(E.ul(footer)))
else:
pages.append(str(E.ul(navbar)) + str(doc))
2022-01-26 10:03:25 +00:00
else:
2022-02-03 13:34:15 +00:00
print("No 'navbar' file found, there will be no navigation bar.")
if 'footer' in globals():
pages.append(str(doc) + str(E.ul(footer)))
else:
pages.append(str(doc))
2022-02-03 13:34:15 +00:00
2022-01-26 10:36:59 +00:00
titles.append(title)
2022-01-26 10:03:25 +00:00
2022-02-03 13:34:15 +00:00
def writePages():
2022-01-26 10:03:25 +00:00
global pages
global titles
#TODO only delete files that aren't present in newest site generation
#deleting contents of folder without deleting the folder, to increase compatibility with various systems
#for root, dirs, files in os.walk('./website-output'):
# for f in files:
# os.unlink(os.path.join(root, f))
# for d in dirs:
# rmtree(os.path.join(root, d))
for id, page in enumerate(pages):
foldername = ""
2022-01-26 10:36:59 +00:00
2022-01-26 10:03:25 +00:00
#creates ./website-output/pagetitle/index.html file if it is not homepage
if titles[id] != homepage:
2022-02-01 16:36:30 +00:00
foldername = titles[id].replace(" ", "-").lower()
outputpath = Path(__file__).parent.joinpath("website-output")
dirpath = outputpath.joinpath(foldername)
2022-01-26 10:03:25 +00:00
2022-01-27 11:02:35 +00:00
dirpath.mkdir(parents=True, exist_ok=True)
2022-01-26 10:03:25 +00:00
2022-01-27 11:02:35 +00:00
filepath = dirpath.joinpath("index.html")
2022-01-27 10:11:33 +00:00
2022-01-27 10:29:24 +00:00
if filepath.exists():
with filepath.open('r') as newpage:
2022-01-26 10:08:19 +00:00
if newpage.read() == page:
2022-01-26 10:36:59 +00:00
print("Page not changed: " + titles[id])
continue
2022-01-27 10:11:33 +00:00
2022-01-27 10:29:24 +00:00
with filepath.open('w') as newpage:
2022-01-26 10:36:59 +00:00
newpage.write(page)
print("Written changed page: " + titles[id])
2022-01-24 16:49:02 +00:00
2022-01-31 10:56:41 +00:00
#resources
respath = Path(__file__).parent.joinpath("resources")
if respath.exists():
2022-02-01 16:36:30 +00:00
#shutil.copytree copies timestamp too
shutil.copytree(respath, outputpath, dirs_exist_ok=True)
#check if folders are named correctly
for folder in outputpath.iterdir():
if folder.is_dir():
#rename folder name format from "About Page" to "about-page"
bettername = folder.name.replace(" ", "-").lower()
if folder.name != bettername:
newpath = outputpath.joinpath(bettername)
#example: resources folder is "About", page got auto-created earlier as "about" (from About.page), let's copy "About" resources to "about" and delete "About"
if newpath.exists():
shutil.copytree(folder, newpath, dirs_exist_ok=True)
shutil.rmtree(folder)
else:
shutil.move(str(folder), newpath)
2022-01-24 16:49:02 +00:00
def main():
2022-01-26 10:36:59 +00:00
2022-01-24 16:49:02 +00:00
#if homepage is at Home.page, set homepage to "Home"
2022-02-03 13:34:15 +00:00
global homepage
2022-01-24 16:49:02 +00:00
homepage = "Home"
footerfile = Path(__file__).parent.joinpath('footer')
if footerfile.exists():
with footerfile.open('r') as footerfile:
generateFooter(footerfile.readlines())
else:
print("No 'footer' file found, there will be no footer.")
2022-01-24 16:49:02 +00:00
pagescount = 0
2022-01-27 10:29:24 +00:00
for file in Path(__file__).parent.iterdir():
if file.is_file():
2022-01-27 11:02:35 +00:00
if file.suffix == ".page":
2022-01-27 10:29:24 +00:00
pagescount += 1
with file.open('r') as page:
2022-01-27 11:03:53 +00:00
generateLines(file.stem, page.readlines())
2022-01-26 10:03:25 +00:00
print("Found " + str(pagescount) + " pages")
2022-01-26 10:36:59 +00:00
#write all pages to files
2022-02-03 13:34:15 +00:00
writePages()
2022-01-24 16:49:02 +00:00
if __name__ == "__main__":
2022-01-26 10:03:25 +00:00
main()