Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a version indicator and selector to all docs pages #22725

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions scripts/docs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ genrule(
name = "gen_release_docs",
srcs = [
":new_toc.yaml",
":new_buttons.html",
"//site/en:docs",
"//src/main/java/com/google/devtools/build/lib:reference-docs.zip",
],
Expand All @@ -16,6 +17,7 @@ genrule(
cmd = "$(location :create_release_docs)" +
" --version=" + BUILD_SCM_REV_CMD +
" --toc_path=$(location :new_toc.yaml)" +
" --buttons_path=$(location :new_buttons.html)" +
" --narrative_docs_path=$(location //site/en:docs)" +
" --reference_docs_path=$(location //src/main/java/com/google/devtools/build/lib:reference-docs.zip)" +
" --output_path=$(OUTS)",
Expand All @@ -30,12 +32,18 @@ genrule(
name = "gen_new_toc",
srcs = [
"//site/en:versions/_toc.yaml",
"//site/en:_buttons.html",
],
outs = [
"new_toc.yaml",
"new_buttons.html",
],
outs = ["new_toc.yaml"],
cmd = "$(location //src/main/java/com/google/devtools/build/docgen/release:toc_updater)" +
" -i $(location //site/en:versions/_toc.yaml)" +
" -o $(OUTS)" +
" -v " + BUILD_SCM_REV_CMD,
" -o $(location new_toc.yaml)" +
" -v " + BUILD_SCM_REV_CMD +
" --version_indicator_input=$(location //site/en:_buttons.html)" +
" --version_indicator_output=$(location new_buttons.html)",
stamp = 1,
tools = [
"//src/main/java/com/google/devtools/build/docgen/release:toc_updater",
Expand Down
14 changes: 13 additions & 1 deletion scripts/docs/create_release_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
None,
"Path to the _toc.yaml file that contains the table of contents for the versions menu.",
)
flags.DEFINE_string(
"buttons_path",
None,
"Path to the _buttons.html file that contains the version indicator.",
)
flags.DEFINE_string(
"narrative_docs_path",
None,
Expand Down Expand Up @@ -70,14 +75,16 @@ def validate_flag(name):
exit(1)


def create_docs_tree(version, toc_path, narrative_docs_path,
def create_docs_tree(version, toc_path, buttons_path, narrative_docs_path,
reference_docs_path):
"""Creates a directory tree containing the docs for the Bazel version.
Args:
version: Version of this Bazel release.
toc_path: Absolute path to the _toc.yaml file that lists the most recent
Bazel versions.
buttons_path: Absolute path of the _buttons.html file that contains the
version indicator.
narrative_docs_path: Absolute path of an archive that contains the narrative
documentation (can be .zip or .tar).
reference_docs_path: Absolute path of an archive that contains the reference
Expand All @@ -101,6 +108,10 @@ def create_docs_tree(version, toc_path, narrative_docs_path,
try_extract(narrative_docs_path, release_dir)
try_extract(reference_docs_path, release_dir)

buttons_dest_path = os.path.join(release_dir, "_buttons.html")
os.remove(buttons_dest_path)
shutil.copyfile(buttons_path, buttons_dest_path)

return root_dir, toc_dest_path, release_dir


Expand Down Expand Up @@ -179,6 +190,7 @@ def main(unused_argv):
root_dir, toc_path, release_dir = create_docs_tree(
version=version,
toc_path=validate_flag("toc_path"),
buttons_path=validate_flag("buttons_path"),
narrative_docs_path=validate_flag("narrative_docs_path"),
reference_docs_path=validate_flag("reference_docs_path"),
)
Expand Down
1 change: 1 addition & 0 deletions site/en/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ exports_files(
[
"docs/user-manual.md",
"versions/_toc.yaml",
"_buttons.html",
],
visibility = [
"//scripts/docs:__pkg__",
Expand Down
5 changes: 4 additions & 1 deletion site/en/_buttons.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
{% dynamic if not setvar.original_path %}
{% dynamic setvar original_path %}{% dynamic print request.path %}{% dynamic endsetvar %}
{% dynamic endif %}
<span style="float: right; line-height: 36px">
<span class="bazel-version-indicator">
{% dynamic if not setvar.version %}
<strong>Nightly</strong>
{% dynamic else %}
<a href="{% dynamic print setvar.original_path %}">Nightly</a>
{% dynamic endif %}
<!-- The lines below are updated by //scripts/docs:gen_new_toc -->
<!-- BEGIN_VERSION_INDICATOR -->
·
{% dynamic if setvar.version == "7.2.0" %}
<strong>7.2</strong>
Expand Down Expand Up @@ -49,5 +51,6 @@
{% dynamic else %}
<a href="/versions/6.4.0{% dynamic print setvar.original_path %}">6.4</a>
{% dynamic endif %}
<!-- END_VERSION_INDICATOR -->
</span>
</p>
5 changes: 5 additions & 0 deletions site/en/bazel.css
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,8 @@
margin-inline-start: 8px;
vertical-align: text-bottom;
}

.bazel-version-indicator {
fmeum marked this conversation as resolved.
Show resolved Hide resolved
float: right;
line-height: 36px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ public class TableOfContentsOptions extends OptionsBase {
help = "Path of the YAML file where the new TOC should be written to.")
public String outputPath;

@Option(
name = "version_indicator_input",
defaultValue = "",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.UNKNOWN},
help = "Path of the file containing the version indicator.")
public String versionIndicatorInputPath;

@Option(
name = "version_indicator_output",
defaultValue = "",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.UNKNOWN},
help = "Path of the file where the version indicator should be written.")
public String versionIndicatorOutputPath;

@Option(
name = "version",
abbrev = 'v',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@
package com.google.devtools.build.docgen.release;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.joining;

import com.google.common.flogger.GoogleLogger;
import com.google.devtools.common.options.OptionsParser;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

Expand All @@ -33,6 +37,20 @@ public class TableOfContentsUpdater {

private static final String VERSION_ROOT = "/versions/";

private static final String VERSION_INDICATOR_START = "<!-- BEGIN_VERSION_INDICATOR -->";

private static final String VERSION_INDICATOR_END = "<!-- END_VERSION_INDICATOR -->";

private static final String VERSION_INDICATOR_TEMPLATE =
"""
·
{% dynamic if setvar.version == "{canonical_version}" %}
<strong>{pretty_version}</strong>
{% dynamic else %}
<a href="{version_root}{canonical_version}/{% dynamic print setvar.original_path %}">{pretty_version}</a>
{% dynamic endif %}
""";

private TableOfContentsUpdater() {}

public static void main(String[] args) {
Expand All @@ -52,23 +70,43 @@ public static void main(String[] args) {
}

Yaml yaml = new Yaml(getYamlOptions());
List<String> versions;
try (FileInputStream fis = new FileInputStream(options.inputPath)) {
Object data = yaml.load(fis);
update(data, options.version, options.maxReleases);
versions = updateTocAndGetVersions(data, options.version, options.maxReleases);
yaml.dump(data, new OutputStreamWriter(new FileOutputStream(options.outputPath), UTF_8));
} catch (Throwable t) {
System.err.printf("ERROR: %s\n", t.getMessage());
logger.atSevere().withCause(t).log(
"Failed to transform TOC from %s to %s", options.inputPath, options.outputPath);
Runtime.getRuntime().exit(1);
throw new IllegalStateException("Not reached");
}

if (!options.versionIndicatorInputPath.isEmpty()) {
try {
Files.writeString(
Path.of(options.versionIndicatorOutputPath),
makeUpdatedVersionIndicator(
Files.readString(Path.of(options.versionIndicatorInputPath)), versions));
} catch (Throwable t) {
System.err.printf("ERROR: %s\n", t.getMessage());
logger.atSevere().withCause(t).log(
"Failed to update version indicator from %s to %s",
options.versionIndicatorInputPath, options.versionIndicatorOutputPath);
Runtime.getRuntime().exit(1);
}
}
}

private static void printUsage() {
System.err.println(
"Usage: toc-updater -i src_toc_path -o dest_toc_path -v version [-m max_releases] [-h]\n\n"
+ "Reads the input TOC, adds an entry for the specified version and saves the new TOC"
+ " at the specified location.\n");
"""
Usage: toc-updater -i src_toc_path -o dest_toc_path -v version [-m max_releases] [-h] [--version_indicator_input path --version_indicator_output path]
Reads the input TOC, adds an entry for the specified version and saves the new TOC\
at the specified location.
""");
}

private static DumperOptions getYamlOptions() {
Expand All @@ -79,10 +117,11 @@ private static DumperOptions getYamlOptions() {
return opts;
}

private static void update(Object data, String version, int maxReleases) {
private static List<String> updateTocAndGetVersions(
Object data, String version, int maxReleases) {
@SuppressWarnings("unchecked") // yaml deserialization
Map<String, List<Map<String, String>>> m = (Map<String, List<Map<String, String>>>) data;
List<Map<String, String>> toc = (List<Map<String, String>>) m.get("toc");
List<Map<String, String>> toc = m.get("toc");
if (toc == null) {
throw new IllegalStateException("Missing 'toc' element.");
}
Expand All @@ -91,9 +130,53 @@ private static void update(Object data, String version, int maxReleases) {
newEntry.put("path", String.format("%s%s", VERSION_ROOT, version));
newEntry.put("label", version);

toc.add(0, newEntry);
toc.addFirst(newEntry);
if (toc.size() > maxReleases) {
m.put("toc", toc.subList(0, maxReleases));
}

return m.get("toc").stream()
// Exclude legacy doc versions.
.filter(e -> e.get("path").startsWith(VERSION_ROOT))
.map(e -> e.get("label"))
.map(TableOfContentsUpdater::canonicalizeVersion)
.toList();
}

private static String makeUpdatedVersionIndicator(
String oldVersionIndicator, List<String> versions) {
int beginPos = oldVersionIndicator.indexOf(VERSION_INDICATOR_START);
int endPos = oldVersionIndicator.indexOf(VERSION_INDICATOR_END);
if (beginPos == -1 || endPos == -1) {
throw new IllegalStateException("Version indicator markers not found.");
}
// Include the line terminator.
String prefix =
oldVersionIndicator.substring(0, beginPos + VERSION_INDICATOR_START.length() + 1);
String suffix = oldVersionIndicator.substring(endPos);
return versions.stream()
.map(
version ->
VERSION_INDICATOR_TEMPLATE
.replace("{canonical_version}", version)
.replace("{pretty_version}", prettifyVersion(version))
.replace("{version_root}", VERSION_ROOT))
.collect(joining("", prefix, suffix));
}

private static String canonicalizeVersion(String version) {
if (version.split(Pattern.quote(".")).length < 3) {
return version + ".0";
} else {
return version;
}
}

private static String prettifyVersion(String version) {
if (version.endsWith(".0")) {
return version.substring(0, version.length() - 2);
} else {
return version;
}
}
}
Loading