"""Extraction unique : kanban.html -> DOCS/kanban/ + kanban-template.html. Une carte = un fichier, un « fait recemment » = un fichier. Ensuite kanban.html est regenere par build_kanban.py et ne s'edite plus a la main. """ import io import json import os import re import unicodedata DOCS = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SRC = os.path.join(DOCS, "kanban.html") KANBAN = os.path.join(DOCS, "kanban") CARDS_DIR = os.path.join(KANBAN, "cards") DONE_DIR = os.path.join(KANBAN, "done") BOARD_OUT = os.path.join(KANBAN, "board.json") TPL_OUT = os.path.join(DOCS, "kanban-template.html") def write(path, text): io.open(path, "w", encoding="utf-8", newline="\n").write(text) def slug(text, maxlen=45): text = re.sub(r"<[^>]+>", "", text) text = unicodedata.normalize("NFKD", text).encode("ascii", "ignore").decode() text = re.sub(r"[^a-zA-Z0-9]+", "-", text).strip("-").lower() return text[:maxlen].rstrip("-") or "sans-titre" html = io.open(SRC, encoding="utf-8", newline="").read() masthead = re.search(r'
(.*?)
', html, re.S).group(1) intro = [p.strip() for p in re.findall(r"

(.*?)

", masthead, re.S)] stamp = re.search(r'
(.*?)
', masthead, re.S).group(1).strip() summary_block = re.search(r'
', html, re.S).group(0) stats = re.findall(r'(\d+)([^<]*)', summary_block) stat_class = {k: cls.strip() for cls, n, k in stats} done_start = html.index('
') board_start = html.index('
') board_end = html.rindex("
", 0, done_start) board_end = html.index("", board_end) + len("") board = html[board_start:board_end] columns = [] n_cards = 0 for pos, col in enumerate( re.finditer( r'\s*
\s*' r'

([^<]*)

\d+
\s*' r'
(.*?)
\s*
', board, re.S, ), start=1, ): comment, stripe, title, stack = col.groups() dirname = "%d-%s" % (pos, slug(title)) os.makedirs(os.path.join(CARDS_DIR, dirname), exist_ok=True) for rank, card in enumerate(re.finditer(r'
]*)>(.*?)
', stack, re.S), start=1): attrs, inner = card.groups() horizon = re.search(r'data-horizon="([^"]*)"', attrs) meta = re.search(r'
(.*?)
', inner, re.S).group(1) flag = re.search(r'(.*?)', meta, re.S) card_title = re.search(r"

(.*?)

", inner, re.S).group(1).strip() front = ["title: " + card_title, "area: " + re.search(r'data-area="([^"]*)"', attrs).group(1)] if horizon: front.append("horizon: " + horizon.group(1)) front.append("tags: " + ", ".join(re.findall(r'(.*?)', meta, re.S))) if flag: front.append("flag: %s | %s" % (flag.group(1), flag.group(2).strip())) front.append("src: " + re.search(r'(.*?)', inner, re.S).group(1).strip()) body = "\n".join("

%s

" % p.strip() for p in re.findall(r"

(.*?)

", inner, re.S)) write( os.path.join(CARDS_DIR, dirname, "%03d-%s.md" % (rank * 10, slug(card_title))), "---\n" + "\n".join(front) + "\n---\n" + body + "\n", ) n_cards += 1 columns.append( {"dir": dirname, "title": title, "stripe": stripe, "statClass": stat_class.get(title, ""), "comment": comment} ) done_section = html[done_start : html.index("
", html.index('
', done_start))] os.makedirs(DONE_DIR, exist_ok=True) n_done = 0 for rank, item in enumerate(re.finditer(r'
\s*(.*?)\s*
', done_section, re.S), start=1): inner = item.group(1) title = re.search(r"(.*?)", inner, re.S).group(1).strip() body = inner[inner.index("") + len("") :].strip() write( os.path.join(DONE_DIR, "%03d-%s.md" % (rank * 10, slug(title))), "---\ntitle: " + title + "\n---\n" + body + "\n", ) n_done += 1 board_meta = { "updated": re.search(r"Mise à jour · ([\d-]+)", stamp).group(1), "stampNote": stamp.split("
")[-1].strip(), "intro": intro, "columns": columns, "done": { "heading": re.search(r"

(.*?)

", done_section, re.S).group(1).strip(), "statLabel": next((k for k in stat_class if "Fait" in k), "Fait récemment"), "statClass": next((v for k, v in stat_class.items() if "Fait" in k), "n-good"), "intro": re.search(r"

(.*?)

", done_section, re.S).group(1).strip(), }, } write(BOARD_OUT, json.dumps(board_meta, ensure_ascii=False, indent=2) + "\n") template = ( html[: html.index('
')] + '
\n
\n ' + re.search(r"

.*?

", masthead, re.S).group(0) + "\n{{INTRO}}\n" + '
\n {{STAMP}}\n
\n
\n\n' + "{{SUMMARY}}\n\n" + html[html.index('
", html.index('
')) + len("") :] ) write(TPL_OUT, template) print("cartes : %d fait-recemment : %d" % (n_cards, n_done)) for c in columns: print(" %-14s %2d" % (c["title"], len(os.listdir(os.path.join(CARDS_DIR, c["dir"]))))) print("board.json %d o template %d o" % (os.path.getsize(BOARD_OUT), os.path.getsize(TPL_OUT)))