#!/usr/bin/python3 # # Script to take the master document and ancillary files and create the # finished manual/website. # # by James Hammons # (C) 2020 Underground Software # # Contributors: Ed Ward # # Remnants (could go into the master document as the first header) import os import re import shutil import argparse import datetime # Global vars global_bootstrap_path = '/bootstrap-3.3.7' global_page_title = 'The Ardour Manual' global_site_dir = './website/' global_manual_url = 'http://manual.ardour.org' global_githuburl = 'https://github.com/Ardour/manual/edit/master/include/' global_screen_template = 'page-template.html' global_onepage_template = 'onepage-template.html' global_pdf_template = 'pdf-template.html' global_master_doc = 'master-doc.txt' global_pdflink = '' from datetime import datetime global_today = datetime.today().strftime('%Y-%m-%d') # This matches all *non* letter/number, ' ', '.', '-', and '_' chars cleanString = re.compile(r'[^a-zA-Z0-9 \._-]+') # This matches new 'unbreakable' links, up to the closing quote or anchor findLinks = re.compile(r'"@@[^#"]*[#"]') # # Create an all lowercase filename without special characters and with spaces # replaced with dashes. # def MakeFilename(s): global cleanString # Clean up the file name, removing all non letter/number or " .-_" chars. # Also, convert to lower case and replace all spaces with dashes. fn = cleanString.sub('', s).lower().replace(' ', '-') # Double dashes can creep in from the above replacement, so we check for # that here. fn = fn.replace('--', '-') return fn # # Parse headers into a dictionary # def ParseHeader(fileObj): header = {} while (True): hdrLine = fileObj.readline().rstrip('\r\n') # Break out of the loop if we hit the end of header marker if hdrLine.startswith('---'): break # Check to see that we have a well-formed header construct match = re.findall(': ', hdrLine) if match: # Parse out foo: bar pairs & put into header dictionary a = re.split(': ', hdrLine, 1) header[a[0]] = a[1] return header # # Turn a "part" name into an int # def PartToLevel(s): lvl = {'part': 0, 'chapter': 1, 'subchapter': 2, 'section': 3, 'subsection': 4 } if s in lvl: return lvl[s] return -1 # # Converts a integer to a Roman numeral # def num2roman(num): num_map = [(1000, 'M'), (900, 'CM'), (500, 'D'), (400, 'CD'), (100, 'C'), (90, 'XC'), (50, 'L'), (40, 'XL'), (10, 'X'), (9, 'IX'), (5, 'V'), (4, 'IV'), (1, 'I')] roman = '' while num > 0: for i, r in num_map: while num >= i: roman += r num -= i return roman # # Capture the master document's structure (and content, if any) in a list # def GetFileStructure(): fs = [] fnames = [None] * 6 content = '' grab = False mf = open(global_master_doc) for ln in mf: if ln.startswith('---'): # First, stuff any content that we may have read into the current # header's dictionary if grab: fs[-1]['content'] = content grab = False content = '' # Then, get the new header and do things to it hdr = ParseHeader(mf) level = PartToLevel(hdr['part']) hdr['level'] = level fnames[level] = MakeFilename(hdr['title']) # Ickyness--user specified URIs if 'uri' in hdr: hdr['filename'] = hdr['uri'] else: fullName = '' for i in range(level + 1): fullName = fullName + fnames[i] + '/' # Strip trailing '/' on filename hdr['filename'] = fullName[:-1] fs.append(hdr) if ('include' not in hdr) and (level > 0): grab = True else: if grab: content = content + ln # Catch the last file, since it would be missed above if grab: fs[-1]['content'] = content mf.close() return fs # # Determine if a particular node has child nodes # def HaveChildren(fs, pos): # If we're at the end of the list, there can be no children if pos == len(fs) - 1: return False # If the next node is at a lower level than the current node, we have # children. if fs[pos]['level'] < fs[pos + 1]['level']: return True # Otherwise, no children at this node. return False # # Get the children at this level, and return them in a list # def GetChildren(fs, pos): children = [] pos = pos + 1 childLevel = fs[pos]['level'] while fs[pos]['level'] >= childLevel: if fs[pos]['level'] == childLevel: children.append(pos) pos = pos + 1 # Sanity check if pos == len(fs): break return children # # Get the parent at this level # def GetParent(fs, pos): thisLevel = fs[pos]['level'] pos = pos - 1 while pos >= 0 and fs[pos]['level'] >= thisLevel: pos = pos - 1 return pos # # Change the hierarchy of titles :
Ch. ' + str(levelNums[level]) + ': ' + header['title'] + '
\n' elif level == 2: toc = toc + '\t\t\n' elif level == 3: toc = toc + '\n' elif level == 4: toc = toc + '\n' # Make the 'this thing contains...' stuff if HaveChildren(fileStruct, pageNumber): pages = GetChildren(fileStruct, pageNumber) for pg in pages: more = more + '