!/usr/bin/env python import argparse import re import sys import knittingneedles as knit

parser = argparse.ArgumentParser(

description="Extract specially formatted diffs from tutorials as a series of patches to apply"

) parser.add_argument(“tutorial”, type=argparse.FileType(“r+”), help=“Input tutorial”) parser.add_argument(

"--patches", nargs='+', help="The patches to knit together with the tutorial"

) args = parser.parse_args() tutorial_contents = args.tutorial.read().split(“n”) chunks = []

# load patches diffs = [] for patch in args.patches:

with open(patch, "r") as handle:
    data = handle.readlines()
    subject = [x for x in data[0:5] if x.startswith('Subject:')]
    if len(subject) != 1:
        commit = "MISSING"
    else:
        if subject[0].count(": ") >= 2:
            commit = subject[0].split(": ")[2]
        else:
            commit = "MISSING"

    indexindex = [idx for (idx, x) in enumerate(data) if x.startswith('index ')]
    if len(indexindex) == 0:
        # take a guess, it's our format?
        data = [x.rstrip("\n") for x in data[5:-3]]
    else:
        # If 'index ' then we start at the next line
        data = [x.rstrip("\n") for x in data[indexindex[0] + 1:-3]]

    diffs.append((commit, data))

current = None diff_idx = 0 prev_line = None for line, text in enumerate(tutorial_contents):

m = re.match(knit.BOXES, text)
if m:
    depth = m.group(1).count(">")
else:
    depth = 0
(unprefixed, prefix) = knit.stripN(text, depth)
m0 = re.match(knit.BOX_PREFIX, unprefixed)
m1 = re.match(knit.BOX_OPEN, unprefixed)
m2 = re.match(knit.BOX_CLOSE, unprefixed)

if m0:
    current = []
if m1 and current is None:
    current = []

if current is not None:
    current.append(unprefixed)
else:
    chunks.append(text)

if current and len(current) > 2 and (current[-2].strip() == "```") and not m2:
    chunks.extend([prefix + x for x in current])
    # chunks.append('REJECT)')
    current = None

if m2 and current and len(current) > 0:
    (amount, _) = knit.removeWhitespacePrefix(current)
    prefix_text = prefix + (amount * " ")
    from_patch = diffs[diff_idx]

    # Compare the diff messages
    obs_msg = knit.extractCommitMsg(current).strip()
    exp_msg = from_patch[0].strip()
    obs_extra = m2.groups()[1]
    if obs_msg != exp_msg:
        # Most just got truncated
        if exp_msg not in obs_msg:
            print(f"WARNING: Diff messages do NOT line up: {obs_msg} != {exp_msg}")
        # Replace with current message
        exp_msg = obs_msg

    # Knit it anyway
    new_diff = from_patch[1]
    chunks.append(prefix_text + "{% raw %}")
    chunks.append(prefix_text + "```diff")
    chunks.extend([f'{prefix}{amount * " "}{line}' for line in new_diff])
    chunks.append(prefix_text + "{% endraw %}")
    chunks.append(prefix_text + "```")
    chunks.append(prefix_text + '{: data-commit="%s"%s}' % (exp_msg, obs_extra))
    diff_idx += 1
    current = None

prev_line = text

# Overwrite the original tutorial args.tutorial.seek(0) args.tutorial.truncate(0) # The last chunk is a newline for some reason. for c in chunks:

args.tutorial.write(c + "\n")

args.tutorial.close()