function main() { $args = $_SERVER['argv']; $boost_root = null; switch (count($args)) { case 2: $boost_root = $args[1]; break; default: echo "Usage: create-module-metadata.php boost_root\n"; exit(1); } $library_details = BoostLibraries::from_xml_file(__DIR__ . '/../doc/libraries.xml')->get_for_version(BoostVersion::develop()); $super_project = new BoostSuperProject($boost_root); $git_submodules = $super_project->get_modules(); // Split the libraries up into modules. $libraries_by_module = array(); foreach ($library_details as $library) { $module = $library['module']; if (!isset($git_submodules[$module])) { echo "Unknown module: {$module}\n"; continue; } if (isset($library['documentation'])) { $doc_url = $library['documentation']; $module_base = $git_submodules[$module]['path']; if ($doc_url == $module_base) { $doc_url = ''; } else { if (strpos($doc_url, "{$module_base}/") === 0) { $doc_url = substr($doc_url, strlen("{$module_base}/")); } else { $doc_url = "/{$doc_url}"; } } if (!$doc_url) { unset($library['documentation']); } else { $library['documentation'] = $doc_url; } } $libraries_by_module[$module][] = $library; } // Write the module metadata foreach ($libraries_by_module as $module => $libraries) { $module_libraries = BoostLibraries::from_array($libraries); $module_dir = "{$boost_root}/{$git_submodules[$module]['path']}"; $meta_dir = "{$module_dir}/meta"; $meta_file = "{$module_dir}/meta/libraries.json"; if (!is_dir($module_dir)) { echo "Module '{$module}' doesn't exist at '{$module_dir}'\n"; continue; } if (!is_dir($meta_dir)) { mkdir($meta_dir); } file_put_contents($meta_file, $module_libraries->to_json(array('boost-version', 'update-version', 'module')) . "\n"); } }
function git_file($location, $ref, $path) { foreach (BoostSuperProject::run_process("git -C {$location} ls-tree {$ref} {$path}") as $entry) { if (!preg_match("@^100644 blob ([a-zA-Z0-9]+)\t(.*)\$@", $entry, $matches)) { assert(false); } return BoostSuperProject::run_process("git -C {$location} show {$matches[1]}"); } return false; }
function convert_quickbook_pages($refresh = false) { try { BoostSuperProject::run_process('quickbook --version'); } catch (ProcessError $e) { echo "Problem running quickbook, will not convert quickbook articles.\n"; return; } $bb_parser = new BoostBookParser(); foreach ($this->pages as $page => $page_data) { if ($page_data->page_state || $refresh) { $xml_filename = tempnam(sys_get_temp_dir(), 'boost-qbk-'); try { echo "Converting ", $page, ":\n"; BoostSuperProject::run_process("quickbook --output-file {$xml_filename} -I {$this->root}/feed {$this->root}/{$page}"); $page_data->load($bb_parser->parse($xml_filename), $refresh); } catch (Exception $e) { unlink($xml_filename); throw $e; } unlink($xml_filename); $template_vars = array('history_style' => '', 'full_title_xml' => $page_data->full_title_xml, 'title_xml' => $page_data->title_xml, 'note_xml' => '', 'web_date' => $page_data->web_date(), 'documentation_para' => '', 'download_table' => $page_data->download_table(), 'description_xml' => $page_data->description_xml); if ($page_data->type == 'release' && empty($page_data->flags['released']) && empty($page_data->flags['beta'])) { $template_vars['note_xml'] = <<<EOL <div class="section-note"><p>Note: This release is still under development. Please don't use this page as a source of information, it's here for development purposes only. Everything is subject to change.</p></div> EOL; } if ($page_data->documentation) { $template_vars['documentation_para'] = ' <p><a href="' . html_encode($page_data->documentation) . '">Documentation</a>'; } if (strpos($page_data->location, 'users/history/') === 0) { $template_vars['history_style'] = <<<EOL <style type="text/css"> /*<![CDATA[*/ #content .news-description ul { list-style: none; } #content .news-description ul ul { list-style: circle; } /*]]>*/ </style> EOL; } self::write_template("{$this->root}/{$page_data->location}", __DIR__ . "/templates/entry.php", $template_vars); } } }
function read_metadata_from_modules($path, $location, $hash, $sublibs = array('libs' => true)) { // echo "Reading from {$path} - {$location} - {$hash}.\n"; $super_project = new BoostSuperProject($location, $hash); $modules = $super_project->get_modules(); // Used to quickly set submodule hash. $modules_by_path = array(); foreach ($modules as $name => $details) { $modules_by_path[$details['path']] = $name; } // Store possible metadata files in this array. $metadata_files = array(); // Get a list of everything that's relevant in the superproject+modules. foreach ($super_project->run_git("ls-tree {$hash} -r") as $line_number => $line) { if (!$line) { continue; } if (preg_match("@^(\\d{6}) (\\w+) ([a-zA-Z0-9]+)\t(.*)\$@", $line, $matches)) { switch ($matches[2]) { case 'blob': $blob_path = $path ? "{$path}/{$matches['4']}" : $matches[4]; if (fnmatch('*/sublibs', $blob_path)) { $sublibs[dirname($blob_path)] = true; } else { if (fnmatch('*/meta/libraries.json', $blob_path)) { $metadata_files[$blob_path] = $matches[3]; } } break; case 'commit': $modules[$modules_by_path[$matches[4]]]['hash'] = $matches[3]; break; } } else { throw new RuntimeException("Unmatched submodule line: {$line}"); } } // Process metadata files $updated_libs = array(); foreach ($metadata_files as $metadata_path => $metadata_hash) { if (empty($sublibs[dirname(dirname(dirname($metadata_path)))])) { echo "Ignoring non-library metadata file: {$metadata_path}.\n"; } else { $text = implode("\n", $super_project->run_git("show {$metadata_hash}")); $updated_libs = array_merge($updated_libs, load_from_text($text, $metadata_path, dirname(dirname($metadata_path)))); } } // Recurse over submodules foreach ($modules as $name => $module) { global $quiet; $submodule_path = $path ? "{$path}/{$module['path']}" : $module['path']; if (!preg_match('@^\\.\\./(\\w+)\\.git$@', $module['url'])) { // In quiet mode don't warn about documentation submodules, which // libraries have previously included from remote locations. if (!$quiet || strpos($submodule_path . '/', '/doc/') === false) { echo "Ignoring submodule '{$name}' in '{$location}'.\n"; } continue; } if (empty($module['hash'])) { echo "Missing module in .gitmodule: '{$name}' in '{$location}'.\n"; continue; } $updated_libs = array_merge($updated_libs, read_metadata_from_modules($submodule_path, "{$location}/{$module['url']}", $module['hash'], $sublibs)); } return $updated_libs; }
/** * * @param string $location The location of the super project in the mirror. * @param string $branch The branch to update from. * @throws RuntimeException */ function read_metadata_from_local_clone($location, $branch = 'latest') { echo "Updating from local checkout/{$branch}\n"; $super_project = new BoostSuperProject($location); $updated_libs = array(); foreach ($super_project->get_modules() as $name => $module_details) { foreach (glob("{$location}/{$module_details['path']}/meta/libraries.*") as $path) { try { $updated_libs = array_merge($updated_libs, load_from_file($path, $name, $module_details['path'])); } catch (library_decode_exception $e) { echo "Error decoding metadata for module {$name}:\n{$e->content()}\n"; } } } }
function convert_quickbook_pages($refresh = false) { try { BoostSuperProject::run_process('quickbook --version'); $have_quickbook = true; } catch (ProcessError $e) { echo "Problem running quickbook, will not convert quickbook articles.\n"; $have_quickbook = false; } $bb_parser = new BoostBookParser(); foreach ($this->pages as $page => $page_data) { if ($page_data->page_state || $refresh) { // Hash the quickbook source $hash = hash('sha256', str_replace("\r\n", "\n", file_get_contents("{$this->root}/{$page}"))); // Get the page from quickbook/read from cache if (array_key_exists($page, $this->page_cache) && (!$have_quickbook || $this->page_cache[$page]['hash'] === $hash)) { $description_xhtml = $this->page_cache[$page]['description_xhtml']; } else { if ($have_quickbook) { $xml_filename = tempnam(sys_get_temp_dir(), 'boost-qbk-'); try { echo "Converting ", $page, ":\n"; BoostSuperProject::run_process("quickbook --output-file {$xml_filename} -I {$this->root}/feed {$this->root}/{$page}"); $values = $bb_parser->parse($xml_filename); $page_data->load_boostbook_data($values, $refresh); $description_xhtml = $values['description_xhtml']; } catch (Exception $e) { unlink($xml_filename); throw $e; } unlink($xml_filename); $this->page_cache[$page] = array('hash' => $hash, 'description_xhtml' => $description_xhtml); } else { echo "Unable to generate page for {$page}.\n"; continue; } } // Set the path where the page should be built. // This can only be done after the quickbook file has been converted, // as the page id is based on the file contents. if (!$page_data->location) { $location_data = $this->get_page_location_data($page_data->qbk_file); $page_data->location = "{$location_data['destination']}/{$page_data->id}.html"; } // Transform links in description if ($page_data->section === 'history') { $doc_prefix = null; if ($page_data->get_release_status() === 'dev' || $page_data->get_release_status() === 'beta') { $doc_prefix = rtrim($page_data->get_documentation() ?: '/doc/libs/master/', '/'); $description_xhtml = BoostSiteTools::transform_links($description_xhtml, function ($x) use($doc_prefix) { return preg_match('@^/(?:libs/|doc/html/)@', $x) ? $doc_prefix . $x : $x; }); } $version = BoostWebsite::array_get($page_data->release_data, 'version'); if ($version && $doc_prefix) { $final_documentation = "/doc/libs/{$version->final_doc_dir()}"; $link_pattern = '@^' . preg_quote($final_documentation, '@') . '/@'; $replace = "{$doc_prefix}/"; $description_xhtml = BoostSiteTools::transform_links($description_xhtml, function ($x) use($link_pattern, $replace) { return preg_replace($link_pattern, $replace, $x); }); } } $description_xhtml = BoostSiteTools::trim_lines($description_xhtml); $page_data->description_xml = $description_xhtml; // Generate the various pages. $template_vars = array('history_style' => '', 'full_title_xml' => $page_data->full_title_xml(), 'title_xml' => $page_data->title_xml, 'note_xml' => '', 'web_date' => $page_data->web_date(), 'documentation_para' => '', 'download_table' => $page_data->download_table(), 'description_xml' => $page_data->description_xml); if ($page_data->get_release_status() === 'dev') { $template_vars['note_xml'] = <<<EOL <div class="section-alert"><p>Note: This release is still under development. Please don't use this page as a source of information, it's here for development purposes only. Everything is subject to change.</p></div> EOL; } if ($page_data->section === 'history' && BoostWebsite::array_get($page_data->release_data, 'documentation')) { $template_vars['documentation_para'] = ' <p><a href="' . html_encode(BoostWebsite::array_get($page_data->release_data, 'documentation')) . '">Documentation</a>'; } if (strpos($page_data->location, 'users/history/') === 0) { $template_vars['history_style'] = <<<EOL <style type="text/css"> /*<![CDATA[*/ #content .news-description ul { list-style: none; } #content .news-description ul ul { list-style: circle; } /*]]>*/ </style> EOL; } self::write_template("{$this->root}/{$page_data->location}", __DIR__ . "/templates/entry.php", $template_vars); $page_data->page_state = null; } } }