#!/usr/bin/env python # Copyright 2016 QvarnLabs Ab # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # =*= License: GPL-3+ =*= import os import shutil import subprocess import sys import tempfile import fnmatch import re def process_uml_blocks(mdwnpath, mdwndir, filename): blocks = [] tmproot = os.path.join(T, os.path.splitext(filename)[0] + '_uml') with open(mdwnpath) as f: content = f.read() # Find UML code blocks to be replaced. blocks = re.findall( r"(?:\t| {4})@startuml[\s\S]*?(?:\t| {4})@enduml", content ) for i, block in enumerate(blocks, start=1): umlpath = '%s%d.puml' % (tmproot, i) imgpath = '%s%d.png' % (tmproot, i) # Remove whitespace and save UML file. with open(umlpath, 'w') as f: f.write(re.sub(r"(?m)^(\t| {4})", "", block) + '\n') # Create a diagram image at imgpath and copy it. subprocess.check_call(['plantuml', umlpath]) shutil.copy2(imgpath, mdwndir) # Replace diagram code with a link to the image. content = '' with open(mdwnpath) as f: content = f.read() with open(mdwnpath, 'w') as f: link = '[[!img %s]]' % os.path.basename(imgpath) f.write(re.sub(re.escape(block), link, content)) def process_uml_includes(mdwnpath, mdwndir): includes = [] with open(mdwnpath) as f: content = f.read() # Find include statements, # put file name in a separate group. includes = re.findall( r"(?m)^()", content ) for inc in includes: # Don't need to copy an image this time subprocess.check_call(['plantuml', os.path.join(mdwndir, inc[1])]) # Replace include statement with a link to the image. content = '' with open(mdwnpath) as f: content = f.read() with open(mdwnpath, 'w') as f: link = '[[!img %s.png]]' % os.path.splitext(inc[1])[0] f.write(re.sub('(?m)^' + inc[0], link, content)) def process_uml(T, dirname='.', ignore=['.git', '.ikiwiki']): for topdir, dirs, files in os.walk(os.path.abspath(dirname), topdown=True): # Filter dirs by modifying the list in-place, # as described in os.walk documentation. dirs[:] = [d for d in dirs if d not in ignore] for filename in fnmatch.filter(files, '*.mdwn'): mdwnpath = os.path.join(topdir, filename) process_uml_blocks(mdwnpath, topdir, filename) process_uml_includes(mdwnpath, topdir) def mangle_setup(src, dest, html): with open(src) as f: text = f.read() lines = [ line for line in text.splitlines() if not line.startswith('destdir:') ] lines.append('destdir: {}'.format(html)) mangled = ''.join(line + '\n' for line in lines) with open(dest, 'w') as f: f.write(mangled) def run_ikiwiki(T): setup = os.path.join(T, 'ikiwiki.setup') html = os.path.join(T, 'html') mangle_setup('ikiwiki.setup', setup, html) subprocess.check_call(['ikiwiki', '--setup', setup, '--gettime']) subprocess.check_call( ['rsync', '-ahHSvs', '--delete', html + '/.', rsync_target]) static_http = sys.argv[1] dirname = sys.argv[2] rsync_target = 'static@{}:/srv/http/{}/.'.format(static_http, dirname) T = tempfile.mkdtemp() try: process_uml(T) run_ikiwiki(T) except BaseException as e: shutil.rmtree(T) raise else: shutil.rmtree(T)