Skip to content

Instantly share code, notes, and snippets.

@treffynnon
Last active December 21, 2019 12:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save treffynnon/5b2dd82ec5a93ed7dcf2 to your computer and use it in GitHub Desktop.
Save treffynnon/5b2dd82ec5a93ed7dcf2 to your computer and use it in GitHub Desktop.
Pelican to Hugo reStructuredText post converter (Python static site generator to Go static site generator)
<?php
/**
* Requires pandoc to be installed and in your path
*
* It will look for .rst files in __DIR__/content/* where it will expect to find
* category folders. Inside these category folders your posts should be available.
*
* So
*
* - content
* - Computing
* - functional-php.rst
* - new-pc.rst
* - Misc
* - moving-house.rst
* - death-defying-stunts.rst
*/
// Path to the folder containing rst documents you want to convert
$content_path = __DIR__ . '/content';
// Output path where the posts will be saved to as markdown
$output_path = __DIR__ . '/hugo';
function map_directory($path, $func) {
$results = [];
$d = dir($path);
while (false !== ($entry = $d->read())) {
if ('.' !== $entry && '..' !== $entry) {
$results[] = $func($entry, $d);
}
}
$d->close();
return $results;
}
map_directory($content_path, function($entry, $d) {
$dir = $d->path . "/$entry";
if (is_dir($dir)) {
parse_posts($dir, $entry);
}
});
function parse_posts($path, $category) {
map_directory($path, function($entry, $d) {
$item = $d->path . "/$entry";
if (is_file($item) && false !== strstr($entry, '.rst')) {
echo "$entry\n";
$out_file = __DIR__ . '/hugo/' . str_replace('.rst', '.md', $entry);
$f = file_get_contents($item);
$f = mutate_file($f);
file_put_contents($out_file, $f);
}
});
}
function mutate_file($f) {
$matches = [];
// add opening YAML front matter indicator
$f = "---\n" . $f;
// Change the rst title into a YAML key and value
$f = preg_replace('/^(---\n+)(.+)\n[#^~\-=_+\'`]+/', '\1' . "\n:title: " . '\2', $f);
// find the last rst key value pair and insert closing YAML front
// matter indicator immediately after it
if (preg_match_all('/^:([\w\d]+): +(.*) *$/m', $f, $matches)) {
$last_key = end($matches[1]);
$f = preg_replace('/^(:' . preg_quote($last_key) . ':.*)$/m', '\1' . "\n---\n", $f);
}
// convert all the rst key value pairs into YAML key value pairs
$f = preg_replace_callback('/^:([\w\d]+): +(.*) *$/m', function($matches) {
$out = '';
if ($matches[2]) {
switch ($matches[1]) {
case 'date':
$date = strtotime($matches[2]);
$out = 'date: "' . date('Y-m-d\TH:i:s\Z', $date) . '"';
break;
case 'tags':
case 'categories':
$cats = explode(',', $matches[2]);
$cats = array_map(function($item) {
$tag = str_replace('.', '', trim($item));
return ' - "' . addslashes($tag) . '"';
}, $cats);
$out = "{$matches[1]}:\n" . implode("\n", $cats);
break;
case 'category':
$out = "categories:\n - " . '"' . addslashes($matches[2]) . '"';
break;
default:
$out = "{$matches[1]}: " . '"' . addslashes($matches[2]) . '"';
break;
}
}
return $out;
}, $f);
$split = preg_split('/^---$/m', $f);
// remove empty lines
$split[1] = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $split[1]);
$content = $split[2];
$pipes_map = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
);
$arguments = array(
'--smart',
'-f rst',
'-t markdown_github',
);
$exec_string = 'pandoc ' . implode(' ', $arguments);
$proc_res = proc_open($exec_string, $pipes_map, $pipes);
if (!is_resource($proc_res)) {
return 'Could not process the file with pandoc.';
}
fwrite($pipes[0], $content);
fclose($pipes[0]);
$markdown = stream_get_contents($pipes[1]);
$split[2] = "\n\n" . $markdown;
$f = implode('---', $split);
return $f;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment