Ich habe den markdown-Code meines Blogs gelöscht. Hier beschreibe ich, wie ich ihn restauriert habe.

Beim Aufräumen habe ich versehentlich das falsche Verzeichnis von einem Server gelöscht, nämlich das Git-Repository, in dem Jekyll aus Markdown-Dateien und Metadaten das HTML des Blogs rendert. Das gerenderte Resultat war auf blog.heinle.cc natürlich noch vorhanden, nur kann man ohne den Markdown-Code und die Metadaten neue Beiträge nur schwer anlegen oder alte bearbeiten. Also muss der Code restauriert werden.

Voraussetzungen

Man braucht:

  • ein Backup vom Repository, das man einfach wiederherstellt Backup hatte ich keins, weil das Repository am falschen Ort lag. Am richtigen wäre es natürlich gesichert worden. Zu spät, sich darüber zu ärgern.
  • pandoc um HTML nach Markdown zu konvertieren. Die Hauptarbeit.
  • Ein Python-Script, das sich um den Rest kümmert. Posts einsammeln, Metadaten extrahieren, etc
  • (optional) Typora oder einen anderen Markdown-Editor, der gut mit Tabellen umgehen kann. Hilfreich, wenn man Tabellen hatte.
  • Den HTML-Code und die Bilder des Blogs

GitHub-Repo

Wer nur den Code will, um es selbst zu versuchen, findet ihn in meinem GitHub Repo: jekyll-restore. Wie die Scripte benutzt werden, steht dort in der README.

Im weiteren Post werde ich erklären, was der Code tut und wieso. Es gibt mehrere Baustellen:

Inhalt einzelner Beiträge extrahieren

Generell hat man mit Jekyll relativ viel Glück beim Restaurieren, da die meiste Komplexität des HTML-Codes im Theme steckt und der eigentliche Text des Blogposts relativ simpel bleibt. Damit kommt pandoc gut klar und kann taugliches Markdown aus dem HTML-Code übersetzen. Das komplizierteste sind meist Code-Snippets mit Syntax-Highlighting. Weniger glücklich ist der Umgang mit Tabellen. Je nach Aufbau der Tabelle kommt pandoc überhaupt nicht damit klar. Darum kümmert sich dann gegebenenfalls Typora.

Wichtig ist, dass man pandoc nicht das komplette HTML-Dokument zum Übersetzen gibt. Darin wären Theme-Details wie Header des Blogs, Navigation, Footer und weitere Stile-Elemente enthalten, die man später wieder über das Theme bekommt und die im Markdown-Code nichts zu suchen haben. Der Hauptteil des Blogposts ist in einem <div itempromp="articleBody"> enthalten. Mit einem HTML-Parser kann man so die Eingabedaten schon auf das Wesentliche reduzieren. Ich nutze dazu BeautifulSoup.

Hat man den HTML-Code auf den Text des Posts reduziert, kann man ihn schon einmal durch pandoc schicken und von HTML nach Markdown konvertieren lassen. Danach müssen Code-Snippets mit und ohne Syntax-Highlighting noch korrigiert werden. Pandoc ist zwar schlau genug, sie dank der <code>-Tags im HTML drum herum nicht als tausend verschiedene <span>-Tags zu interpretieren, kommt aber mit den umgebenden <div>-Tags nicht gut klar. Auch das Erkennen der jeweiligen Sprache des Syntax-Highlightings gelingt nicht. Die notwendigen Informationen sind glücklicherweise aber nicht verloren, müssen nur richtig umgebaut werden. Was Pandoc von <div>mit Klassen nach :::-Tags mit Attributen im Markdown übersetzt, lässt sich mit ein paar regulären Ausdrücken einfach reparieren; selbst die Sprache für das Highlighting kann wieder richtig in die Backticks der Code-Blöcke geschrieben werden.

Metadaten

Nebst den eigentlichen Beitragstexten sind die Metadaten der Posts wichtig. Nur wenn das Datum des Posts, der Titel in Slug-Form und die Konfiguration der Permalinks gleich wie vor der Restauration sind, ergeben sich bei Jekyll die gleichen URLs für die Beiträge. Stellt man nicht sicher, dass die URL der Posts alle gleich bleiben, brechen interne Verlinkungen im eigenen Blog, Verlinkungen von außen und man verliert etwaige bei Suchmaschinen schon verdiente Ränge für den eigenen Inhalt. Es ist also wichtig, auch die Metadaten korrekt zu extrahieren.

Wichtig für das korrekte Wiederherstellen der Linkstruktur sind vor allen Dingen das Datum der jeweiligen Beiträge sowie der Titel in seiner Slug-Form, also wie er im Link vorkommt. Das Datum lässt sich sehr einfach wieder mit dem HTML-Parser aus dem Blogpost extrahieren, für den Slug nimmt man einfach den Dateinamen der jeweiligen HTML-Datei, ohne Suffix. Daraus kann man dann wieder den für Jekyll notwendigen Dateinamen in der Form %Y-%m-%d-slug.md rekonstruieren. In der Konfigurationsdatei der neuen Jekyll-Instanz muss später dann die Einstellung für die Permalinks wieder so gewählt werden, dass die gleichen Links herauskommen wie früher.

Kleine Korrekturen

Stört man sich daran, dass pandoc für die ersten Ebenen einer Überschrift den Setex-Stil verwendet und für die folgenden den atx-Stil, kann man einfach alles so lassen wie es aus pandoc heraus kommt. Das zu HTML gerenderte Ergebnis ist natürlich jeweils das gleiche. Will man das unbedingt einheitlich haben, hilft hier die großzügige Anwendung regulärer Ausdrücke.

Überschrift im Setex-Stil
=========================

Unterüberschrift im Setex-Stil
------------------------------

### Unter-Unterüberschrift im atx-Stil

Wie schon erwähnt hat pandoc Probleme mit Tabellen, die ich nicht automatisch habe beheben können. Aufgrund der überschaubaren Anzahl an Tabellen in meinen Blogposts habe ich die lieber manuell von HTML nach Markdown konvertiert. Behilflich sind dabei der Browser sowie ein guter Markdown-Editor wie Typora. Zuerst löscht man die kaputte Tabelle im Markdown-Code, dann kopiert man im Browser die gewünschte Tabelle und fügt sie mit Hilfe von Typora aus der Zwischenablage an die richtige Stelle ein. Für gewöhnlich formattiert der Editor dabei die Tabelle bereits korrekt.

Blog restaurieren

Hat man die Posts wieder als Markdown-Dateien vorliegen und die Metadaten korrekt eingelesen und in Form der Dateinamen abgespeichert, kann alles zu einem funktionierenden Blog zurückgespielt werden. Dazu muss ein neues Jekyll-Blog angelegt werden. Ein ganz grundlegender reicht erst mal. Die Markdown-Dateien kommen wie gewohnt nach _posts, die restlichen Dateien aus dem Verzeichnis mit dem Blog in HTML-Format kommen einfach ins Hauptverzeichnis - das betrifft etwa Verzeichnisse mit Bildern. Nicht zurückkopiert werden muss CSS, das wird vom jeweiligen Theme bereitgestellt. Je nachdem, welche Themes verwendet wurde, ist also etwa der assets-Ordner nicht wichtig. Nicht vergessen werden darf auch eine etwaige .htaccess-Datei, die mit ihrem führenden Punkt im Dateinamen meist als versteckte Datei behandelt und vergessen wird.

Der Inhalt der _config.yaml muss nun eben aus dem Gedächtnis wiederhergestellt werden. Besonderes Augenmerk gilt den Einstellungen permalink (Dokumentation zu Permalinks), baseurl sowie default-Einstellungen für Posts (Dokumentation zu Default-Einstellungen). Letztere regeln unter anderem, welches Layout Blog-Posts annehmen sollen, bei denen nicht explizit eines im Front-Matter gewählt wurde.

Zu guter Letzt sollten noch etwaige zuvor auch verwendete Plugins wieder aktiviert werden, also zum einen über das Gemfile installiert werden und dann auch in der _config.yaml wieder aktiviert werden.

Ausprobieren

Damit sollte das Gröbste geschafft sein und das Blog sollte sich wieder mit Jekyll rendern lassen. Die Kontrolle mit dem Browser sollte Fehler im Design oder Markup offenbaren, etwa wenn ein Codeblock kaputt ist oder eine Tabelle falsch gebaut wurde.

Sicherheitshalber ist auch schlau, das Resultat auf 404-Fehler in den Verlinkungen zu prüfen. Das muss glücklicherweise auch nicht von Hand gemacht werden, dafür gibt es wget. Ein einfacher Aufruf aller Seiten lässt sich etwa folgendermaßen bewerkstelligen. Dazu muss zunächst mit jekyll serve der lokale Entwicklungsserver gestartet werden, dann kann wget darauf angesetzt werden:

wget -o ~/404.txt -l 10 -r --spider http://localhost:4000

Man erhält eine sehr unübersichtliche Datei 404.txt im Heimverzeichnis. Die kann mit einem geeigneten Texteditor dann nach 404 durchsucht werden und jeweils der Kontext nachvollzogen werden. Damit sollten dann auch tote Links aufzufinden sein.

Backups

Der ganze Aufwand wäre ohne Backups nicht notwendig gewesen. Hat man das Blog erfolgreich wiederhergestellt, sollte danach ein Backup das erste sein, was man macht. Schlau ist, ein git-Repository anzulegen und dessen Inhalt dann auch irgendwohin zu pushen. Nachdem im Repository nichts enthalten ist, was nicht auch öffentlich im Internet lesbar wäre, kann das auch GitHub sein oder ein vergleichbares Hosting.