mirror of
https://github.com/ROCm/ROCm.git
synced 2026-01-06 21:33:57 -05:00
142 lines
4.9 KiB
Python
142 lines
4.9 KiB
Python
from docutils import nodes
|
|
from docutils.parsers.rst import Directive
|
|
from docutils.statemachine import ViewList
|
|
from sphinx.util import logging
|
|
from sphinx.util.nodes import nested_parse_with_titles
|
|
import requests
|
|
import re
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class BranchAwareRemoteContent(Directive):
|
|
"""
|
|
Directive that downloads and includes content from other repositories,
|
|
matching the branch/tag of the current documentation build.
|
|
|
|
Usage:
|
|
.. remote-content::
|
|
:repo: owner/repository
|
|
:path: path/to/file.rst
|
|
:default_branch: docs/develop # Branch to use when not on a release
|
|
:tag_prefix: Docs/ # Optional
|
|
"""
|
|
|
|
required_arguments = 0
|
|
optional_arguments = 0
|
|
final_argument_whitespace = True
|
|
has_content = False
|
|
option_spec = {
|
|
'repo': str,
|
|
'path': str,
|
|
'default_branch': str, # Branch to use when not on a release tag
|
|
'start_line': int, # Include the file from a specific line
|
|
'tag_prefix': str, # Prefix for release tags (e.g., 'Docs/')
|
|
}
|
|
|
|
def get_current_version(self):
|
|
"""Get current version/branch being built"""
|
|
env = self.state.document.settings.env
|
|
html_context = env.config.html_context
|
|
|
|
# Check if building from a tag
|
|
if "official_branch" in html_context:
|
|
if html_context["official_branch"] == 0:
|
|
if "version" in html_context:
|
|
# Remove any 'v' prefix
|
|
version = html_context["version"]
|
|
if re.match(r'^\d+\.\d+\.\d+$', version):
|
|
return version
|
|
|
|
# Not a version tag, so we'll use the default branch
|
|
return None
|
|
|
|
def get_target_ref(self):
|
|
"""Get target reference for the remote repository"""
|
|
current_version = self.get_current_version()
|
|
|
|
# If it's a version number, use tag prefix and version
|
|
if current_version:
|
|
tag_prefix = self.options.get('tag_prefix', '')
|
|
return f'{tag_prefix}{current_version}'
|
|
|
|
# For any other case, use the specified default branch
|
|
if 'default_branch' not in self.options:
|
|
logger.warning('No default_branch specified and not building from a version tag')
|
|
return None
|
|
|
|
return self.options['default_branch']
|
|
|
|
def construct_raw_url(self, repo, path, ref):
|
|
"""Construct the raw.githubusercontent.com URL"""
|
|
return f'https://raw.githubusercontent.com/{repo}/{ref}/{path}'
|
|
|
|
def fetch_and_parse_content(self, url, source_path):
|
|
"""Fetch content and parse it as RST"""
|
|
response = requests.get(url)
|
|
response.raise_for_status()
|
|
content = response.text
|
|
|
|
start_line = self.options.get('start_line', 0)
|
|
|
|
# Create ViewList for parsing
|
|
line_count = 0
|
|
content_list = ViewList()
|
|
for line_no, line in enumerate(content.splitlines()):
|
|
if line_count >= start_line:
|
|
content_list.append(line, source_path, line_no)
|
|
line_count+=1
|
|
|
|
# Create a section node and parse content
|
|
node = nodes.section()
|
|
nested_parse_with_titles(self.state, content_list, node)
|
|
|
|
return node.children
|
|
|
|
def run(self):
|
|
if 'repo' not in self.options or 'path' not in self.options:
|
|
logger.warning('Both repo and path options are required')
|
|
return []
|
|
|
|
target_ref = self.get_target_ref()
|
|
if not target_ref:
|
|
return []
|
|
|
|
raw_url = self.construct_raw_url(
|
|
self.options['repo'],
|
|
self.options['path'],
|
|
target_ref
|
|
)
|
|
|
|
try:
|
|
logger.info(f'Attempting to fetch content from {raw_url}')
|
|
return self.fetch_and_parse_content(raw_url, self.options['path'])
|
|
except requests.exceptions.RequestException as e:
|
|
logger.warning(f'Failed to fetch content from {raw_url}: {str(e)}')
|
|
|
|
# If we failed on a tag, try falling back to default_branch
|
|
if re.match(r'^\d+\.\d+\.\d+$', target_ref) or target_ref.startswith('Docs/'):
|
|
if 'default_branch' in self.options:
|
|
try:
|
|
fallback_ref = self.options['default_branch']
|
|
logger.info(f'Attempting fallback to {fallback_ref}...')
|
|
|
|
fallback_url = self.construct_raw_url(
|
|
self.options['repo'],
|
|
self.options['path'],
|
|
fallback_ref
|
|
)
|
|
|
|
return self.fetch_and_parse_content(fallback_url, self.options['path'])
|
|
except requests.exceptions.RequestException as e2:
|
|
logger.warning(f'Fallback also failed: {str(e2)}')
|
|
|
|
return []
|
|
|
|
def setup(app):
|
|
app.add_directive('remote-content', BranchAwareRemoteContent)
|
|
|
|
return {
|
|
'parallel_read_safe': True,
|
|
'parallel_write_safe': True,
|
|
}
|