#!/usr/bin/env php getPathName()); $src = $node_info->getPathname(); if (str_starts_with($src, SITE . 'target/') OR str_starts_with($src, SITE . 'cache/')) continue; $target = str_replace(SITE, SITE . 'cache/', $src); $path_parts_src = pathinfo($src); $path_parts_target = pathinfo($target); if (preg_match('#/\.(?!htaccess|well-known)#', $src) !== 0) // Skip hidden nodes other than .htaccess and .well-known continue; if ($node_info->getType() !== 'file') continue; if (in_array('draft', explode('.', $path_parts_target['basename']), true)) continue; if (!file_exists($path_parts_target['dirname'])) // Create parent directory if needed mkdir($path_parts_target['dirname'], 0755, true); copy($src, $target); } if (file_exists(SITE . 'po4a.cfg')) exec('po4a --destdir ' . SITE . ' --srcdir ' . SITE . ' ' . SITE . 'po4a.cfg'); $nodes_cache = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(SITE . 'cache/', RecursiveDirectoryIterator::SKIP_DOTS)); foreach($nodes_cache as $node) { $node_info = new SplFileInfo($node->getPathName()); $src = $node_info->getPathname(); if (str_starts_with($src, SITE . 'target/')) continue; $target = str_replace(SITE . 'cache/', SITE . 'target/', $src); $path_parts_src = pathinfo($src); $path_parts_target = pathinfo($target); if (preg_match('#/\.(?!htaccess|well-known)#', $src) !== 0) // Skip hidden nodes other than .htaccess and .well-known continue; if ($node_info->getType() !== 'file') continue; if (in_array('draft', explode('.', $path_parts_target['basename']), true)) continue; if (!file_exists($path_parts_target['dirname'])) // Create parent directory if needed mkdir($path_parts_target['dirname'], 0755, true); copy($src, $target); if ($node_info->getExtension() !== 'md') continue; preg_match('/(?[-\w]+)(?:\.(?[a-z]{2}))?\.md/', $path_parts_src['basename'], $matches); if ($matches['pagename'] === strtoupper($matches['pagename'])) // Ignore uppercase-only filenames (like README.md) continue; $pages[] = $node; $lang = $matches['lang'] ?? $config['default-lang'] ?? exit('no language found for ' . $src . LF); $pages_langs[$path_parts_src['dirname'] . '/' . $matches['pagename']][] = $lang; $files_langs[$src] = $lang; $page_names[$src] = $matches['pagename']; } foreach ($pages as $node) { $node_info = new SplFileInfo($node->getPathName()); $src = $node_info->getPathname(); $target = str_replace(SITE . 'cache/', SITE . 'target/', $src); $path_parts_src = pathinfo($src); $path_parts_target = pathinfo($target); $base_filepath_src = $path_parts_src['dirname'] . '/' . $path_parts_src['filename']; $base_filepath_target = $path_parts_target['dirname'] . '/' . $path_parts_target['filename']; $content = file_get_contents($src); $lang = $files_langs[$src]; preg_match('/^# (?.*)$/Dm', $content, $matches); $title = $matches['title'] ?? NULL; if (!file_exists($base_filepath_target . '.html') OR (filemtime($src) > filemtime($base_filepath_target . '.html')) OR $opt['force']) { echo 'Compiling ' . $src . ' ' . date("Y-m-d H:i:s", $node_info->getMTime()) . LF; // Execute PHP code ob_start(); eval('?>' . $content); $content = ob_get_clean(); // Convert Gemtext to Markdown if ($path_parts_target['extension'] === 'gmi' OR $path_parts_target['extension'] === 'md') { $content = preg_replace_callback( '/^=>\h*(?<addr>\S+)(:?\h+(?<title>\V+))?$/m', function ($matches) { if (!str_contains($matches['addr'], ':') AND str_ends_with($matches['addr'], '.gmi')) $matches['addr'] = substr($matches['addr'], 0, -3) . 'md'; return '[' . ($matches['title'] ?? $matches['addr']) . '](' . $matches['addr'] . ')'; }, $content, ); } // Compile Markdown to HTML $process = proc_open('pandoc --fail-if-warnings --section-divs -f markdown-citations-native_divs-native_spans+abbreviations+hard_line_breaks+lists_without_preceding_blankline+multiline_tables+fenced_divs+bracketed_spans+markdown_attribute -t html --wrap none', [ 0 => ['pipe', 'r'], 1 => ['pipe', 'w'], ], $pipes); if (is_resource($process) !== true) exit('Can\'t spawn pandoc.' . PHP_EOL); fwrite($pipes[0], $content); fclose($pipes[0]); $content = stream_get_contents($pipes[1]); fclose($pipes[1]); if (proc_close($process) !== 0) exit('pandoc failed.' . PHP_EOL); // .md > .html for local links $content = preg_replace('/ href="([^:"]+)\.md"/', ' href="$1.html"', $content); $relative_root_path = str_repeat('../', substr_count(str_replace(SITE . 'target', '', $path_parts_target['dirname']), '/')); ob_start(); ?> <!DOCTYPE html> <html lang="<?= $lang ?>"> <head> <meta charset="utf-8"> <?php if (isset($title) AND isset($config['title'])) echo '<title>' . $title . ' · ' . $config['title'] . ''; else if (isset($title)) echo '' . $title . ''; else if (isset($config['title'])) echo '' . $config['title'] . ''; ?> '; ?> ' . LF; if ($config['announce-css']) { if (file_exists(SITE . 'style.css')) echo ' ' . LF; echo ' ' . LF; } if (file_exists(SITE . 'head.inc.html')) echo file_get_contents(SITE . 'head.inc.html'); ?> 1) { sort($page_langs); $lang_txt = [ 'fr' => 'français', 'en' => 'english', ]; ?> ' . file_get_contents(SITE . 'header.inc.php')); if ($config['center-index'] AND $path_parts_target['filename'] === 'index') echo '
' . $content . '
'; else echo '
' . $content . '
'; if (file_exists(SITE . 'end.inc.html')) require SITE . 'end.inc.html'; echo ''; $content = ob_get_clean(); if (extension_loaded('tidy')) { $content = tidy_repair_string($content, [ 'indent' => true, 'indent-spaces' => 4, 'output-xhtml' => true, 'wrap' => 0, 'hide-comments' => true, ]); $content = str_replace(' ', ' ', $content); } file_put_contents($base_filepath_target . '.html', $content); if ($config['gzip']) exec('gzip --keep --fast --force ' . $base_filepath_target . '.html'); } if ($page_names[$src] === 'index') continue; $relative_addr = str_replace(SITE . 'cache/', '', $base_filepath_src . '.html'); // As of RFC 3151: A URN Namespace for Public Identifiers $public_id = 'urn:publicid:' . $config['id'] . str_replace('/', '%2F', $relative_addr); preg_match('#\(?.*)\#s', file_get_contents($base_filepath_target . '.html'), $match); $atom_entry_content = $match['content']; // Make relative links absolute $atom_entry_content = preg_replace_callback('# href=\"(?[^:"]+)\"#', function ($matches) { global $config; global $path_parts_target; return ' href="' . ($config['base-url'][0] ?? '') . substr($path_parts_target['dirname'], strlen(SITE)) . '/' . $matches['relative_url'] . '"'; }, $atom_entry_content); ob_start(); ?> <?= $title ?> getMTime()) ?> ' . LF; ?> $unused) { $dir = implode('/', array_slice(explode('/', $relative_addr), 0, $level)) . '/'; $last_update = $node_info->getMTime(); $dirs_entries_per_lang['all'][$dir] = ($dirs_entries_per_lang['all'][$dir] ?? '') . $atom_entry; $dirs_entries_per_lang[$lang][$dir] = ($dirs_entries_per_lang[$lang][$dir] ?? '') . $atom_entry; if (!isset($dirs_last_update['all'][$dir]) OR $last_update > $dirs_last_update['all'][$dir]) $dirs_last_update['all'][$dir] = $last_update; if (!isset($dirs_last_update[$lang][$dir]) OR $last_update > $dirs_last_update[$lang][$dir]) $dirs_last_update[$lang][$dir] = $last_update; } } foreach ($dirs_entries_per_lang as $lang => $dirs_entries) { foreach ($dirs_entries as $dir => $entries) { ob_start(); ?> <?= ($config['title'] ?? '') . (($dir !== '/') ? ' ' . $dir : '') ?> urn:publicid: ' . LF; ?> ' . LF); } } if ($config['announce-css']) copy(ROOT . '/style.css', SITE . 'target/mkht-php.css');