Wissensmanagement in der Architekturarbeit, Teil 1
Die Anforderungen
In der Architekturarbeit werden relativ viele Dokumente (Konzepte, Richtlinien, Architecture Decision Records) verfasst und auch verarbeitet, d.h. wir zitieren oder verweisen z.B. sehr häufig auf Sicherheitsrichtlinien wie die Anweisung zur Transportverschlüsselung.
Wir möchten die dazu notwendigen Arbeitsschritte vereinfachen und mit dem bereits etablierten Arbeitsmodell verbinden. Dieses basiert auf einem zentralen Sourcecodemanagementsystem, in dem Quellcodedateien gepflegt werden. Die Betriebsteams nutzen hierzu Gitlab zum einen als verfügbares Sourcecodemanagementsystem, um die Quellcodedateien entsprechend zu versionieren und die verschiedenen Autoren und Entwicklungsstände zu managen. Zum anderen bietet Gitlab mit der integrierten CI/CD-Pipeline vielfältige Automatisierungsmöglichkeiten.
Beides möchten wir mit unserem Workflow ebenfalls nutzen.
Welche Anforderungen haben wir hier konkret?
-
Dokumente in einem Textformat erstellen
-
Dokumente als Text-Dateien in Gitlab versionieren
-
Die Dokumente müssen zwingend Diagramme beinhalten können
-
Die Diagramme sollen aus einem Textformat konvertiert werden
-
Textbausteine sollen aus anderen Dateien inkludiert werden können
-
Komplexe Dokumenten sollen sich in mehrer Dateien zerlegen lassen können
-
-
Dokumente in PDF konvertieren und als PDF außerhalb des Gitlab zirkulieren lassen
- Dokumente in PDF konvertieren und als PDF in der eAkte vorschriftsgemäß versenken
-
Die PDF-Konvertierung soll in der Gitlab-Pipeline automatisiert stattfinden
-
Eine zentraler Katalog - die Bibliographie - soll alle von uns erstellten oder bearbeiteten Dokumente erfassen
-
Die Bibliographie soll als Quelle dienen um Dokumente finden zu können
-
Die Bibliographie soll Zitationen in Dokumenten automatisch auflösen können, um Daten nur ein mal zu erfassen
-
Dazu soll in der Bibliographie ein zentraler Primärschlüssel für jedes Dokument gepflegt werden
-
Die Bibliographie soll alle Dokumente mittels Stichwörtern semantisch verschlagworten
-
Über die Zitationen und/oder Schlagworte kann ein semantisches Netzwerk der Dokumente visualisiert werden
-
Die Bibliographie soll als Quelle dienen um die Dokumentenstruktur unterschiedlich darstellen zu können, z.B. über das Aktenzeichen, Dateiname, Modul etc. (Gib mir alle internen Richtlinien zum Thema Verschlüsselung im Modul Identity Access Management mit BSI Grundschutz-Relevanz)
-
-
Ein zentrales Glossar soll gepflegt werden können, um die gleichen Stichwortdefinitionen projektweit zu nutzen
-
Ein Stichwortverzeichnis soll automatisiert erstellt werden können
-
Ein Verzeichnis von Tabellen und Abbildungen soll automatisch erstellt werden
Warum Auszeichnungssprachen?
Auszeichnungssprachen (Markup Languages) sind Sprachen, in den Formatierungsanweisungen in maschinenlesbarer Form enthalten sind. Dabei werden Struktur und Darstellung getrennt. Damit wäre unsere Anforderung an das Textformat der Dokumente erfüllt.
Die bekannteste Auszeichnungssprache ist HTML, in der u.a. Webseiten interpretiert werden. Ein minimales Arbeitsbeispiel (MWE) sieht folgendermaßen aus:
<html>
<head>
<meta charset="utf-8">
<title>HTML-Beispiel</title>
</head>
<body>
<h1> Hauptüberschrift</h1>
<h2> Unter-Überschrift</h2>
<b>fett <i>und kursiv</i></b>
</body>
</html>
-
Im Kopf werden Meta-Daten wie der Schriftsatz festgelegt
-
Im Body kommt der eigentliche Seitentext
-
Tags können verschachtelt werden.
HTML nutzt sogenannte Tags, um Inhalte zu strukturieren und zu markieren, <b> setzt Text fett, <i> kursiv. Mit einem Slash wird der jeweilige Tag geschlossen (</i></b>). Das funktioniert wie die Klammern in der Mathematik. Zu jeder öffnenden Klammer gibt es in der Regel auch eine schließende Klammer.
Auszeichnungssprachen lassen sich, wie der Quellcode anderer Programmiersprachen auch, problemlos als normale Text-Datei speichern und in einem Sourcecodemanagementsystem wie SCCS, RCS, CVS, SVN, Mercurial oder git ablegen und managen. Man kann zwar auch Binärdateien wie PDF, JPG oder DOCXfootnote::[Eigentlich ist DOCX eine gezippte Verzeichnisstruktur von XML-Dateien und könnte als Textdatei betrachtet werden. Für Gitlab und Co. sieht DOCX dennoch wie eine einfache Binärdatei aus.] in git managen, allerdings sind dann nicht alle Funktionen wie z.B. diff/patch nutzbar, da es sich eben um Binärdateien handelt.
Daher eignen sich Auszeichnungssprachen perfekt für einen Gitlab-zentrierten Workflow mit einfachen Text-Dateien.
Auszeichnungssprachen bieten einige Vorteile, unabhängig davon welche man verwendet:
-
Dateien liegen als normale Text-Dateien vor und können wie z.B. auch Quellcode bequem in Repositories (Gitlab, Github, CVS, SVN, Mercurial …) liegen
-
Da es normale Text-Dateien sind, kann man bequem mit diff/patch arbeiten
-
einfache Versionierung der Dateien möglich, z.B. mit git oder cvs
-
Die meisten Auszeichnungssprachen können problemlos ineinander konvertiert werden, z.B. AsciiDoc nach HTML oder DocBook XML
-
offenes, wohldefiniertes Format, kein Vendor Lock-In, sondern gelebte digitale Souveränität
-
Keine Veraltung des Formats. Meine LaTeX-Dateien von 1996 funktionieren heute noch genau so gut, die gleichaltrigen WordPerfect-Dateien nicht.
-
Die Daten sind maschinenlesbar und -interpretierbar. D.h. man kann die Daten bequem umstrukturieren oder weiterverarbeiten.
-
Einbau in Pipelines einfach möglich. Egal ob Perl, Python oder ein Bash-Skript mit sed und awk, Auszeichnungssprachen lassen sich einfach in Pipelines einbauen
-
Dutzende, wenn nicht Hunderte Toolchains existieren und setzen Auszeichnungssprachen ein, z.B. Dokumentationstools um Quelltext zu dokumentieren
-
Die Dokumentation kann teilweise direkt im Quelltext erfolgen. Das beste Beispiel hierfür ist das Literate Programming, welches von Donald E. Knuth in WEB für TeX umgesetzt wurde.
-
Und das wichtigste: Die Dateien lassen sich bequem mit Vim oder einem anderen Editor bearbeiten. Es ist kein Griff zur Maus notwendig.
Es kommen nun mehrere Auszeichnungssprachen in Frage. Ich selbst nutze seit Mitte der 1990er Jahre LaTeX und habe damit im Laufe der Zeit komplexe Toolchains aufgebaut. Unter anderem zur Publikation eines wissenschaftlichen Russisch-Deutschen Wörterbuches, eine Open-Access-Journals zur Sicherheitsforschung und mehrerer wissenschaftlicher Sammelbände.
LaTeX ist zwar sehr mächtig, damit aber auch sehr komplex. Für unser Einsatzszenario etwas zu komplex. Daher kommt es hier nicht in Frage. Zwei andere Auszeichnungssprachen sind hiingegen besser geeignet und durch die Integration in Gitlab prädestiniert. Markdown und AsciiDoc.
MarkDown vs AsciiDoc
Gitlab unterstützt MarkDown nativ, d.h. es kann MD-Dateien formatiert Anzeigen. Standardmäßig wird in einem Repository eine README.MD angelegt, die entsprechend angezeigt wird. Darin kann man problemlos die Markdown-Formatierungen des Gitlab-Dialekts nutzen und z.B. Listen erzeugen oder Textteile fett und kursiv setzen.
Hier haben wir aber auch schon einen großen Nachteil von Markdown — es gibt sehr viele unterschiedliche Dialekte, die nicht 100% kompatibel miteinander sind. So haben Github und Gitlab jeweils eigene Erweiterungen für Markdown entwickelt. Darüberhinaus gibt es neben Pandoc noch dutzende weitere Markdown-Interpreter und damit Dialekte, wie z.B. KramDown oder GoldMark. Verwendet man den Gitlab-Dialekt ist man entsprechend an Gitlab gebunden — was der Idee der Portabilität und Souveränität widerspricht.
Dies ist einer der Gründe warum wir uns für AsciiDoc entschieden haben.
AsciiDoc existiert nur in genau einem Dialekt, der direkt in einem Interpreter implementiert wird. Die AsciiDoctor-Entwickler standardisieren auch die AsciiDoc-Fähigkeiten, so dass es nur einen gültigen Standard und Interpreter gibt. Keinen Wildwuchs wie bei Markdown. Das vereinfacht die Auswahl schon ein mal erheblich und macht AsciiDoc wesentlich interessanter für uns.
Auch AsciiDoc wird von Gitlab nativ unterstützt, wenn auch mommentan nicht mit einer Live-Vorschau im WebGUI-Editor. Gitlab ist aber genauso wie bei Markdown in der Lage, AsciiDoc entsprechend zu interpretieren und anzuzeigen.
AsciiDoc: die vielen Vorteile
Darüberhinaus implementiert AsciiDoc noch viele Funktionen, die MarkDown nicht bietet, aber gerade für die Achitektur wichtig sind.
-
AsciiDoc kann alles was MarkDown kann — und noch einiges mehr. AsciiDoc ist mächtiger als Markdown.
-
AsciiDoc erzeugt auf Wunsch automatisch ein Inhaltsverzeichnis mit entsprechenden Links im Dokument
-
AsciiDoc unterstützt Fußnoten im Dokument, komplexe, verschachtelte Listen, selbst definierbare Variablen und Makros
-
AsciiDOc kann speziell für PDFs das Layout mit einem Theme in YAML anpassen, ähnlich einem CSS-Stylesheet für HTML oder einem STY-File für LaTeX. Damit habe ich eine Vorlage für Richtlinien erstellt.
-
AsciiDoc unterstützt die Einbindung von Diagrammen z.B. in PlantUML. ArchiMate oder sogar AsciiArt. Mittels Kroki können diverse Diagrammstile in einer Auszeichnungssprache definiert werden, Kroki erzeugt daraus dann JPG/PNG/SVG-Dateien. Kroki ist voll containerisiert und kann problemlos im internen Gitlab oder auf einem Server lokal laufen. Keine Daten gehen dabei nach außen.
-
AsciiDoc unterstützt interne Verweise z.B. auf Abbildungen oder Tabellen und Kapitel
-
AsciiDoc unterstützt komplexe verschachtelte Tabellen
-
AsciiDoc kann CSV-Dateien einlesen
-
AsciiDoc kann Quellcode (schön) darstellen und auch Kommentare in den Quelltext einbinden.
-
AsciiDoc-Dokumente können auf beliebig viele Dateien aufgeteilt und in einem Dokument eingelesen werden. Somit kann man z.B. das Betriebshandbuch zentral anlegen und Teile der Betriebsdoku direkt aus dem Gitlab importieren. Sogar mit bestimmten if-then-Bedingungen. So kann man das Handbuch mittels if-Weichen z.B. für Version 1.0 und 2.0 erzeugen lassen
-
AsciiDoc unterstützt selbst definierte Variablen, die mit if-then-Weichen abgefragt werden können. Ist z.B. die Variable :status: auf Entwurf gesetzt, kann auf der Titelseite eine entsprechende Warnung zum Entwurfsstatus ausgegeben werden. Oder es wird eine einfache Weiche für interne und externe Freigaben eingefügt.
-
AsciiDoc kann nativ in Gitlab angezeigt werden, außerdem können HTML, PDF, PDF/A, man-Page, Docbook XML und HTML5 mit reactjs erzeugt werden
-
AsciiDoc kann ein Stichwortverzeichnis (Index) automatisiert erstellen. Ebenso ein Glossar.
-
AsciiDoc kann via AsciiMath oder LaTeX komplexe Mathematik darstellen
-
AsciiDoc kann FontAwesome einbinden und damit diverse Symbole und Emojis darstellen
-
AsciiDoc unterstützt eine einfache Literaturverwaltung. Mit asciidoctor-bibtex sogar komplette BibLaTeX-Bibliographien!
-
AsciiDoc ist ähnlich komplex wie MarkDown und in der Regel einfacher als LaTeX zu benutzen
-
Für AsciiDoc existiert mit Antora ein Static Site Generator, der statische HTML-Seiten zu Dokumentationszwecken aus (mehreren) git-Repositories generieren kann. Antora kann in Gitlab gehostet werden
-
Gitlab kann Gitlab Pages direkt aus AsciiDoc erzeugen
Mit AsciiDoc lassen sich bequem auch komplexere Dokumente verteilt schreiben. Da wir von vornherein git/Gitlab als Entwicklungsplattform einsetzen, sind die notwendige Werkzeuge wie Vim schon vorhanden und können sofort eingesetzt werden.
AsciiDoc-Template gemäß Layout-Vorgaben
Für die Ausgestaltung von Richtlinien gibt es Vorgaben zum Aufbau von Inhalt, Layout und Deckblatt. Diese lassen sich in AsciiDoc über ein angepasstes Theme (für das Layout) und eine sekbst-entwickelte Vorlage umsetzen.
Wir haben dazu ein Template entwickelt, in dem zum einen eine AsciiDoc-Datei enthalten ist, die direkt als Vorlage für eigene Dokumente genutzt werden kann. Dazu gehört neben dem angepassten Theme für das Layout auch eine weitere AsciiDoc-Datei, die die meisten Standardeinstellungen und -werte sowie einige Logiken kapselt. Diese wird dann in jedem eigenen Dokument eingebunden.

In der Datei include/Theme.yml
werden Layout-Optionen wie
Seitenränder, lebende Titel, Schriftgrößen u.ä. konfiguriert. Dies geht
am einfachsten, indem man mit der Option extends: default
das
AsciiDoc-Default-Theme um eigene Optionen erweitert.
In der Datei include/AsciiDoc-Header.adoc
finden sich
Konfigurationsoptionen und Logiken für die Richtlinien, die von den
Autoren in der Regel nicht angefasst werden müssen.
Hier finden sich im Head z.B. Angaben zur Papiergröße mit
:pdf-page-size: A4
sowie das manuell gesetzte Deckblatt, um den
Layout-Vorgaben zu genügen. Außerdem sind hier einige Logiken gekapselt.
So wird z.B. anhand von einigen Variablen entschieden ob das Dokument
ein Entwurf ist oder bereits in der freigegebenen und archivierten
Fassung samt Aktenzeichen vorliegt.
Der folgende vereinfachte AsciiDoc-Code evaluiert die Versionsnummer und
die Variable beschlossen
. Wenn diese >1 bzw. wahr sind, Wird der
Freigabevermerk sams Versionsnummer ausgegeben. Ist die Variable
beschlossen
hingegen nicht-wahr, wird der Block mit der Warnung
»Enwurfsversion« ausgegeben. Wenn dies der Fall ist, wird außerdem bei
einer PDF-Datei der aktuelle Zeitstempel und Pfad zur Datei ausgegeben.
Erzeugt man eine HTML-Seite, wird diese Information weggelassen.
Mit diesen simplen booleschen Variablen können diverse Layout-Optionen in Abhängigkeit von verschiedenen Variablen automatisiert gesetzt werden. So erhalten z.B. Anweisungen kein Aktenzeichen und damit auch keinen Veraktungsvermerk, Richtlinien aber schon.
AsciiDoc-Logik für den Block zur Entwurfsversion
// Versionsnummer muss über 1 liegen
ifeval::[{revnumber} >= 1]
ifdef::beschlossen[]
TIP: FREIGEGEBEN - {status} - in Version {revnumber} am {revdate}
endif::beschlossen[]
ifndef::beschlossen[]
WARNING: ENTWURFSVERSION -- NICHT FREIGEGEBEN
// Pfad zur adoc-Datei nur ausgeben wenn eine PDF erzeugt wird
ifdef::backend-pdf[]
*PDF* erzeugt am {localdate} um {localtime} unter {docfile}
endif::backend-pdf[]
endif::beschlossen[]
// [{revnumber} >= 1]
endif::[]
AsciiDoc: ein Mantel-Dokument mit include
-Direktiven erzeugen
AsciiDoc verfügt über die Möglichkeit, mittels include
beliebige
Text-Dateien direkt zu importieren und im aktuellen Dokument zu
interpretieren. Die inkludierte Datei kann AsciiDoc, Quellcode oder Text
als komma-separierte Liste (CSV) enthalten. Somit kann man bequem z.B.
eine Konfigdatei im YAML-Format einlesen und als Quellcodeblock
entsprechend formatieren und highlighten.
Eine andere Anwendungsmöglichkeit ist es, ein gößeres Dokument entsprechend in mehrere Dateien zu zerlegen und in einer Manteldatei einzulesen:
include::chapter01.adoc[]
include::chapter02.adoc[lines="1..10,15..20"]
include::chapter03.adoc[tag=datenschutz]
Dabei können auch verschiedene Optionen übergeben werden, z.B. kann man spezifische Zeilenbereiche auswählen oder über Tags entsprechend markierte Bereich aus dem Quelldokment auswählen. Die einzubindenden Dateien müssen auch nicht in einem Verzeichnis liegen. So können wir zum Beispiel unser übergreifendes Rollen- und Rechte-Konzept aus den jeweiligen Konzepten der Module zusammenbauen:
== Rollen und Rechtekonzept der Gesamt-Architektur
=== Modul IAM
include::../../Modul_IAM/RollenRechte/09RollenRechte.adoc[tag=rollen]
=== Modul WWW
include::../../Modul_WWW/RollenRechte/09RollenRechte.adoc[tag=rollen]
=== Modul WIKI
include::../../Modul_WIKI/RollenRechte/09RollenRechte.adoc[tag=rollen]
Dabei haben wir etabliert, im eingebundenen AsciiDoc einen Kommentar
einzutragen, der auf die Inkludierung in einem anderen Verzeichnis
hinweist. Somit weiß ein Autor beim öffnen von 09RollenRechte.adoc
sofort, dass diese Datei auch anderweitig eingebunden wird:
// INCLUDEDBY: ../../Gesamtarch/RollenRechte/RollenRechteGesamtarchitektur.adoc
Die Tags selber werden im Quelldokument als Kommentar öffnend und schließend gesetzt:
// tag::datenschutz[]
Hier seyen Datenschutz ...
// end::datenschutz[]
Es besteht auch die Möglichkeit, Kapitelnamen zu referenzieren. Dies ist aber zu vermeiden, da ein anderer Autor eventuell Kapitelnamen ändert und so die include-Anweisung nicht mehr funktioniert
Außerdem kann man in AsciiDoc mit ifeval
/ifdef
IF-Abfragen
einsetzen, um Bedingungen zu evaluieren und entsprechend Dateien zu
inkludieren:
ifeval::[{revnumber} < 1]
include::Entwurfswarnung.adoc[]
endif::[]
ifeval::[{revnumber} >= 1]
include::Freigabeliste.adoc[]
endif::[]
In diesem Beispiel wird die Datei Entwurfswarnung.adoc inkludiert wenn die Versionsnummer des Dokuments < 1 ist und die Freigabeliste.adoc wenn die Version >= 1 ist.
Mittels ifdef/ifndef kann man evaluieren, ob eine Variable (nicht) gesetzt ist. So kann man z.B. im Header die Variable :Kundenversion: setzen und damit Kapitel selektiv einbinden.
ifndef::Kundenversion[]
include::InterneServeradressen.adoc[]
endif::[]
Der große Vorteil dieser Arbeitsweise ist es, dass man quasi verschiedene Views bzw. Sichten aus bereits existierenden Dateien erzeugen kann. So ist zum Beispiel für den BSI-Grundschutzcheck ebenso wie für den Datenschutz das Verschlüsselungskonzept relevant, jedoch in unterschiedlichem Umfang und Detailgrad.
In der Datenschutzdokumentation inkludiert man nur den relevanten Teil
mit include::Verschluesselungskonzept.adoc[tag=datenschutz]
, im
Grundschutzdokument aber das komplette Dokument mit
include::Verschluesselungskonzept.adoc[]
einbinden. ==
AsciiDoc-Artefakte erzeugen
Mit AsciiDoctor wird ein AsciiDoc-Interpreter direkt von den AsciiDoc-Entwicklern gepflegt. AsciiDoctor ist in Ruby implementiert und kann durch Ruby-Gems erweitert werden. Entweder installiert man AsciiDoctor aus der Paketverwaltung oder direkt via Ruby auf einem lokalen Rechner. Alternativ gibt es Container, die in Gitlab ausgeführt werden können.
AsciiDoctor erzeugt dann statische HTML-Seiten, Docbook-XML oder man-Pages aus AsciiDoc-Dateien, AsciiDoctorPDF erzeugt analog dazu eine PDF-Datei.
Auf einem Ubuntu kann man die benötigten Ruby Gems hiermit installieren:
sudo apt -y update && sudo apt -y upgrade
sudo apt -y install ruby-rubygems ruby-dev
sudo gem install asciidoctor asciidoc-bib asciidoctor-bibtex asciidoctor-pdf asciidoctor-latex asciidoctor-revealjs asciidoctor-reducer asciidoctor-epub3 asciidoctor-chart reverse_adoc asciidoctor-plantuml asciidoctor-kroki asciidoctor-include-ext asciidoctor-rouge asciidoctor-multipage asciidoctor-bibliography asciidoctor-lists asciidoctor-question
Anschließend kann man mit asciidoctor-pdf -r bibtex Datei.adoc
eine
PDF-Datei erzeugen.
Es besteht aber auch die Möglichkeit, DOCX oder ODT-Dateien zu erzeugen. Dazu erzeugt man mit AsciiDoctor zuerst eine DocBook-XML und konvertiert diese mit Pandoc nach DOCX:
asciidoctor --backend docbook Datei.adoc
pandoc --from docbook --to docx --output Datei.docx --highlight-style espresso Datei.xml
Dies lässt sich auch mittel Containern in der Gitlab CICD-Pipeline umsetzen, wie in ??? beschrieben.
Diagramme aus Text generieren
Seit den frühen 90er Jahren gibt es mit GraphViz von IBM eine recht weit verbreitete Graphenbeschreibungssprache. Damit können gerichtete und ungerichtete Graphen auf verschiedene Arten visualisiert werden, z.B. um Abhängigkeitsbäume von Softwarepaketen darzustellen. Graphviz nutzt dazu eine einfache Grammatik, um den Graphen zu beschreiben.
Eine weitere Text-Form um Diagramme darzustellen ist PlantUML. Es unterstützt u.a. Gantt-, Mind-Map oder Archimate-Diagramme. Also genau das, was Architekten benötigen.
Sowohl GraphViz als auch PlantUML lassen sich direkt auf einem Linux-Rechner installieren und nutzen. Alternativ kann hierzu auch der Kroki-Server genutzt werden. Dieser empfängt verschiedenste Diagrammformate per HTTP POST oder GET und liefert verschiedene Grafikformate wie SVG oder PNG zurück.
AsciiDoctor unterstützt Kroki nativ und kann so recht einfach Diagramme visualisieren.
Der Kroki-Server kann entweder direkt im Internet genutzt werden, was hier im professionellen Kontext aber nicht sinnvoll ist, da so Daten abfließen. Alternativ kann Kroki auch als Container in der Gitlab-Pipeline liegen und so bei Bedarf Diagramme für AsciiDoc-Dokumente oder alleinstehende Diagramme als SVG oder PNG erzeugen.
Der Job krokibilder
in programlisting_title zeigt den
entsprechenden Einsatz der Containers um reine Diagramme zu erzeugen, in
asciidoc2pdf
wird Kroki als Service eingesetzt, um eingebettete
Diagramme in AsciiDoc-PDFs zu erzeugen.
Wie dies funktioniert, ist in programlisting_title beschrieben.
krokibilder:
stage: build
services:
- name: yuzutech/kroki:latest
alias: krokiserver
artifacts:
untracked: true
image:
name: curlimages/curl
entrypoint: ["/bin/sh", "-c"]
script:
- find . -type f -name "*.puml" -exec sh -c 'curl http://krokiserver:8000/plantuml/png --data-binary "@""{}" > "$(dirname "{}")"/"$(basename "{}" .puml).png" ' \; -exec sh -c 'curl http://krokiserver:8000/plantuml/svg --data-binary "@""{}" > "$(dirname "{}")"/"$(basename "{}" .puml).svg" ' \;
- find . -type f -name "*.dot" -exec sh -c 'curl http://krokiserver:8000/graphviz/png --data-binary "@""{}" > "$(dirname "{}")"/"$(basename "{}" .dot).png" ' \; -exec sh -c 'curl http://krokiserver:8000/graphviz/svg --data-binary "@""{}" > "$(dirname "{}")"/"$(basename "{}" .puml).svg" ' \;