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 main()
{
    global $quiet;
    $options = BoostSiteTools\CommandLineOptions::parse(UPDATE_DOC_LIST_USAGE, array('quiet' => false));
    $quiet = $options->flags['quiet'];
    $location = null;
    $version = null;
    switch (count($options->positional)) {
        case 2:
            $version = $options->positional[1];
        case 1:
            $location = $options->positional[0];
        case 0:
            break;
        default:
            echo $options->usage_message();
            exit(1);
    }
    if ($version) {
        // BoostVersion dies if version is invalid.
        $version = BoostVersion::from($version);
    }
    $libs = BoostLibraries::from_xml_file(dirname(__FILE__) . '/../doc/libraries.xml');
    $updates = array();
    if ($location) {
        $real_location = realpath($location);
        if ($real_location && !is_dir($real_location)) {
            echo "Not a directory: {$location}\n";
            exit(1);
        }
        $location = $real_location;
        // If this is not a git repo.
        // TODO: Don't output stderr.
        exec("cd \"{$location}\" && git rev-parse --git-dir", $output, $return_var);
        if ($return_var != 0) {
            if (!$version || !$version->is_numbered_release()) {
                echo "Error: Release version required for release.\n";
                exit(1);
            }
            $updates[(string) $version] = read_metadata_from_filesystem($location, $version);
        } else {
            if (get_bool_from_array(BoostSuperProject::run_process("cd '{$location}' && git rev-parse --is-bare-repository"))) {
                if ($version) {
                    $updates[(string) $version] = read_metadata_from_git($location, $version);
                } else {
                    $updates[(string) 'master'] = read_metadata_from_git($location, 'master');
                    $updates[(string) 'develop'] = read_metadata_from_git($location, 'develop');
                }
            } else {
                // TODO: Could get version from the branch in a git checkout.
                if (!$version) {
                    echo "Error: Version required for local tree.\n";
                    exit(1);
                }
                $updates[(string) $version] = read_metadata_from_filesystem($location, $version);
            }
        }
    }
    if ($updates) {
        foreach ($updates as $update_version => $update) {
            $libs->update($update_version, $update);
        }
    } else {
        $libs->update();
    }
    if (!$quiet) {
        echo "Writing to disk\n";
    }
    file_put_contents(dirname(__FILE__) . '/../doc/libraries.xml', $libs->to_xml());
    $libs->squash_name_arrays();
    file_put_contents(dirname(__FILE__) . '/../generated/libraries.txt', serialize($libs));
}
/**
 *
 * @param string $location The location of the super project in the mirror.
 * @param BoostVersion|string $version The version to update from.
 * @throws RuntimeException
 */
function read_metadata_from_git($location, $version)
{
    $branch = BoostVersion::from($version)->git_ref();
    echo "Updating from {$branch}\n";
    $super_project = new BoostSuperProject($location, $branch);
    $modules = $super_project->get_modules();
    $modules_by_path = array();
    foreach ($modules as $name => $details) {
        $modules_by_path[$details['path']] = $name;
    }
    foreach ($super_project->run_git("ls-tree {$branch} " . implode(' ', array_keys($modules_by_path))) as $line_number => $line) {
        if (!$line) {
            continue;
        }
        if (preg_match("@^160000 commit ([a-zA-Z0-9]+)\t(.*)\$@", $line, $matches)) {
            $modules[$modules_by_path[$matches[2]]]['hash'] = $matches[1];
        } else {
            throw new RuntimeException("Unmatched submodule line: {$line}");
        }
    }
    $updated_libs = array();
    foreach ($modules as $name => $module) {
        $module_location = "{$location}/{$module['url']}";
        $module_command = "cd '{$module_location}' && git";
        foreach (BoostSuperProject::run_process("{$module_command} ls-tree {$module['hash']} " . "meta/libraries.xml meta/libraries.json") as $entry) {
            try {
                $entry = trim($entry);
                if (preg_match("@^100644 blob ([a-zA-Z0-9]+)\t(.*)\$@", $entry, $matches)) {
                    $hash = $matches[1];
                    $filename = $matches[2];
                    $text = implode("\n", BoostSuperProject::run_process("{$module_command} show {$hash}"));
                    $updated_libs = array_merge($updated_libs, load_from_text($text, $filename, $name, $module['path']));
                }
            } catch (library_decode_exception $e) {
                echo "Error decoding metadata for module {$name}:\n{$e->content()}\n";
            }
        }
    }
    return $updated_libs;
}
    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;
            }
        }
    }