sphinx.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. # -*- coding: utf-8 -*-
  2. import json
  3. import pathlib
  4. import collections
  5. import importlib.abc
  6. import logging
  7. import os
  8. import posixpath
  9. logger = logging.getLogger(__name__)
  10. DEFAULT_TAG_WHITELIST = r'^.*$'
  11. DEFAULT_BRANCH_WHITELIST = r'^.*$'
  12. DEFAULT_REMOTE_WHITELIST = None
  13. DEFAULT_OUTPUTDIR_FORMAT = r'{version.version}/{language}'
  14. Version = collections.namedtuple('Version', ['name', 'url', 'version'])
  15. class VersionInfo:
  16. def __init__(self, app, context, metadata):
  17. self.app = app
  18. self.context = context
  19. self.metadata = metadata
  20. @property
  21. def tags(self):
  22. return [
  23. Version(v["name"], self.vpathto(v["name"]), v["version"])
  24. for v in self.metadata.values() if v["source"] == "tags"
  25. ]
  26. @property
  27. def branches(self):
  28. return [
  29. Version(v["name"], self.vpathto(v["name"]), v["version"])
  30. for v in self.metadata.values() if v["source"] != "tags"
  31. ]
  32. def __iter__(self):
  33. for item in self.tags:
  34. yield item
  35. for item in self.branches:
  36. yield item
  37. def vhasdoc(self, other_version_name):
  38. if self.context["current_version"] == other_version_name:
  39. return True
  40. other_version = self.metadata[other_version_name]
  41. return self.context["pagename"] in other_version["docnames"]
  42. def vpathto(self, other_version_name):
  43. if self.context["current_version"] == other_version_name:
  44. return '{}.html'.format(
  45. posixpath.split(self.context["pagename"])[-1])
  46. # Find output root
  47. current_version = self.metadata[self.context["current_version"]]
  48. relpath = pathlib.PurePath(current_version["outputdir"])
  49. outputroot = os.path.join(
  50. *('..' for x in relpath.joinpath(self.context["pagename"]).parent.parts)
  51. )
  52. # Find output dir of other version
  53. other_version = self.metadata[other_version_name]
  54. outputdir = posixpath.join(outputroot, other_version["outputdir"])
  55. if not self.vhasdoc(other_version_name):
  56. return posixpath.join(outputdir, 'index.html')
  57. return posixpath.join(outputdir, '{}.html'.format(self.context["pagename"]))
  58. def parse_conf(config):
  59. module = {}
  60. code = importlib.abc.InspectLoader.source_to_code(config)
  61. exec(code, module)
  62. return module
  63. def format_outputdir(fmt, versionref, language):
  64. return fmt.format(version=versionref, language=language)
  65. def html_page_context(app, pagename, templatename, context, doctree):
  66. context["latest_version"] = app.config.smv_latest_version
  67. context["current_version"] = app.config.smv_current_version
  68. context["html_theme"] = app.config.html_theme
  69. versioninfo = VersionInfo(app, context, app.config.smv_metadata)
  70. context["versions"] = versioninfo
  71. context["vhasdoc"] = versioninfo.vhasdoc
  72. context["vpathto"] = versioninfo.vpathto
  73. def config_inited(app, config):
  74. """Update the Sphinx builder.
  75. :param sphinx.application.Sphinx app: Sphinx application object.
  76. """
  77. if not config.smv_metadata:
  78. if not config.smv_metadata_path:
  79. return
  80. with open(config.smv_metadata_path, mode="r") as f:
  81. metadata = json.load(f)
  82. config.smv_metadata = metadata
  83. if not config.smv_current_version:
  84. return
  85. app.connect("html-page-context", html_page_context)
  86. # Restore config values
  87. conf_path = os.path.join(app.srcdir, "conf.py")
  88. with open(conf_path, mode="r") as f:
  89. conf = parse_conf(f.read())
  90. config.version = conf['version']
  91. config.release = conf['release']
  92. def setup(app):
  93. app.add_config_value("smv_metadata", {}, "html")
  94. app.add_config_value("smv_metadata_path", "", "html")
  95. app.add_config_value("smv_current_version", "", "html")
  96. app.add_config_value("smv_latest_version", "master", "html")
  97. app.add_config_value("smv_tag_whitelist", DEFAULT_TAG_WHITELIST, "html")
  98. app.add_config_value("smv_branch_whitelist", DEFAULT_BRANCH_WHITELIST, "html")
  99. app.add_config_value("smv_remote_whitelist", DEFAULT_REMOTE_WHITELIST, "html")
  100. app.add_config_value("smv_outputdir_format", DEFAULT_OUTPUTDIR_FORMAT, "html")
  101. app.connect("config-inited", config_inited)
  102. return {
  103. "version": "0.1",
  104. "parallel_read_safe": True,
  105. "parallel_write_safe": True,
  106. }