2021-08-14 16:04:22 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
2021-08-26 22:22:48 +00:00
|
|
|
import html
|
2021-08-14 16:04:22 +00:00
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import uuid
|
|
|
|
from datetime import datetime
|
|
|
|
|
2021-08-26 22:22:48 +00:00
|
|
|
from org_rw import OrgTime, dom
|
2021-08-14 16:04:22 +00:00
|
|
|
from org_rw import dump as dump_org
|
|
|
|
from org_rw import load as load_org
|
2021-08-26 22:22:48 +00:00
|
|
|
from org_rw import token_list_to_raw
|
2021-08-14 16:04:22 +00:00
|
|
|
|
|
|
|
EXTENSIONS = [
|
|
|
|
".org",
|
|
|
|
".org.txt",
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def load_all(top_dir_relative):
|
|
|
|
top = os.path.abspath(top_dir_relative)
|
|
|
|
|
|
|
|
docs = []
|
|
|
|
|
|
|
|
for root, dirs, files in os.walk(top):
|
|
|
|
for name in files:
|
|
|
|
if ".org" not in name:
|
|
|
|
continue
|
|
|
|
|
|
|
|
path = os.path.join(root, name)
|
|
|
|
|
|
|
|
try:
|
|
|
|
doc = load_org(open(path), extra_cautious=True)
|
|
|
|
docs.append(doc)
|
|
|
|
except Exception as err:
|
|
|
|
import traceback
|
|
|
|
|
|
|
|
traceback.print_exc()
|
|
|
|
print(f"== On {path}")
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
logging.info("Collected {} files".format(len(docs)))
|
|
|
|
return docs
|
|
|
|
|
|
|
|
|
|
|
|
def main(src_top, dest_top):
|
|
|
|
docs = load_all(src_top)
|
2021-08-26 22:22:48 +00:00
|
|
|
files_generated = 0
|
2021-08-14 16:04:22 +00:00
|
|
|
|
|
|
|
os.makedirs(dest_top, exist_ok=True)
|
|
|
|
for doc in docs:
|
|
|
|
relpath = os.path.relpath(doc.path, src_top)
|
|
|
|
changed = False
|
2021-09-03 18:19:45 +00:00
|
|
|
headlines = list(doc.getAllHeadlines())
|
2021-08-14 16:04:22 +00:00
|
|
|
related = None
|
|
|
|
|
|
|
|
i = len(headlines)
|
|
|
|
while i > 0:
|
|
|
|
i -= 1
|
|
|
|
headline = headlines[i]
|
2021-09-03 18:19:45 +00:00
|
|
|
if headline.title.strip().lower() == "related" and headline.depth == 1:
|
|
|
|
if related is not None:
|
|
|
|
print(
|
|
|
|
"Found duplicated related: {} vs {}".format(
|
|
|
|
related.id, headline.id
|
|
|
|
)
|
|
|
|
)
|
|
|
|
assert related is None
|
2021-08-14 16:04:22 +00:00
|
|
|
related = headline
|
|
|
|
headlines.pop(i)
|
|
|
|
|
|
|
|
for headline in headlines:
|
|
|
|
if headline.id is None:
|
|
|
|
headline.id = str(uuid.uuid4())
|
|
|
|
changed = True
|
|
|
|
|
|
|
|
if changed:
|
|
|
|
print("Updated", relpath)
|
|
|
|
save_changes(doc)
|
|
|
|
|
|
|
|
if not relpath.startswith("public/"):
|
|
|
|
# print("Skip:", relpath)
|
|
|
|
continue
|
2021-08-26 22:22:48 +00:00
|
|
|
|
|
|
|
for headline in headlines:
|
|
|
|
endpath = os.path.join(dest_top, headline.id + ".node.html")
|
|
|
|
|
|
|
|
with open(endpath, "wt") as f:
|
2021-09-03 22:26:10 +00:00
|
|
|
f.write(as_document(render(headline, doc)))
|
2021-08-26 22:22:48 +00:00
|
|
|
files_generated += 1
|
|
|
|
|
|
|
|
logging.info("Generated {} files".format(files_generated))
|
|
|
|
|
|
|
|
|
|
|
|
def print_tree(tree, indentation=0):
|
|
|
|
for element in tree:
|
|
|
|
print(" " * indentation + "- " + str(type(element)))
|
|
|
|
if "children" in dir(element):
|
|
|
|
if len(element.children) > 0:
|
|
|
|
print_tree(element.children, indentation + 1)
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
|
|
def render_property_drawer(element, acc):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def render_logbook_drawer(element, acc):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def render_property_node(element, acc):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def render_list_group(element, acc):
|
|
|
|
acc.append("<ul>")
|
|
|
|
render_tree(element.children, acc)
|
|
|
|
acc.append("</ul>")
|
|
|
|
|
|
|
|
|
|
|
|
def render_list_item(element, acc):
|
|
|
|
acc.append("<li>")
|
|
|
|
if element.content.tag is not None:
|
|
|
|
acc.append("<span class='tag'>")
|
|
|
|
acc.append(element.content.tag)
|
|
|
|
acc.append("</span>")
|
|
|
|
|
|
|
|
acc.append("<span class='item'>")
|
|
|
|
acc.append(token_list_to_raw(element.content.content))
|
|
|
|
acc.append("</span></li>")
|
|
|
|
|
|
|
|
|
|
|
|
def render_code_block(element, acc):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def render_text(element, acc):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def render_tag(element, acc):
|
|
|
|
return {
|
|
|
|
dom.PropertyDrawerNode: render_property_drawer,
|
|
|
|
dom.LogbookDrawerNode: render_logbook_drawer,
|
|
|
|
dom.PropertyNode: render_property_node,
|
|
|
|
dom.ListGroupNode: render_list_group,
|
|
|
|
dom.ListItem: render_list_item,
|
|
|
|
dom.CodeBlock: render_code_block,
|
|
|
|
dom.Text: render_text,
|
|
|
|
}[type(element)](element, acc)
|
|
|
|
|
|
|
|
|
|
|
|
def render_tree(tree, acc):
|
|
|
|
for element in tree:
|
|
|
|
render_tag(element, acc)
|
|
|
|
|
|
|
|
|
|
|
|
def render(headline, doc):
|
|
|
|
print("\n===========")
|
|
|
|
dom = headline.as_dom()
|
|
|
|
print_tree(dom)
|
|
|
|
|
|
|
|
content = []
|
|
|
|
render_tree(dom, content)
|
|
|
|
|
2021-09-03 18:19:45 +00:00
|
|
|
if headline.state is None:
|
|
|
|
state = ""
|
|
|
|
else:
|
|
|
|
state = f'<span class="state todo-{headline.is_todo} state-{headline.state}">{headline.state}</span>'
|
|
|
|
|
|
|
|
if headline.is_todo:
|
|
|
|
todo_state = "todo"
|
|
|
|
else:
|
|
|
|
todo_state = "done"
|
2021-08-26 22:22:48 +00:00
|
|
|
return f"""
|
2021-09-03 22:26:10 +00:00
|
|
|
<div id="{html.escape(headline.id)}" class="node {todo_state}">
|
2021-08-26 22:22:48 +00:00
|
|
|
<h1 class="title">
|
2021-09-03 18:19:45 +00:00
|
|
|
{state}
|
2021-08-26 22:22:48 +00:00
|
|
|
<a href=\"org-protocol://org-id?id={html.escape(headline.id)}\">
|
|
|
|
{html.escape(headline.title)}
|
|
|
|
</a>
|
|
|
|
</h1>
|
|
|
|
|
|
|
|
{''.join(content)}
|
2021-09-03 22:26:10 +00:00
|
|
|
</div>
|
2021-08-26 22:22:48 +00:00
|
|
|
"""
|
2021-08-14 16:04:22 +00:00
|
|
|
|
|
|
|
|
2021-09-03 22:26:10 +00:00
|
|
|
def as_document(html):
|
|
|
|
return f"""
|
|
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<link href="../static/style.css" rel="stylesheet"/>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
{html}
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
2021-08-14 16:04:22 +00:00
|
|
|
def save_changes(doc):
|
|
|
|
assert doc.path is not None
|
|
|
|
with open(doc.path, "wt") as f:
|
2021-09-03 18:19:45 +00:00
|
|
|
dump_org(doc, f)
|
2021-08-14 16:04:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
if len(sys.argv) != 3:
|
|
|
|
print("Usage: {} SOURCE_TOP DEST_TOP".format(sys.argv[0]))
|
|
|
|
exit(0)
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")
|
|
|
|
main(sys.argv[1], sys.argv[2])
|