#! /usr/bin/env python3
from __future__ import print_function
from os.path import join, basename
from glob import glob
import re
def find_section_nodes(section_dict, node):
if "section" in node:
section_dict[node["section"]] = node
for subnode in node.get("nodes", []):
find_section_nodes(section_dict, subnode)
class RenderSettings:
def __init__(self, default_icon):
self.default_icon = default_icon
def render(settings, outf, node, indent=0, skip=1):
attrs = {}
icon = settings.default_icon
if "icon" in node:
icon = node["icon"]
attrs["icon"] = icon
if "opened" in node and int(bool(node["opened"])):
attrs["opened"] = True
text = node["text"]
if "section" in node:
text = "%s" % text
if not skip:
from json import dumps
print(
indent * " ",
"
" % dumps(attrs).replace("'", '"'),
file=outf, sep="")
indent += 2
if "link" in node:
print(
indent * " ",
"%s" % (
node["link"],
text),
file=outf, sep="")
else:
print(indent * " ", text, file=outf, sep="")
subnodes = node.get("nodes", [])
if subnodes:
print(indent * " ", "", file=outf, sep="")
indent += 2
for subnode in subnodes:
render(settings, outf, subnode, indent, skip=max(0, skip - 1))
indent -= 2
print(indent * " ", "
", file=outf, sep="")
if not skip:
indent -= 2
print(indent * " ", "", file=outf, sep="")
FN_REGEX = re.compile(r"^([0-9][0-9])-(.*)(\.[a-z]+)$")
def main():
import argparse
parser = argparse.ArgumentParser(
description='Turn a YAML file into a jsTree-compatible data file')
parser.add_argument("-o", "--output-file", metavar="FILE", required=True)
parser.add_argument("--ipynb-dir", metavar="DIRECTORY")
parser.add_argument("--ipynb-urlroot", metavar="URL",
help="(without the trailing slash)")
parser.add_argument("--ipynb-as-py", action="store_true")
parser.add_argument("--ipynb-as-ipynb", action="store_true")
parser.add_argument("--py-dir", metavar="DIRECTORY")
parser.add_argument("--py-urlroot", metavar="URL",
help="(without the trailing slash)")
parser.add_argument("--pdf-dir", metavar="DIRECTORY")
parser.add_argument("--pdf-urlroot", metavar="URL",
help="(without the trailing slash)")
parser.add_argument("--default-icon", metavar="ICON_STR",
default="fa fa-file-o")
parser.add_argument("input_file", metavar="FILE")
args = parser.parse_args()
from yaml import load
with open(args.input_file, "rb") as inf:
root_node = load(inf)
section_dict = {}
find_section_nodes(section_dict, root_node)
# {{{ demos
if args.ipynb_dir is not None:
for fn in sorted(glob(join(args.ipynb_dir, "[0-9]*", "*.ipynb"))):
trunk = fn[len(args.ipynb_dir)+1:]
fn_match = FN_REGEX.match(trunk)
sec_nr = int(fn_match.group(1))
link_ipynb = args.ipynb_urlroot + "/" + trunk
link_html = link_ipynb.replace(".ipynb", ".html")
sub_nodes = [{
"text": "View on the web",
"link": link_html,
"icon": "fa fa-newspaper-o",
}]
if args.ipynb_as_py:
link_py = link_ipynb.replace(".ipynb", ".py")
sub_nodes.append({
"text": "Download Python script",
"link": link_py,
"icon": "fa fa-terminal",
})
if args.ipynb_as_ipynb:
sub_nodes.append({
"text": "Download IPython notebook",
"link": link_ipynb,
"icon": "fa fa-download",
})
demo_node = {
"text": "Demo: " + basename(fn_match.group(2)),
"link": link_html,
"icon": "fa fa-keyboard-o",
"nodes": sub_nodes,
}
section_dict[sec_nr]["nodes"].append(demo_node)
# }}}
# {{{ python source
if args.py_dir is not None:
for fn in sorted(glob(join(args.py_dir, "[0-9]*", "*.py"))):
trunk = fn[len(args.py_dir)+1:]
fn_match = FN_REGEX.match(trunk)
sec_nr = int(fn_match.group(1))
src_node = {
"text": "Code: " + basename(
fn_match.group(2)+fn_match.group(3)),
"link": args.py_urlroot + "/" + trunk,
"icon": "fa fa-file-text-o",
}
section_dict[sec_nr]["nodes"].append(src_node)
# }}}
# {{{ notes
if args.pdf_dir is not None:
for fn in sorted(glob(join(args.pdf_dir, "[0-9]*.pdf"))):
if "autosave" in fn:
continue
trunk = fn[len(args.pdf_dir)+1:]
fn_match = FN_REGEX.match(trunk)
sec_nr = int(fn_match.group(1))
notes_node = {
"text": "PDF: " + basename(
fn_match.group(2)+fn_match.group(3)),
"link": args.pdf_urlroot + "/" + trunk,
"icon": "fa fa-book",
}
section_dict[sec_nr]["nodes"].insert(0, notes_node)
# }}}
with open(args.output_file, "wt") as outf:
render(RenderSettings(default_icon=args.default_icon), outf, root_node)
if __name__ == "__main__":
main()
# vim: foldmethod=marker