#!/usr/bin/env python3
"""Render resume.yaml -> MikeEberlein_Resume.odt.
Builds the ODT zip from scratch (mimetype, manifest, meta, styles, content).
The ODT styling lives inline as STYLES below; content comes from resume.yaml.
DOCX is produced by piping this output through LibreOffice:
soffice --headless --convert-to docx MikeEberlein_Resume.odt
"""
import os
import shutil
import sys
import yaml
import zipfile
HERE = os.path.dirname(os.path.abspath(__file__))
DATA = os.path.join(HERE, "resume.yaml")
OUT = os.path.join(HERE, "MikeEberlein_Resume.odt")
MIMETYPE = "application/vnd.oasis.opendocument.text"
MANIFEST = '''
'''
META = '''
Mike Eberlein Resumerender_odt.py
'''
STYLES = '''
'''
CONTENT_HEAD = '''
'''
CONTENT_TAIL = ''
# ---------- XML helpers ----------
XML_ESCAPES = {"&": "&", "<": "<", ">": ">"}
def xesc(s: str) -> str:
return "".join(XML_ESCAPES.get(c, c) for c in s)
def p(style, content):
return f'{content}'
def b(text):
return f'{xesc(text)}'
def i(text):
return f'{xesc(text)}'
TAB = ''
def bullet(text, style="Bullet"):
return (f''
f'{xesc(text)}'
f'')
def render(data) -> str:
parts = []
h = data["header"]
parts.append(p("Name", xesc(h["name"])))
contact = f'{xesc(h["tagline"])} • {xesc(h["email"])}'
parts.append(p("Contact", contact))
parts.append(p("Summary", xesc(data["summary"].strip())))
parts.append(p("SectionHead", "EXPERIENCE"))
for company in data["experience"]:
parts.append(f'{b(company["company"])}{TAB}{xesc(company["dates"])}')
for role in company["roles"]:
parts.append(f'{i(role["title"])}{TAB}{i(role["dates"])}')
if "subroles" in role:
for sr in role["subroles"]:
parts.append(f'{xesc(sr["title"])}{TAB}{i(sr["dates"])}')
for blt in sr["bullets"]:
parts.append(bullet(blt, style="SubBullet"))
elif "bullets" in role:
for blt in role["bullets"]:
parts.append(bullet(blt, style="Bullet"))
parts.append(p("SectionHead", "EDUCATION"))
for ed in data["education"]:
parts.append(f'{b(ed["school"])}{TAB}{xesc(ed["dates"])}')
for blt in ed["bullets"]:
parts.append(bullet(blt, style="Bullet"))
parts.append(p("SectionHead", "CERTIFICATIONS"))
parts.append(p("Standard", " • ".join(xesc(c) for c in data["certifications"])))
return CONTENT_HEAD + "".join(parts) + CONTENT_TAIL
def main():
with open(DATA, "r", encoding="utf-8") as f:
data = yaml.safe_load(f)
content = render(data)
with zipfile.ZipFile(OUT, "w", zipfile.ZIP_DEFLATED) as z:
zi = zipfile.ZipInfo("mimetype")
zi.compress_type = zipfile.ZIP_STORED
z.writestr(zi, MIMETYPE)
z.writestr("META-INF/manifest.xml", MANIFEST)
z.writestr("meta.xml", META)
z.writestr("styles.xml", STYLES)
z.writestr("content.xml", content)
print(f"wrote {OUT}")
if __name__ == "__main__":
main()