diff --git a/build.bfg b/build.bfg index 40ab15f4..9b66cdaf 100644 --- a/build.bfg +++ b/build.bfg @@ -1,7 +1,9 @@ # -*- python -*- bfg9000_required_version('>=0.5.0') -project('mettle', '0.1-dev', intermediate_dirs=False) + +mettle_version = '0.1-dev' +project('mettle', mettle_version, intermediate_dirs=False) global_options([opts.std(argv.std)], lang='c++') @@ -91,9 +93,9 @@ alias('examples', [ # XXX: Don't cd once MkDocs supports building from other dirs. cd = ['cd', directory('.')] -command('doc', cmds=[cd, ['mkdocs', 'build', '--clean']]) -command('doc-serve', cmds=[cd, ['mkdocs', 'serve', '--dev-addr=0.0.0.0:8000']]) -command('doc-deploy', cmds=[cd, ['mkdocs', 'gh-deploy', '--clean']]) +doc_deploy = source_file('scripts/doc_deploy.py') +command('doc-serve', cmds=[cd, ['mike', 'serve', '--dev-addr=0.0.0.0:8000']]) +command('doc-deploy', cmds=[cd, [doc_deploy, mettle_version]]) # Extra files to be packaged in the source dist. find_files('src', '*.[ch]pp', filter=filter_by_platform, flat=True) diff --git a/doc/css/version-select.css b/doc/css/version-select.css new file mode 100644 index 00000000..7943fa7d --- /dev/null +++ b/doc/css/version-select.css @@ -0,0 +1,12 @@ +#version-selector { + float: left; + display: flex; + align-items: center; + margin: 0 10px; +} + +#version-selector > select { + width: auto; + height: auto; + padding: 1px; +} diff --git a/doc/js/version-select.js b/doc/js/version-select.js new file mode 100644 index 00000000..fa58c56f --- /dev/null +++ b/doc/js/version-select.js @@ -0,0 +1,71 @@ +window.addEventListener("DOMContentLoaded", function() { + function normalizePath(path) { + var normalized = []; + path.split("/").forEach(function(bit, i) { + if (bit === "." || (bit === "" && i !== 0)) { + return; + } else if (bit === "..") { + if (normalized.length === 1 && normalized[0] === "") { + // We must be trying to .. past the root! + throw new Error("invalid path"); + } else if (normalized.length === 0 || + normalized[normalized.length - 1] === "..") { + normalized.push(".."); + } else { + normalized.pop(); + } + } else { + normalized.push(bit); + } + }); + return normalized.join("/"); + } + + // `base_url` comes from the base.html template for this theme. + var REL_BASE_URL = base_url; + var ABS_BASE_URL = normalizePath(window.location.pathname + "/" + + REL_BASE_URL); + var CURRENT_VERSION = ABS_BASE_URL.split("/").pop(); + + function makeSelect(options, selected) { + var select = document.createElement("select"); + select.classList.add("form-control"); + + options.forEach(function(i) { + var option = new Option(i.text, i.value, undefined, + i.value === selected); + select.add(option); + }); + + return select; + } + + var xhr = new XMLHttpRequest(); + xhr.open("GET", REL_BASE_URL + "/../versions.json"); + xhr.onload = function() { + var versions = JSON.parse(this.responseText); + + var realVersion = versions.find(function(i) { + return i.version === CURRENT_VERSION || + i.aliases.includes(CURRENT_VERSION); + }).version; + + var select = makeSelect(versions.map(function(i) { + return {text: i.title, value: i.version}; + }), realVersion); + select.addEventListener("change", function(event) { + window.location.href = REL_BASE_URL + "/../" + this.value; + }); + + var container = document.createElement("div"); + container.id = "version-selector"; + container.appendChild(select); + + var title = document.querySelector("div.navbar-header"); + var height = window.getComputedStyle(title).getPropertyValue("height"); + container.style.height = height; + + title.appendChild(container); + }; + xhr.send(); +}); diff --git a/mkdocs.yml b/mkdocs.yml index 18795db3..33ea01ad 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,6 +7,9 @@ copyright: Copyright © 2014-2019 Jim Porter theme: yeti extra_css: - css/extra.css + - css/version-select.css +extra_javascript: + - js/version-select.js markdown_extensions: - admonition diff --git a/scripts/doc_deploy.py b/scripts/doc_deploy.py new file mode 100644 index 00000000..1674b00d --- /dev/null +++ b/scripts/doc_deploy.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +import argparse +import json +import re +import subprocess +from packaging.version import Version + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="Deploy mettle's documentation to the gh-pages branch" + ) + parser.add_argument('version', help='the current mettle version number') + + args = parser.parse_args() + + v = Version(args.version) + alias = 'dev' if v.is_devrelease else 'latest' + title = '{} ({})'.format(v.base_version, alias) + short_version = '{}.{}'.format(*v.release[:2]) + + info = json.loads(subprocess.check_output( + ['mike', 'list', '-j', alias], + universal_newlines=True + )) + if info['version'] != short_version: + t = re.sub(r' \({}\)$'.format(re.escape(alias)), '', + info['title']) + subprocess.check_call(['mike', 'retitle', info['version'], t]) + + subprocess.check_call(['mike', 'deploy', '-ut', title, + short_version, alias])