#!/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(S, T, dirname='.', ignore=['.git*', '.ikiwiki']): shutil.copytree( os.path.abspath('.'), S, ignore=shutil.ignore_patterns(*ignore) ) for topdir, dirs, files in os.walk(S, topdown=True): 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, mdwn): with open(src) as f: text = f.read() lines = [ line for line in text.splitlines() if (not line.startswith('srcdir:') or not line.startswith('destdir:')) ] lines.append('srcdir: {}'.format(mdwn)) 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(S, T, locally=False): setup = os.path.join(T, 'ikiwiki.setup') html = os.path.join(T, 'html') mangle_setup('ikiwiki.setup', setup, html, S) subprocess.check_call(['ikiwiki', '--setup', setup, '--gettime']) if not locally: subprocess.check_call( ['rsync', '-ahHSvs', '--delete', html + '/.', rsync_target]) rsync_target = None if len(sys.argv) == 3: static_http = sys.argv[1] dirname = sys.argv[2] rsync_target = 'static@{}:/srv/http/{}/.'.format(static_http, dirname) S = '.publish' T = tempfile.mkdtemp() try: process_uml(S, T) run_ikiwiki(S, T, locally=rsync_target is None) except BaseException as e: shutil.rmtree(S) shutil.rmtree(T) raise else: shutil.rmtree(S) if rsync_target is None: print("Open wiki: firefox %s/html/index.html" % T) else: shutil.rmtree(T)