main.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import json
  4. import pathlib
  5. import subprocess
  6. import sys
  7. import tempfile
  8. from sphinx.cmd import build as sphinx_build
  9. from sphinx import project as sphinx_project
  10. from . import sphinx
  11. from . import git
  12. def main(argv=None):
  13. if not argv:
  14. argv = sys.argv[1:]
  15. parser = sphinx_build.get_parser()
  16. args = parser.parse_args(argv)
  17. # Find the indices
  18. srcdir_index = None
  19. outdir_index = None
  20. for i, value in enumerate(argv):
  21. if value == args.sourcedir:
  22. argv[i] = '{{{SOURCEDIR}}}'
  23. test_args = parser.parse_args(argv)
  24. if test_args.sourcedir == argv[i]:
  25. srcdir_index = i
  26. argv[i] = args.sourcedir
  27. if value == args.outputdir:
  28. argv[i] = '{{{OUTPUTDIR}}}'
  29. test_args = parser.parse_args(argv)
  30. if test_args.outputdir == argv[i]:
  31. outdir_index = i
  32. argv[i] = args.outputdir
  33. if srcdir_index is None:
  34. raise ValueError("Failed to find srcdir index")
  35. if outdir_index is None:
  36. raise ValueError("Failed to find outdir index")
  37. # Parse config
  38. confpath = os.path.join(args.confdir, 'conf.py')
  39. with open(confpath, mode='r') as f:
  40. config = sphinx.parse_conf(f.read())
  41. for d in args.define:
  42. key, _, value = d.partition('=')
  43. config[key] = value
  44. tag_whitelist = config.get('smv_tag_whitelist', sphinx.DEFAULT_TAG_WHITELIST)
  45. branch_whitelist = config.get('smv_branch_whitelist', sphinx.DEFAULT_BRANCH_WHITELIST)
  46. remote_whitelist = config.get('smv_remote_whitelist', sphinx.DEFAULT_REMOTE_WHITELIST)
  47. outputdir_format = config.get('smv_outputdir_format', sphinx.DEFAULT_OUTPUTDIR_FORMAT)
  48. gitroot = pathlib.Path('.').resolve()
  49. versions = git.find_versions(str(gitroot), 'source/conf.py', tag_whitelist, branch_whitelist, remote_whitelist)
  50. remotes = dict(git.get_remotes(str(gitroot)))
  51. with tempfile.TemporaryDirectory() as tmp:
  52. # Generate Metadata
  53. metadata = {}
  54. outputdirs = set()
  55. sourcedir = os.path.relpath(args.sourcedir, str(gitroot))
  56. for versionref in versions:
  57. # Ensure that there are not duplicate output dirs
  58. outputdir = sphinx.format_outputdir(
  59. outputdir_format, versionref, language=config["language"])
  60. if outputdir in outputdirs:
  61. print("outputdir '%s' of version %r conflicts with other versions!"
  62. % (outputdir, versionref))
  63. continue
  64. outputdirs.add(outputdir)
  65. # Clone Git repo
  66. repopath = os.path.join(tmp, str(hash(versionref)))
  67. srcdir = os.path.join(repopath, sourcedir)
  68. if versionref.source.startswith('remotes/'):
  69. repo_url = remotes[versionref.source.partition("/")[2]]
  70. else:
  71. repo_url = gitroot.as_uri()
  72. try:
  73. git.shallow_clone(repo_url, repopath, versionref.name)
  74. except subprocess.CalledProcessError:
  75. outputdirs.remove(outputdir)
  76. continue
  77. # Get List of files
  78. source_suffixes = config.get("source_suffix", "")
  79. if isinstance(source_suffixes, str):
  80. source_suffixes = [source_suffixes]
  81. project = sphinx_project.Project(srcdir, source_suffixes)
  82. metadata[versionref.name] = {
  83. "name": versionref.name,
  84. "source": versionref.source,
  85. "sourcedir": srcdir,
  86. "outputdir": outputdir,
  87. "docnames": list(project.discover())
  88. }
  89. metadata_path = os.path.abspath(os.path.join(tmp, "versions.json"))
  90. with open(metadata_path, mode='w') as fp:
  91. json.dump(metadata, fp, indent=2)
  92. # Run Sphinx
  93. argv.extend(["-D", "smv_metadata_path={}".format(metadata_path)])
  94. for version_name, data in metadata.items():
  95. current_argv = argv.copy()
  96. current_argv.extend([
  97. "-D", "smv_current_version={}".format(version_name),
  98. ])
  99. outdir = os.path.join(args.outputdir, data["outputdir"])
  100. current_argv[srcdir_index] = data["sourcedir"]
  101. current_argv[outdir_index] = outdir
  102. os.makedirs(outdir, exist_ok=True)
  103. status = sphinx_build.build_main(current_argv)
  104. if status not in (0, None):
  105. break