* [PATCH v2] doc: fix the switchers menu
@ 2026-02-04 10:03 Antonin Godard
2026-02-04 13:32 ` [bitbake-devel] " Richard Purdie
2026-02-04 15:01 ` [docs] " Quentin Schulz
0 siblings, 2 replies; 8+ messages in thread
From: Antonin Godard @ 2026-02-04 10:03 UTC (permalink / raw)
To: bitbake-devel; +Cc: Thomas Petazzoni, docs, Antonin Godard
Fix the switchers.js script of Bitbake to show what are the supported
versions and be able to switch between them.
The default landing page is the stable branch and shows the BitBake
version along with the corresponding Yocto Project codename. This
hopefully makes it easier to remember the correspondance between the
BitBake version and the Yocto Project version.
This works thanks to a set_versions.py script, which is largely inspired
from yocto-docs. It reads the tags from the repository and tries to
guess the currently checked out version of BitBake on which we are.
The "obsolete" warning is now also shown when browsing outdated manuals,
meaning any version not part of activereleases in set_versions.py.
Signed-off-by: Antonin Godard <antonin.godard@bootlin.com>
---
Note: This will be accompanied by a patch to adapt the Autobuilder to
generate this file for each release.
---
Changes in v2:
- Remove environment information grabbing mechanism, making this fully
standalone.
- Link to v1: https://lore.kernel.org/r/20250915-fix-switchers-js-v1-0-523ef53fe802@bootlin.com
---
doc/.gitignore | 2 +
doc/Makefile | 3 +-
doc/bitbake.yaml.in | 1 +
doc/conf.py | 10 +-
doc/set_versions.py | 155 ++++++++++++++++++++++++
doc/sphinx-static/switchers.js | 233 -----------------------------------
doc/sphinx-static/switchers.js.in | 247 ++++++++++++++++++++++++++++++++++++++
7 files changed, 416 insertions(+), 235 deletions(-)
diff --git a/doc/.gitignore b/doc/.gitignore
index 69fa449dd96..40ebe76c088 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -1 +1,3 @@
_build/
+sphinx-static/switchers.js
+bitbake.yaml
diff --git a/doc/Makefile b/doc/Makefile
index 996f01b7d5c..cdb054d3a52 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -27,9 +27,10 @@ publish: Makefile html singlehtml
sed -i -e 's@index.html#@singleindex.html#@g' $(BUILDDIR)/$(DESTDIR)/singleindex.html
clean:
- @rm -rf $(BUILDDIR)
+ @rm -rf $(BUILDDIR) sphinx-static/switchers.js bitbake.yaml
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
+ $(SOURCEDIR)/set_versions.py
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/bitbake.yaml.in b/doc/bitbake.yaml.in
new file mode 100644
index 00000000000..4085582df60
--- /dev/null
+++ b/doc/bitbake.yaml.in
@@ -0,0 +1 @@
+DOCCONF_VERSION : "dev"
diff --git a/doc/conf.py b/doc/conf.py
index bce386624e2..5b28808c590 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -14,17 +14,25 @@
# import sys
# sys.path.insert(0, os.path.abspath('.'))
+import os
import sys
import datetime
+import yaml
from pathlib import Path
-current_version = "dev"
+current_version = 'dev'
+
+with open("bitbake.yaml") as data:
+ buff = data.read()
+ subst_vars = yaml.safe_load(buff)
+ current_version = subst_vars["DOCCONF_VERSION"]
# String used in sidebar
version = 'Version: ' + current_version
if current_version == 'dev':
version = 'Version: Current Development'
+
# Version seen in documentation_options.js and hence in js switchers code
release = current_version
diff --git a/doc/set_versions.py b/doc/set_versions.py
new file mode 100755
index 00000000000..63fba2fe948
--- /dev/null
+++ b/doc/set_versions.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+#
+# This is a minimal version of the set_versions.py from yocto-docs,
+# use to replace VERSIONS_PLACEHOLDER in switchers.js.in by a list defined below
+# with BITBAKE_ACTIVE_RELEASES in the environment.
+#
+# When the documentation is built with the autobuilder, the versions are
+# calculated based on the info found in set_versions.py from yocto-docs.
+#
+# Copyright Linux Foundation
+# Author: Antonin Godard <antonin.godard@bootlin.com>
+#
+# SPDX-License-Identifier: MIT
+#
+
+import collections
+import itertools
+import re
+import os
+import subprocess
+import sys
+
+from packaging.version import Version
+from typing import Tuple
+
+devbranch = "2.18"
+ltsseries = ["2.8", "2.0"]
+activereleases = ["2.16"] + ltsseries
+
+yocto_mapping = {
+ "2.18": "wrynose",
+ "2.16": "whinlatter",
+ "2.12": "walnascar",
+ "2.10": "styhead",
+ "2.8": "scarthgap",
+ "2.6": "nanbield",
+ "2.4": "mickledore",
+ "2.2": "langdale",
+ "2.0": "kirkstone",
+ "1.52": "honister",
+ "1.50": "hardknott",
+ "1.48": "gatesgarth",
+ "1.46": "dunfell",
+}
+
+bbver_re = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+$")
+ourversion = None
+
+# Test that we are building from a Git repository
+try:
+ subprocess.run(["git", "rev-parse", "--is-inside-work-tree"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
+except subprocess.CalledProcessError:
+ sys.exit("Building bitbake's documentation must be done from its Git repository.\n"
+ "Clone the repository with the following command:\n"
+ "git clone https://git.openembedded.org/bitbake ")
+
+# Test tags exist and inform the user to fetch if not
+try:
+ subprocess.run(["git", "show", f"{ltsseries[0]}.0"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
+except subprocess.CalledProcessError:
+ sys.exit("Please run 'git fetch --tags' before building the documentation")
+
+
+# Try and figure out what we are
+tags = subprocess.run(["git", "tag", "--points-at", "HEAD"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ universal_newlines=True).stdout
+for t in tags.split():
+ if re.match(bbver_re, t):
+ ourversion = t
+
+if ourversion:
+ # We're a tagged release
+ components = ourversion.split(".")
+ ourseries = f"{components[0]}.{components[1]}"
+else:
+ # We're floating on a branch
+ branch = subprocess.run(["git", "branch", "--show-current"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ universal_newlines=True).stdout.strip()
+
+ if branch == "" or branch not in list(yocto_mapping.keys()) + ["master", "master-next"]:
+ # We're not on a known release branch so we have to guess. Compare the
+ # numbers of commits from each release branch and assume the smallest
+ # number of commits is the one we're based off
+ possible_branch = None
+ branch_count = 0
+ for b in itertools.chain(yocto_mapping.keys(), ["master"]):
+ result = subprocess.run(["git", "log", "--format=oneline", "HEAD..origin/" + b],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ universal_newlines=True)
+ if result.returncode == 0:
+ count = result.stdout.count('\n')
+ if not possible_branch or count < branch_count:
+ print("Branch %s has count %s" % (b, count))
+ possible_branch = b
+ branch_count = count
+ if possible_branch:
+ branch = possible_branch
+ else:
+ branch = "master"
+ print("Nearest release branch estimated to be %s" % branch)
+
+ if branch == "master":
+ ourversion = "dev"
+ ourseries = devbranch
+ elif branch == "master-next":
+ ourversion = "next"
+ ourseries = devbranch
+ else:
+ ourversion = branch
+ head_commit = subprocess.run(["git", "rev-parse", "--short", "HEAD"],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ universal_newlines=True).stdout.strip()
+ branch_commit = subprocess.run(["git", "rev-parse", "--short", branch],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ universal_newlines=True).stdout.strip()
+ if head_commit != branch_commit:
+ ourversion += f" ({head_commit})"
+ ourseries = branch
+
+print("Version calculated to be %s" % ourversion)
+print("Series calculated to be %s" % ourseries)
+
+replacements = {
+ "DOCCONF_VERSION": ourversion,
+}
+
+if os.path.exists("bitbake.yaml.in"):
+ with open("bitbake.yaml.in", "r") as r, open("bitbake.yaml", "w") as w:
+ lines = r.readlines()
+ for line in lines:
+ data = line.split(":")
+ k = data[0].strip()
+ if k in replacements:
+ w.write("%s : \"%s\"\n" % (k, replacements[k]))
+ else:
+ w.write(line)
+
+ print("bitbake.yaml generated from bitbake.yaml.in")
+
+with open("sphinx-static/switchers.js.in", "r") as r, \
+ open("sphinx-static/switchers.js", "w") as w:
+ lines = r.readlines()
+ for line in lines:
+ if "VERSIONS_PLACEHOLDER" in line:
+ if ourversion != "dev":
+ w.write(f" 'dev': 'Unstable (dev)',\n")
+ for series in activereleases:
+ w.write(f" '{series}': '{series} ({yocto_mapping[series]})',\n")
+ else:
+ w.write(line)
+ print("switchers.js generated from switchers.js.in")
diff --git a/doc/sphinx-static/switchers.js b/doc/sphinx-static/switchers.js
deleted file mode 100644
index 32113cfa960..00000000000
--- a/doc/sphinx-static/switchers.js
+++ /dev/null
@@ -1,233 +0,0 @@
-(function() {
- 'use strict';
-
- var all_versions = {
- 'dev': 'dev (3.2)',
- '3.1.2': '3.1.2',
- '3.0.3': '3.0.3',
- '2.7.4': '2.7.4',
- };
-
- var all_doctypes = {
- 'single': 'Individual Webpages',
- 'mega': "All-in-one 'Mega' Manual",
- };
-
- // Simple version comparision
- // Return 1 if a > b
- // Return -1 if a < b
- // Return 0 if a == b
- function ver_compare(a, b) {
- if (a == "dev") {
- return 1;
- }
-
- if (a === b) {
- return 0;
- }
-
- var a_components = a.split(".");
- var b_components = b.split(".");
-
- var len = Math.min(a_components.length, b_components.length);
-
- // loop while the components are equal
- for (var i = 0; i < len; i++) {
- // A bigger than B
- if (parseInt(a_components[i]) > parseInt(b_components[i])) {
- return 1;
- }
-
- // B bigger than A
- if (parseInt(a_components[i]) < parseInt(b_components[i])) {
- return -1;
- }
- }
-
- // If one's a prefix of the other, the longer one is greater.
- if (a_components.length > b_components.length) {
- return 1;
- }
-
- if (a_components.length < b_components.length) {
- return -1;
- }
-
- // Otherwise they are the same.
- return 0;
- }
-
- function build_version_select(current_series, current_version) {
- var buf = ['<select>'];
-
- $.each(all_versions, function(version, title) {
- var series = version.substr(0, 3);
- if (series == current_series) {
- if (version == current_version)
- buf.push('<option value="' + version + '" selected="selected">' + title + '</option>');
- else
- buf.push('<option value="' + version + '">' + title + '</option>');
-
- if (version != current_version)
- buf.push('<option value="' + current_version + '" selected="selected">' + current_version + '</option>');
- } else {
- buf.push('<option value="' + version + '">' + title + '</option>');
- }
- });
-
- buf.push('</select>');
- return buf.join('');
- }
-
- function build_doctype_select(current_doctype) {
- var buf = ['<select>'];
-
- $.each(all_doctypes, function(doctype, title) {
- if (doctype == current_doctype)
- buf.push('<option value="' + doctype + '" selected="selected">' +
- all_doctypes[current_doctype] + '</option>');
- else
- buf.push('<option value="' + doctype + '">' + title + '</option>');
- });
- if (!(current_doctype in all_doctypes)) {
- // In case we're browsing a doctype that is not yet in all_doctypes.
- buf.push('<option value="' + current_doctype + '" selected="selected">' +
- current_doctype + '</option>');
- all_doctypes[current_doctype] = current_doctype;
- }
- buf.push('</select>');
- return buf.join('');
- }
-
- function navigate_to_first_existing(urls) {
- // Navigate to the first existing URL in urls.
- var url = urls.shift();
-
- // Web browsers won't redirect file:// urls to file urls using ajax but
- // its useful for local testing
- if (url.startsWith("file://")) {
- window.location.href = url;
- return;
- }
-
- if (urls.length == 0) {
- window.location.href = url;
- return;
- }
- $.ajax({
- url: url,
- success: function() {
- window.location.href = url;
- },
- error: function() {
- navigate_to_first_existing(urls);
- }
- });
- }
-
- function get_docroot_url() {
- var url = window.location.href;
- var root = DOCUMENTATION_OPTIONS.URL_ROOT;
-
- var urlarray = url.split('/');
- // Trim off anything after '/'
- urlarray.pop();
- var depth = (root.match(/\.\.\//g) || []).length;
- for (var i = 0; i < depth; i++) {
- urlarray.pop();
- }
-
- return urlarray.join('/') + '/';
- }
-
- function on_version_switch() {
- var selected_version = $(this).children('option:selected').attr('value');
- var url = window.location.href;
- var current_version = DOCUMENTATION_OPTIONS.VERSION;
- var docroot = get_docroot_url()
-
- var new_versionpath = selected_version + '/';
- if (selected_version == "dev")
- new_versionpath = '';
-
- // dev versions have no version prefix
- if (current_version == "dev") {
- var new_url = docroot + new_versionpath + url.replace(docroot, "");
- var fallback_url = docroot + new_versionpath;
- } else {
- var new_url = url.replace('/' + current_version + '/', '/' + new_versionpath);
- var fallback_url = new_url.replace(url.replace(docroot, ""), "");
- }
-
- console.log(get_docroot_url())
- console.log(url + " to url " + new_url);
- console.log(url + " to fallback " + fallback_url);
-
- if (new_url != url) {
- navigate_to_first_existing([
- new_url,
- fallback_url,
- 'https://www.yoctoproject.org/docs/',
- ]);
- }
- }
-
- function on_doctype_switch() {
- var selected_doctype = $(this).children('option:selected').attr('value');
- var url = window.location.href;
- if (selected_doctype == 'mega') {
- var docroot = get_docroot_url()
- var current_version = DOCUMENTATION_OPTIONS.VERSION;
- // Assume manuals before 3.2 are using old docbook mega-manual
- if (ver_compare(current_version, "3.2") < 0) {
- var new_url = docroot + "mega-manual/mega-manual.html";
- } else {
- var new_url = docroot + "singleindex.html";
- }
- } else {
- var new_url = url.replace("singleindex.html", "index.html")
- }
-
- if (new_url != url) {
- navigate_to_first_existing([
- new_url,
- 'https://www.yoctoproject.org/docs/',
- ]);
- }
- }
-
- // Returns the current doctype based upon the url
- function doctype_segment_from_url(url) {
- if (url.includes("singleindex") || url.includes("mega-manual"))
- return "mega";
- return "single";
- }
-
- $(document).ready(function() {
- var release = DOCUMENTATION_OPTIONS.VERSION;
- var current_doctype = doctype_segment_from_url(window.location.href);
- var current_series = release.substr(0, 3);
- var version_select = build_version_select(current_series, release);
-
- $('.version_switcher_placeholder').html(version_select);
- $('.version_switcher_placeholder select').bind('change', on_version_switch);
-
- var doctype_select = build_doctype_select(current_doctype);
-
- $('.doctype_switcher_placeholder').html(doctype_select);
- $('.doctype_switcher_placeholder select').bind('change', on_doctype_switch);
-
- if (ver_compare(release, "3.1") < 0) {
- $('#outdated-warning').html('Version ' + release + ' of the project is now considered obsolete, please select and use a more recent version');
- $('#outdated-warning').css('padding', '.5em');
- } else if (release != "dev") {
- $.each(all_versions, function(version, title) {
- var series = version.substr(0, 3);
- if (series == current_series && version != release) {
- $('#outdated-warning').html('This document is for outdated version ' + release + ', you should select the latest release version in this series, ' + version + '.');
- $('#outdated-warning').css('padding', '.5em');
- }
- });
- }
- });
-})();
diff --git a/doc/sphinx-static/switchers.js.in b/doc/sphinx-static/switchers.js.in
new file mode 100644
index 00000000000..108d1a7d77f
--- /dev/null
+++ b/doc/sphinx-static/switchers.js.in
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: MIT
+(function () {
+ "use strict";
+
+ var all_versions = {
+ VERSIONS_PLACEHOLDER,
+ };
+
+ var all_doctypes = {
+ single: "Individual Webpages",
+ mega: "All-in-one 'Mega' Manual",
+ };
+
+ // Simple version comparision
+ // Return 1 if a > b
+ // Return -1 if a < b
+ // Return 0 if a == b
+ function ver_compare(a, b) {
+ if (a == "dev") {
+ return 1;
+ }
+
+ if (a === b) {
+ return 0;
+ }
+
+ var a_components = a.split(".");
+ var b_components = b.split(".");
+
+ var len = Math.min(a_components.length, b_components.length);
+
+ // loop while the components are equal
+ for (var i = 0; i < len; i++) {
+ // A bigger than B
+ if (parseInt(a_components[i]) > parseInt(b_components[i])) {
+ return 1;
+ }
+
+ // B bigger than A
+ if (parseInt(a_components[i]) < parseInt(b_components[i])) {
+ return -1;
+ }
+ }
+
+ // If one's a prefix of the other, the longer one is greater.
+ if (a_components.length > b_components.length) {
+ return 1;
+ }
+
+ if (a_components.length < b_components.length) {
+ return -1;
+ }
+
+ // Otherwise they are the same.
+ return 0;
+ }
+
+ function build_version_select(current_version) {
+ var buf = ["<select>"];
+
+ $.each(all_versions, function (version, title) {
+ if (current_version != version) {
+ buf.push(
+ '<option value="' +
+ version +
+ '" selected="selected">' +
+ title +
+ "</option>",
+ );
+ }
+ });
+
+ var current_title = current_version;
+ if (current_version in all_versions) {
+ current_title = all_versions[current_version];
+ }
+ buf.push(
+ '<option value="' +
+ current_version +
+ '" selected="selected">' +
+ current_title +
+ "</option>",
+ );
+
+ buf.push("</select>");
+ return buf.join("");
+ }
+
+ function build_doctype_select(current_doctype) {
+ var buf = ["<select>"];
+
+ $.each(all_doctypes, function (doctype, title) {
+ if (doctype == current_doctype)
+ buf.push(
+ '<option value="' +
+ doctype +
+ '" selected="selected">' +
+ all_doctypes[current_doctype] +
+ "</option>",
+ );
+ else buf.push('<option value="' + doctype + '">' + title + "</option>");
+ });
+ if (!(current_doctype in all_doctypes)) {
+ // In case we're browsing a doctype that is not yet in all_doctypes.
+ buf.push(
+ '<option value="' +
+ current_doctype +
+ '" selected="selected">' +
+ current_doctype +
+ "</option>",
+ );
+ all_doctypes[current_doctype] = current_doctype;
+ }
+ buf.push("</select>");
+ return buf.join("");
+ }
+
+ function navigate_to_first_existing(urls) {
+ // Navigate to the first existing URL in urls.
+ var url = urls.shift();
+
+ // Web browsers won't redirect file:// urls to file urls using ajax but
+ // its useful for local testing
+ if (url.startsWith("file://")) {
+ window.location.href = url;
+ return;
+ }
+
+ if (urls.length == 0) {
+ window.location.href = url;
+ return;
+ }
+ $.ajax({
+ url: url,
+ success: function () {
+ window.location.href = url;
+ },
+ error: function () {
+ navigate_to_first_existing(urls);
+ },
+ });
+ }
+
+ function get_docroot_url() {
+ var url = window.location.href;
+ // Try to get the variable from documentation_options.js
+ var root = DOCUMENTATION_OPTIONS.URL_ROOT;
+ if (root == null) {
+ // In recent versions of Sphinx, URL_ROOT was removed from
+ // documentation_options.js, so get it like searchtools.js does.
+ root = document.documentElement.dataset.content_root;
+ }
+
+ var urlarray = url.split("/");
+ // Trim off anything after '/'
+ urlarray.pop();
+ var depth = (root.match(/\.\.\//g) || []).length;
+ for (var i = 0; i < depth; i++) {
+ urlarray.pop();
+ }
+
+ return urlarray.join("/") + "/";
+ }
+
+ function on_version_switch() {
+ var selected_version = $(this).children("option:selected").attr("value");
+ var url = window.location.href;
+ var current_version = DOCUMENTATION_OPTIONS.VERSION;
+ var docroot = get_docroot_url();
+
+ var new_versionpath = selected_version + "/";
+
+ // latest tag is also the default page (without version information)
+ if (docroot.endsWith("dev/")) {
+ var new_url = url.replace("/dev/", "/" + new_versionpath);
+ var fallback_url = new_url.replace(url.replace(docroot, ""), "");
+ } else if (docroot.endsWith(current_version + "/") == false) {
+ var new_url = docroot + new_versionpath + url.replace(docroot, "");
+ var fallback_url = docroot + new_versionpath;
+ } else {
+ var new_url = url.replace(
+ "/" + current_version + "/",
+ "/" + new_versionpath,
+ );
+ var fallback_url = new_url.replace(url.replace(docroot, ""), "");
+ }
+
+ console.log(url + " to url " + new_url);
+ console.log(url + " to fallback " + fallback_url);
+
+ if (new_url != url) {
+ navigate_to_first_existing([
+ new_url,
+ fallback_url,
+ "https://www.yoctoproject.org/bitbake/",
+ ]);
+ }
+ }
+
+ function on_doctype_switch() {
+ var selected_doctype = $(this).children("option:selected").attr("value");
+ var url = window.location.href;
+ if (selected_doctype == "mega") {
+ var docroot = get_docroot_url();
+ var current_version = DOCUMENTATION_OPTIONS.VERSION;
+ var new_url = docroot + "singleindex.html";
+ } else {
+ var new_url = url.replace("singleindex.html", "index.html");
+ }
+
+ if (new_url != url) {
+ navigate_to_first_existing([
+ new_url,
+ "https://www.yoctoproject.org/docs/",
+ ]);
+ }
+ }
+
+ // Returns the current doctype based upon the url
+ function doctype_segment_from_url(url) {
+ if (url.includes("singleindex") || url.includes("mega-manual"))
+ return "mega";
+ return "single";
+ }
+
+ $(document).ready(function () {
+ var release = DOCUMENTATION_OPTIONS.VERSION;
+ var current_doctype = doctype_segment_from_url(window.location.href);
+ var current_series = release.substr(0, 3);
+ var version_select = build_version_select(release);
+
+ $(".version_switcher_placeholder").html(version_select);
+ $(".version_switcher_placeholder select").bind("change", on_version_switch);
+
+ var doctype_select = build_doctype_select(current_doctype);
+
+ $(".doctype_switcher_placeholder").html(doctype_select);
+ $(".doctype_switcher_placeholder select").bind("change", on_doctype_switch);
+
+ if (!(["dev", "next"].includes(release)) && !(release in all_versions)) {
+ $("#outdated-warning").html(
+ "Version " + release + " of the project is now considered obsolete, please select and use a more recent version",
+ );
+ $("#outdated-warning").css("padding", ".5em");
+ }
+ });
+})();
---
base-commit: cdd79c1768ac396a9c6577e38098da4331507f24
change-id: 20241227-fix-switchers-js-8cf445610b97
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [bitbake-devel] [PATCH v2] doc: fix the switchers menu
2026-02-04 10:03 [PATCH v2] doc: fix the switchers menu Antonin Godard
@ 2026-02-04 13:32 ` Richard Purdie
2026-02-04 13:41 ` Antonin Godard
2026-02-04 15:01 ` [docs] " Quentin Schulz
1 sibling, 1 reply; 8+ messages in thread
From: Richard Purdie @ 2026-02-04 13:32 UTC (permalink / raw)
To: antonin.godard, bitbake-devel; +Cc: Thomas Petazzoni, docs
On Wed, 2026-02-04 at 11:03 +0100, Antonin Godard via lists.openembedded.org wrote:
> Fix the switchers.js script of Bitbake to show what are the supported
> versions and be able to switch between them.
>
> The default landing page is the stable branch and shows the BitBake
> version along with the corresponding Yocto Project codename. This
> hopefully makes it easier to remember the correspondance between the
> BitBake version and the Yocto Project version.
>
> This works thanks to a set_versions.py script, which is largely inspired
> from yocto-docs. It reads the tags from the repository and tries to
> guess the currently checked out version of BitBake on which we are.
>
> The "obsolete" warning is now also shown when browsing outdated manuals,
> meaning any version not part of activereleases in set_versions.py.
>
> Signed-off-by: Antonin Godard <antonin.godard@bootlin.com>
> ---
> Note: This will be accompanied by a patch to adapt the Autobuilder to
> generate this file for each release.
> ---
> Changes in v2:
> - Remove environment information grabbing mechanism, making this fully
> standalone.
> - Link to v1: https://lore.kernel.org/r/20250915-fix-switchers-js-v1-0-523ef53fe802@bootlin.com
> ---
> doc/.gitignore | 2 +
> doc/Makefile | 3 +-
> doc/bitbake.yaml.in | 1 +
I was about to merge this however is there a requirement to use yaml
here? I ask mainly as we don't currently have yaml config files and I'd
prefer not to start adding them and try to remain consistent with what
we're using...
Cheers,
Richard
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [bitbake-devel] [PATCH v2] doc: fix the switchers menu
2026-02-04 13:32 ` [bitbake-devel] " Richard Purdie
@ 2026-02-04 13:41 ` Antonin Godard
0 siblings, 0 replies; 8+ messages in thread
From: Antonin Godard @ 2026-02-04 13:41 UTC (permalink / raw)
To: Richard Purdie, bitbake-devel; +Cc: Thomas Petazzoni, docs
On Wed Feb 4, 2026 at 2:32 PM CET, Richard Purdie wrote:
> On Wed, 2026-02-04 at 11:03 +0100, Antonin Godard via lists.openembedded.org wrote:
>> Fix the switchers.js script of Bitbake to show what are the supported
>> versions and be able to switch between them.
>>
>> The default landing page is the stable branch and shows the BitBake
>> version along with the corresponding Yocto Project codename. This
>> hopefully makes it easier to remember the correspondance between the
>> BitBake version and the Yocto Project version.
>>
>> This works thanks to a set_versions.py script, which is largely inspired
>> from yocto-docs. It reads the tags from the repository and tries to
>> guess the currently checked out version of BitBake on which we are.
>>
>> The "obsolete" warning is now also shown when browsing outdated manuals,
>> meaning any version not part of activereleases in set_versions.py.
>>
>> Signed-off-by: Antonin Godard <antonin.godard@bootlin.com>
>> ---
>> Note: This will be accompanied by a patch to adapt the Autobuilder to
>> generate this file for each release.
>> ---
>> Changes in v2:
>> - Remove environment information grabbing mechanism, making this fully
>> standalone.
>> - Link to v1: https://lore.kernel.org/r/20250915-fix-switchers-js-v1-0-523ef53fe802@bootlin.com
>> ---
>> doc/.gitignore | 2 +
>> doc/Makefile | 3 +-
>> doc/bitbake.yaml.in | 1 +
>
> I was about to merge this however is there a requirement to use yaml
> here? I ask mainly as we don't currently have yaml config files and I'd
> prefer not to start adding them and try to remain consistent with what
> we're using...
You're right, I don't see any obvious reason to use yaml either, and we could
use JSON instead. I just aligned with what was done on yocto-docs without this
afterthought. I'd be happy to make the switch (here and perhaps we could also do
that on yocto-docs). I'll try it out, thanks.
Antonin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [docs] [PATCH v2] doc: fix the switchers menu
2026-02-04 10:03 [PATCH v2] doc: fix the switchers menu Antonin Godard
2026-02-04 13:32 ` [bitbake-devel] " Richard Purdie
@ 2026-02-04 15:01 ` Quentin Schulz
2026-02-05 11:34 ` Antonin Godard
1 sibling, 1 reply; 8+ messages in thread
From: Quentin Schulz @ 2026-02-04 15:01 UTC (permalink / raw)
To: antonin.godard, bitbake-devel; +Cc: Thomas Petazzoni, docs
Hi Antonin,
On 2/4/26 11:03 AM, Antonin Godard via lists.yoctoproject.org wrote:
> Fix the switchers.js script of Bitbake to show what are the supported
> versions and be able to switch between them.
>
> The default landing page is the stable branch and shows the BitBake
> version along with the corresponding Yocto Project codename. This
> hopefully makes it easier to remember the correspondance between the
> BitBake version and the Yocto Project version.
>
> This works thanks to a set_versions.py script, which is largely inspired
> from yocto-docs. It reads the tags from the repository and tries to
> guess the currently checked out version of BitBake on which we are.
>
> The "obsolete" warning is now also shown when browsing outdated manuals,
> meaning any version not part of activereleases in set_versions.py.
>
> Signed-off-by: Antonin Godard <antonin.godard@bootlin.com>
> ---
> Note: This will be accompanied by a patch to adapt the Autobuilder to
> generate this file for each release.
> ---
> Changes in v2:
> - Remove environment information grabbing mechanism, making this fully
> standalone.
> - Link to v1: https://lore.kernel.org/r/20250915-fix-switchers-js-v1-0-523ef53fe802@bootlin.com
> ---
> doc/.gitignore | 2 +
> doc/Makefile | 3 +-
> doc/bitbake.yaml.in | 1 +
> doc/conf.py | 10 +-
> doc/set_versions.py | 155 ++++++++++++++++++++++++
> doc/sphinx-static/switchers.js | 233 -----------------------------------
> doc/sphinx-static/switchers.js.in | 247 ++++++++++++++++++++++++++++++++++++++
> 7 files changed, 416 insertions(+), 235 deletions(-)
>
> diff --git a/doc/.gitignore b/doc/.gitignore
> index 69fa449dd96..40ebe76c088 100644
> --- a/doc/.gitignore
> +++ b/doc/.gitignore
> @@ -1 +1,3 @@
> _build/
> +sphinx-static/switchers.js
> +bitbake.yaml
> diff --git a/doc/Makefile b/doc/Makefile
> index 996f01b7d5c..cdb054d3a52 100644
> --- a/doc/Makefile
> +++ b/doc/Makefile
> @@ -27,9 +27,10 @@ publish: Makefile html singlehtml
> sed -i -e 's@index.html#@singleindex.html#@g' $(BUILDDIR)/$(DESTDIR)/singleindex.html
>
> clean:
> - @rm -rf $(BUILDDIR)
> + @rm -rf $(BUILDDIR) sphinx-static/switchers.js bitbake.yaml
>
> # Catch-all target: route all unknown targets to Sphinx using the new
> # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
> %: Makefile
> + $(SOURCEDIR)/set_versions.py
> @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
> diff --git a/doc/bitbake.yaml.in b/doc/bitbake.yaml.in
> new file mode 100644
> index 00000000000..4085582df60
> --- /dev/null
> +++ b/doc/bitbake.yaml.in
> @@ -0,0 +1 @@
> +DOCCONF_VERSION : "dev"
> diff --git a/doc/conf.py b/doc/conf.py
> index bce386624e2..5b28808c590 100644
> --- a/doc/conf.py
> +++ b/doc/conf.py
> @@ -14,17 +14,25 @@
> # import sys
> # sys.path.insert(0, os.path.abspath('.'))
>
> +import os
I don't see it being used?
> import sys
> import datetime
> +import yaml
>
> from pathlib import Path
>
> -current_version = "dev"
> +current_version = 'dev'
Unnecessary noise.
> +
> +with open("bitbake.yaml") as data:
> + buff = data.read()
> + subst_vars = yaml.safe_load(buff)
> + current_version = subst_vars["DOCCONF_VERSION"]
>
> # String used in sidebar
> version = 'Version: ' + current_version
> if current_version == 'dev':
> version = 'Version: Current Development'
> +
Ditto.
> # Version seen in documentation_options.js and hence in js switchers code
> release = current_version
>
> diff --git a/doc/set_versions.py b/doc/set_versions.py
> new file mode 100755
> index 00000000000..63fba2fe948
> --- /dev/null
> +++ b/doc/set_versions.py
> @@ -0,0 +1,155 @@
> +#!/usr/bin/env python3
> +#
> +# This is a minimal version of the set_versions.py from yocto-docs,
> +# use to replace VERSIONS_PLACEHOLDER in switchers.js.in by a list defined below
> +# with BITBAKE_ACTIVE_RELEASES in the environment.
> +#
Where?
> +# When the documentation is built with the autobuilder, the versions are
> +# calculated based on the info found in set_versions.py from yocto-docs.
> +#
> +# Copyright Linux Foundation
> +# Author: Antonin Godard <antonin.godard@bootlin.com>
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +
> +import collections
> +import itertools
> +import re
> +import os
> +import subprocess
> +import sys
> +
Sort alphabetically please.
> +from packaging.version import Version
> +from typing import Tuple
> +
> +devbranch = "2.18"
> +ltsseries = ["2.8", "2.0"]
> +activereleases = ["2.16"] + ltsseries
> +
> +yocto_mapping = {
> + "2.18": "wrynose",
> + "2.16": "whinlatter",
> + "2.12": "walnascar",
> + "2.10": "styhead",
> + "2.8": "scarthgap",
> + "2.6": "nanbield",
> + "2.4": "mickledore",
> + "2.2": "langdale",
> + "2.0": "kirkstone",
> + "1.52": "honister",
> + "1.50": "hardknott",
> + "1.48": "gatesgarth",
> + "1.46": "dunfell",
> +}
> +
> +bbver_re = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+$")
> +ourversion = None
> +
> +# Test that we are building from a Git repository
> +try:
> + subprocess.run(["git", "rev-parse", "--is-inside-work-tree"],
> + stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
> +except subprocess.CalledProcessError:
> + sys.exit("Building bitbake's documentation must be done from its Git repository.\n"
> + "Clone the repository with the following command:\n"
> + "git clone https://git.openembedded.org/bitbake ")
> +
> +# Test tags exist and inform the user to fetch if not
> +try:
> + subprocess.run(["git", "show", f"{ltsseries[0]}.0"],
> + stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
> +except subprocess.CalledProcessError:
> + sys.exit("Please run 'git fetch --tags' before building the documentation")
> +
> +
> +# Try and figure out what we are
> +tags = subprocess.run(["git", "tag", "--points-at", "HEAD"],
> + stdout=subprocess.PIPE, stderr=subprocess.PIPE,
> + universal_newlines=True).stdout
> +for t in tags.split():
> + if re.match(bbver_re, t):
> + ourversion = t
We can break here as we can only match one X.Y.Z tag for a given commit
hash.
> +
> +if ourversion:
> + # We're a tagged release
> + components = ourversion.split(".")
> + ourseries = f"{components[0]}.{components[1]}"
> +else:
> + # We're floating on a branch
> + branch = subprocess.run(["git", "branch", "--show-current"],
> + stdout=subprocess.PIPE, stderr=subprocess.PIPE,
> + universal_newlines=True).stdout.strip()
> +
> + if branch == "" or branch not in list(yocto_mapping.keys()) + ["master", "master-next"]:
> + # We're not on a known release branch so we have to guess. Compare the
> + # numbers of commits from each release branch and assume the smallest
> + # number of commits is the one we're based off
> + possible_branch = None
> + branch_count = 0
> + for b in itertools.chain(yocto_mapping.keys(), ["master"]):
> + result = subprocess.run(["git", "log", "--format=oneline", "HEAD..origin/" + b],
> + stdout=subprocess.PIPE, stderr=subprocess.PIPE,
> + universal_newlines=True)
> + if result.returncode == 0:
> + count = result.stdout.count('\n')
> + if not possible_branch or count < branch_count:
> + print("Branch %s has count %s" % (b, count))
> + possible_branch = b
> + branch_count = count
> + if possible_branch:
> + branch = possible_branch
> + else:
> + branch = "master"
> + print("Nearest release branch estimated to be %s" % branch)
> +
> + if branch == "master":
> + ourversion = "dev"
> + ourseries = devbranch
> + elif branch == "master-next":
> + ourversion = "next"
> + ourseries = devbranch
> + else:
> + ourversion = branch
> + head_commit = subprocess.run(["git", "rev-parse", "--short", "HEAD"],
> + stdout=subprocess.PIPE, stderr=subprocess.PIPE,
> + universal_newlines=True).stdout.strip()
> + branch_commit = subprocess.run(["git", "rev-parse", "--short", branch],
> + stdout=subprocess.PIPE, stderr=subprocess.PIPE,
> + universal_newlines=True).stdout.strip()
> + if head_commit != branch_commit:
> + ourversion += f" ({head_commit})"
> + ourseries = branch
> +
> +print("Version calculated to be %s" % ourversion)
> +print("Series calculated to be %s" % ourseries)
> +
> +replacements = {
> + "DOCCONF_VERSION": ourversion,
> +}
> +
> +if os.path.exists("bitbake.yaml.in"):
> + with open("bitbake.yaml.in", "r") as r, open("bitbake.yaml", "w") as w:
> + lines = r.readlines()
> + for line in lines:
> + data = line.split(":")
> + k = data[0].strip()
> + if k in replacements:
> + w.write("%s : \"%s\"\n" % (k, replacements[k]))
> + else:
> + w.write(line)
> +
> + print("bitbake.yaml generated from bitbake.yaml.in")
> +
> +with open("sphinx-static/switchers.js.in", "r") as r, \
> + open("sphinx-static/switchers.js", "w") as w:
> + lines = r.readlines()
> + for line in lines:
> + if "VERSIONS_PLACEHOLDER" in line:
> + if ourversion != "dev":
> + w.write(f" 'dev': 'Unstable (dev)',\n")
> + for series in activereleases:
> + w.write(f" '{series}': '{series} ({yocto_mapping[series]})',\n")
Why is this different from yp-docs? We don't handle showing the current
series (ourseries)/version (ourversion) if it's outdated anymore?
To answer Richard on the other thread, we use YAML because JSON doesn't
allow comments. Also, because we used to want multiline variables (see
https://yaml-multiline.info/) which aren't supported in JSON, but those
are gone since 8d993022c2ae ("docs: use literalinclude for system
requirements"). Not sure we can get rid of it for yp-docs as we only
override *some* variables in this file by set_versions.py so the
autobuilder won't replace poky.yaml.in, and the YAML is consumed by
sphinx/yocto-vars.py.
If we don't plan on having comments in this file *ever*, then the YAML
dependency isn't necessary.
Another option is INI and use configparser, c.f.
https://docs.python.org/3/library/configparser.html
It seems that INI supports the ':' as key-value delimiter as well as
multiline strings (but not the way we used it for YAML!), so it could be
a drop-in replacement. We could even simply write to the file with
configparser.write() (though that will drop the in-file comments).
Cheers,
Quentin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [docs] [PATCH v2] doc: fix the switchers menu
2026-02-04 15:01 ` [docs] " Quentin Schulz
@ 2026-02-05 11:34 ` Antonin Godard
2026-02-05 13:08 ` Quentin Schulz
0 siblings, 1 reply; 8+ messages in thread
From: Antonin Godard @ 2026-02-05 11:34 UTC (permalink / raw)
To: quentin.schulz, bitbake-devel; +Cc: Thomas Petazzoni, docs
Hi,
On Wed Feb 4, 2026 at 4:01 PM CET, Quentin Schulz via lists.yoctoproject.org wrote:
[...]
>> diff --git a/doc/set_versions.py b/doc/set_versions.py
>> new file mode 100755
>> index 00000000000..63fba2fe948
>> --- /dev/null
>> +++ b/doc/set_versions.py
>> @@ -0,0 +1,155 @@
>> +#!/usr/bin/env python3
>> +#
>> +# This is a minimal version of the set_versions.py from yocto-docs,
>> +# use to replace VERSIONS_PLACEHOLDER in switchers.js.in by a list defined below
>> +# with BITBAKE_ACTIVE_RELEASES in the environment.
>> +#
>
> Where?
A leftover from the previous version, thanks.
[...]
>> +with open("sphinx-static/switchers.js.in", "r") as r, \
>> + open("sphinx-static/switchers.js", "w") as w:
>> + lines = r.readlines()
>> + for line in lines:
>> + if "VERSIONS_PLACEHOLDER" in line:
>> + if ourversion != "dev":
>> + w.write(f" 'dev': 'Unstable (dev)',\n")
>> + for series in activereleases:
>> + w.write(f" '{series}': '{series} ({yocto_mapping[series]})',\n")
>
> Why is this different from yp-docs? We don't handle showing the current
> series (ourseries)/version (ourversion) if it's outdated anymore?
We do, but from switchers.js, where in build_version_select we push the current
version of the document last:
buf.push(
'<option value="' +
current_version +
'" selected="selected">' +
current_title +
"</option>",
);
So the version from our branch gets displayed.
(trust me, I've had a hard time locating and understanding how all of this
worked :))
However, you made me realize that due to our branch the abbrev hash, it would
always appear as outdated. I fixed that for v2.
> To answer Richard on the other thread, we use YAML because JSON doesn't
> allow comments. Also, because we used to want multiline variables (see
> https://yaml-multiline.info/) which aren't supported in JSON, but those
> are gone since 8d993022c2ae ("docs: use literalinclude for system
> requirements"). Not sure we can get rid of it for yp-docs as we only
> override *some* variables in this file by set_versions.py so the
> autobuilder won't replace poky.yaml.in, and the YAML is consumed by
> sphinx/yocto-vars.py.
>
> If we don't plan on having comments in this file *ever*, then the YAML
> dependency isn't necessary.
>
> Another option is INI and use configparser, c.f.
> https://docs.python.org/3/library/configparser.html
>
> It seems that INI supports the ':' as key-value delimiter as well as
> multiline strings (but not the way we used it for YAML!), so it could be
> a drop-in replacement. We could even simply write to the file with
> configparser.write() (though that will drop the in-file comments).
If we directly write the ini file with configparser.write(), maybe we can just
maintain the list of variable as Python instead, instead of a separate ".in"
file?
Antonin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [docs] [PATCH v2] doc: fix the switchers menu
2026-02-05 11:34 ` Antonin Godard
@ 2026-02-05 13:08 ` Quentin Schulz
2026-02-05 13:40 ` Antonin Godard
0 siblings, 1 reply; 8+ messages in thread
From: Quentin Schulz @ 2026-02-05 13:08 UTC (permalink / raw)
To: Antonin Godard, bitbake-devel; +Cc: Thomas Petazzoni, docs
Hi Antonin,
On 2/5/26 12:34 PM, Antonin Godard wrote:
> Hi,
>
> On Wed Feb 4, 2026 at 4:01 PM CET, Quentin Schulz via lists.yoctoproject.org wrote:
> [...]
>>> +with open("sphinx-static/switchers.js.in", "r") as r, \
>>> + open("sphinx-static/switchers.js", "w") as w:
>>> + lines = r.readlines()
>>> + for line in lines:
>>> + if "VERSIONS_PLACEHOLDER" in line:
>>> + if ourversion != "dev":
>>> + w.write(f" 'dev': 'Unstable (dev)',\n")
>>> + for series in activereleases:
>>> + w.write(f" '{series}': '{series} ({yocto_mapping[series]})',\n")
>>
>> Why is this different from yp-docs? We don't handle showing the current
>> series (ourseries)/version (ourversion) if it's outdated anymore?
>
> We do, but from switchers.js, where in build_version_select we push the current
> version of the document last:
>
> buf.push(
> '<option value="' +
> current_version +
> '" selected="selected">' +
> current_title +
> "</option>",
> );
>
> So the version from our branch gets displayed.
>
> (trust me, I've had a hard time locating and understanding how all of this
> worked :))
>
Yeah set_versions.py and the switchers aren't the nicest things to dig
into :/
Is the above mechanism something we could migrate yp-docs switcher to to
simplify it a bit?
> However, you made me realize that due to our branch the abbrev hash, it would
> always appear as outdated. I fixed that for v2.
>
>> To answer Richard on the other thread, we use YAML because JSON doesn't
>> allow comments. Also, because we used to want multiline variables (see
>> https://yaml-multiline.info/) which aren't supported in JSON, but those
>> are gone since 8d993022c2ae ("docs: use literalinclude for system
>> requirements"). Not sure we can get rid of it for yp-docs as we only
>> override *some* variables in this file by set_versions.py so the
>> autobuilder won't replace poky.yaml.in, and the YAML is consumed by
>> sphinx/yocto-vars.py.
>>
>> If we don't plan on having comments in this file *ever*, then the YAML
>> dependency isn't necessary.
>>
>> Another option is INI and use configparser, c.f.
>> https://docs.python.org/3/library/configparser.html
>>
>> It seems that INI supports the ':' as key-value delimiter as well as
>> multiline strings (but not the way we used it for YAML!), so it could be
>> a drop-in replacement. We could even simply write to the file with
>> configparser.write() (though that will drop the in-file comments).
>
> If we directly write the ini file with configparser.write(), maybe we can just
> maintain the list of variable as Python instead, instead of a separate ".in"
> file?
>
The benefit of having a .in file is that it's explicit what the user can
use in the docs (if we have yocto-vars.py! which we don't (yet?) in
BitBake).
What's the usecase for DOCCONF_VERSION BTW? We only use it for setting
the current version (always "dev") but we never override it? Either in
release branches, in the autobuilder, only from set_versions.py do we
read it and override it. But then it's nowhere to be found in the docs
either so we don't use. Do we actually need this for BitBake?
We could push this even further if we wanted to and have a bitbake.py
instead? In some internal Sphinx project, we provide a skeleton with
options to provide (Python) variables through another file we then include:
exec(open('variables.py').read())
is what we use. This would support f-strings (can easily reference a
variable from another one), multiline strings, etc. No need to parse
anything, it just needs to be valid Python variable assignment.
Cheers,
Quentin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [docs] [PATCH v2] doc: fix the switchers menu
2026-02-05 13:08 ` Quentin Schulz
@ 2026-02-05 13:40 ` Antonin Godard
2026-02-05 14:00 ` Quentin Schulz
0 siblings, 1 reply; 8+ messages in thread
From: Antonin Godard @ 2026-02-05 13:40 UTC (permalink / raw)
To: quentin.schulz, bitbake-devel; +Cc: Thomas Petazzoni, docs
Hi,
On Thu Feb 5, 2026 at 2:08 PM CET, Quentin Schulz via lists.yoctoproject.org wrote:
> Hi Antonin,
>
> On 2/5/26 12:34 PM, Antonin Godard wrote:
>> Hi,
>>
>> On Wed Feb 4, 2026 at 4:01 PM CET, Quentin Schulz via lists.yoctoproject.org wrote:
>> [...]
>>>> +with open("sphinx-static/switchers.js.in", "r") as r, \
>>>> + open("sphinx-static/switchers.js", "w") as w:
>>>> + lines = r.readlines()
>>>> + for line in lines:
>>>> + if "VERSIONS_PLACEHOLDER" in line:
>>>> + if ourversion != "dev":
>>>> + w.write(f" 'dev': 'Unstable (dev)',\n")
>>>> + for series in activereleases:
>>>> + w.write(f" '{series}': '{series} ({yocto_mapping[series]})',\n")
>>>
>>> Why is this different from yp-docs? We don't handle showing the current
>>> series (ourseries)/version (ourversion) if it's outdated anymore?
>>
>> We do, but from switchers.js, where in build_version_select we push the current
>> version of the document last:
>>
>> buf.push(
>> '<option value="' +
>> current_version +
>> '" selected="selected">' +
>> current_title +
>> "</option>",
>> );
>>
>> So the version from our branch gets displayed.
>>
>> (trust me, I've had a hard time locating and understanding how all of this
>> worked :))
>>
>
> Yeah set_versions.py and the switchers aren't the nicest things to dig
> into :/
>
> Is the above mechanism something we could migrate yp-docs switcher to to
> simplify it a bit?
Yes, I think I'd like to port these simplifications to yocto-docs soon after,
while memory is still fresh
>> However, you made me realize that due to our branch the abbrev hash, it would
>> always appear as outdated. I fixed that for v2.
>>
>>> To answer Richard on the other thread, we use YAML because JSON doesn't
>>> allow comments. Also, because we used to want multiline variables (see
>>> https://yaml-multiline.info/) which aren't supported in JSON, but those
>>> are gone since 8d993022c2ae ("docs: use literalinclude for system
>>> requirements"). Not sure we can get rid of it for yp-docs as we only
>>> override *some* variables in this file by set_versions.py so the
>>> autobuilder won't replace poky.yaml.in, and the YAML is consumed by
>>> sphinx/yocto-vars.py.
>>>
>>> If we don't plan on having comments in this file *ever*, then the YAML
>>> dependency isn't necessary.
>>>
>>> Another option is INI and use configparser, c.f.
>>> https://docs.python.org/3/library/configparser.html
>>>
>>> It seems that INI supports the ':' as key-value delimiter as well as
>>> multiline strings (but not the way we used it for YAML!), so it could be
>>> a drop-in replacement. We could even simply write to the file with
>>> configparser.write() (though that will drop the in-file comments).
>>
>> If we directly write the ini file with configparser.write(), maybe we can just
>> maintain the list of variable as Python instead, instead of a separate ".in"
>> file?
>>
>
> The benefit of having a .in file is that it's explicit what the user can
> use in the docs (if we have yocto-vars.py! which we don't (yet?) in
> BitBake).
>
> What's the usecase for DOCCONF_VERSION BTW? We only use it for setting
> the current version (always "dev") but we never override it? Either in
> release branches, in the autobuilder, only from set_versions.py do we
> read it and override it. But then it's nowhere to be found in the docs
> either so we don't use. Do we actually need this for BitBake?
We use it in doc/conf.py:
current_version = 'dev'
with open("bitbake.yaml") as data:
buff = data.read()
subst_vars = yaml.safe_load(buff)
current_version = subst_vars["DOCCONF_VERSION"]
So basically we just need a way to pass this information from set_versions.py to
the sphinx-build command.
> We could push this even further if we wanted to and have a bitbake.py
> instead? In some internal Sphinx project, we provide a skeleton with
> options to provide (Python) variables through another file we then include:
>
> exec(open('variables.py').read())
>
> is what we use. This would support f-strings (can easily reference a
> variable from another one), multiline strings, etc. No need to parse
> anything, it just needs to be valid Python variable assignment.
So basically, you'd write a variables.py file from set_versions.py and read it
from conf.py?
I'm starting to wonder if it just wouldn't be better do move all of this logic
into doc/conf.py, actually.
Thanks,
Antonin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [docs] [PATCH v2] doc: fix the switchers menu
2026-02-05 13:40 ` Antonin Godard
@ 2026-02-05 14:00 ` Quentin Schulz
0 siblings, 0 replies; 8+ messages in thread
From: Quentin Schulz @ 2026-02-05 14:00 UTC (permalink / raw)
To: Antonin Godard, bitbake-devel; +Cc: Thomas Petazzoni, docs
Hi Antonin,
On 2/5/26 2:40 PM, Antonin Godard wrote:
> Hi,
>
> On Thu Feb 5, 2026 at 2:08 PM CET, Quentin Schulz via lists.yoctoproject.org wrote:
>> Hi Antonin,
>>
>> On 2/5/26 12:34 PM, Antonin Godard wrote:
>>> Hi,
>>>
>>> On Wed Feb 4, 2026 at 4:01 PM CET, Quentin Schulz via lists.yoctoproject.org wrote:
>>> [...]
>>>>> +with open("sphinx-static/switchers.js.in", "r") as r, \
>>>>> + open("sphinx-static/switchers.js", "w") as w:
>>>>> + lines = r.readlines()
>>>>> + for line in lines:
>>>>> + if "VERSIONS_PLACEHOLDER" in line:
>>>>> + if ourversion != "dev":
>>>>> + w.write(f" 'dev': 'Unstable (dev)',\n")
>>>>> + for series in activereleases:
>>>>> + w.write(f" '{series}': '{series} ({yocto_mapping[series]})',\n")
>>>>
>>>> Why is this different from yp-docs? We don't handle showing the current
>>>> series (ourseries)/version (ourversion) if it's outdated anymore?
>>>
>>> We do, but from switchers.js, where in build_version_select we push the current
>>> version of the document last:
>>>
>>> buf.push(
>>> '<option value="' +
>>> current_version +
>>> '" selected="selected">' +
>>> current_title +
>>> "</option>",
>>> );
>>>
>>> So the version from our branch gets displayed.
>>>
>>> (trust me, I've had a hard time locating and understanding how all of this
>>> worked :))
>>>
>>
>> Yeah set_versions.py and the switchers aren't the nicest things to dig
>> into :/
>>
>> Is the above mechanism something we could migrate yp-docs switcher to to
>> simplify it a bit?
>
> Yes, I think I'd like to port these simplifications to yocto-docs soon after,
> while memory is still fresh
>
>>> However, you made me realize that due to our branch the abbrev hash, it would
>>> always appear as outdated. I fixed that for v2.
>>>
>>>> To answer Richard on the other thread, we use YAML because JSON doesn't
>>>> allow comments. Also, because we used to want multiline variables (see
>>>> https://yaml-multiline.info/) which aren't supported in JSON, but those
>>>> are gone since 8d993022c2ae ("docs: use literalinclude for system
>>>> requirements"). Not sure we can get rid of it for yp-docs as we only
>>>> override *some* variables in this file by set_versions.py so the
>>>> autobuilder won't replace poky.yaml.in, and the YAML is consumed by
>>>> sphinx/yocto-vars.py.
>>>>
>>>> If we don't plan on having comments in this file *ever*, then the YAML
>>>> dependency isn't necessary.
>>>>
>>>> Another option is INI and use configparser, c.f.
>>>> https://docs.python.org/3/library/configparser.html
>>>>
>>>> It seems that INI supports the ':' as key-value delimiter as well as
>>>> multiline strings (but not the way we used it for YAML!), so it could be
>>>> a drop-in replacement. We could even simply write to the file with
>>>> configparser.write() (though that will drop the in-file comments).
>>>
>>> If we directly write the ini file with configparser.write(), maybe we can just
>>> maintain the list of variable as Python instead, instead of a separate ".in"
>>> file?
>>>
>>
>> The benefit of having a .in file is that it's explicit what the user can
>> use in the docs (if we have yocto-vars.py! which we don't (yet?) in
>> BitBake).
>>
>> What's the usecase for DOCCONF_VERSION BTW? We only use it for setting
>> the current version (always "dev") but we never override it? Either in
>> release branches, in the autobuilder, only from set_versions.py do we
>> read it and override it. But then it's nowhere to be found in the docs
>> either so we don't use. Do we actually need this for BitBake?
>
> We use it in doc/conf.py:
>
> current_version = 'dev'
>
> with open("bitbake.yaml") as data:
> buff = data.read()
> subst_vars = yaml.safe_load(buff)
> current_version = subst_vars["DOCCONF_VERSION"]
>
> So basically we just need a way to pass this information from set_versions.py to
> the sphinx-build command.
>
DOCCONF_VERSION is always "dev". current_version defaults to "dev" too.
So what is this *actually* used for?
>> We could push this even further if we wanted to and have a bitbake.py
>> instead? In some internal Sphinx project, we provide a skeleton with
>> options to provide (Python) variables through another file we then include:
>>
>> exec(open('variables.py').read())
>>
>> is what we use. This would support f-strings (can easily reference a
>> variable from another one), multiline strings, etc. No need to parse
>> anything, it just needs to be valid Python variable assignment.
>
> So basically, you'd write a variables.py file from set_versions.py and read it
> from conf.py?
>
> I'm starting to wonder if it just wouldn't be better do move all of this logic
> into doc/conf.py, actually.
>
Is DOCCONF_VERSION supposed to be used from the docs? Is DOCCONF_VERSION
supposed to be set externally such that it makes it to conf.py which
does something with it? If no is the answer to both, then there's no
reason for this mechanism to exist in the first place.
Cheers,
Quentin
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-02-05 14:01 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-04 10:03 [PATCH v2] doc: fix the switchers menu Antonin Godard
2026-02-04 13:32 ` [bitbake-devel] " Richard Purdie
2026-02-04 13:41 ` Antonin Godard
2026-02-04 15:01 ` [docs] " Quentin Schulz
2026-02-05 11:34 ` Antonin Godard
2026-02-05 13:08 ` Quentin Schulz
2026-02-05 13:40 ` Antonin Godard
2026-02-05 14:00 ` Quentin Schulz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox