Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop creating a conf.py automatically and doing magic around README handling #5609

Merged
merged 18 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 40 additions & 54 deletions readthedocs/doc_builder/backends/mkdocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def __init__(self, *args, **kwargs):
if self.project.has_feature(Feature.MKDOCS_THEME_RTD):
self.DEFAULT_THEME_NAME = 'readthedocs'
log.warning(
'Project using readthedocs theme as default for MkDocs.',
"Project using readthedocs theme as default for MkDocs.",
project_slug=self.project.slug,
)
else:
Expand All @@ -76,14 +76,14 @@ def get_final_doctype(self):
self.yaml_file, "r", allow_symlinks=True, base_path=self.project_path
) as fh:
config = yaml_load_safely(fh)
use_directory_urls = config.get('use_directory_urls', True)
use_directory_urls = config.get("use_directory_urls", True)
return MKDOCS if use_directory_urls else MKDOCS_HTML

def get_yaml_config(self):
"""Find the ``mkdocs.yml`` file in the project root."""
mkdocs_path = self.config.mkdocs.configuration
if not mkdocs_path:
mkdocs_path = 'mkdocs.yml'
mkdocs_path = "mkdocs.yml"
return os.path.join(
self.project_path,
mkdocs_path,
Expand All @@ -108,25 +108,13 @@ def load_yaml_config(self):
config = yaml_load_safely(result)

if not config:
raise MkDocsYAMLParseError(
MkDocsYAMLParseError.EMPTY_CONFIG
)
raise MkDocsYAMLParseError(MkDocsYAMLParseError.EMPTY_CONFIG)
if not isinstance(config, dict):
raise MkDocsYAMLParseError(
MkDocsYAMLParseError.CONFIG_NOT_DICT
)
raise MkDocsYAMLParseError(MkDocsYAMLParseError.CONFIG_NOT_DICT)
return config

except IOError:
log.info(
'Creating default MkDocs config file for project.',
project_slug=self.project.slug,
version_slug=self.version.slug,
)
return {
'site_name': self.version.project.name,
'docs_dir': self.docs_dir(),
}
raise MkDocsYAMLParseError(MkDocsYAMLParseError.NOT_FOUND)
except yaml.YAMLError as exc:
note = ''
if hasattr(exc, 'problem_mark'):
Expand All @@ -150,7 +138,7 @@ def append_conf(self):
user_config = self.load_yaml_config()

# Handle custom docs dirs
docs_dir = user_config.get('docs_dir', 'docs')
docs_dir = user_config.get("docs_dir", "docs")
if not isinstance(docs_dir, (type(None), str)):
raise MkDocsYAMLParseError(
MkDocsYAMLParseError.INVALID_DOCS_DIR_CONFIG,
Expand All @@ -167,14 +155,14 @@ def append_conf(self):

# Set mkdocs config values.
extra_assets = {
'extra_javascript': [
'readthedocs-data.js',
f'{static_url}core/js/readthedocs-doc-embed.js',
f'{static_url}javascript/readthedocs-analytics.js',
"extra_javascript": [
"readthedocs-data.js",
f"{static_url}core/js/readthedocs-doc-embed.js",
f"{static_url}javascript/readthedocs-analytics.js",
],
'extra_css': [
f'{static_url}css/badge_only.css',
f'{static_url}css/readthedocs-doc-embed.css',
"extra_css": [
f"{static_url}css/badge_only.css",
f"{static_url}css/readthedocs-doc-embed.css",
],
}

Expand All @@ -189,11 +177,7 @@ def append_conf(self):
),
)
# Add the static file only if isn't already in the list.
value.extend([
extra
for extra in extras
if extra not in value
])
value.extend([extra for extra in extras if extra not in value])
user_config[config] = value

# The docs path is relative to the location
Expand Down Expand Up @@ -257,38 +241,39 @@ def generate_rtd_data(self, docs_dir, mkdocs_config):
self.version.project.vcs_repo(
version=self.version.slug,
environment=self.build_env,
)
.commit,
).commit,
)

# Will be available in the JavaScript as READTHEDOCS_DATA.
readthedocs_data = {
'project': self.version.project.slug,
'version': self.version.slug,
'language': self.version.project.language,
'programming_language': self.version.project.programming_language,
'page': None,
'theme': self.get_theme_name(mkdocs_config),
'builder': 'mkdocs',
'docroot': docs_dir,
'source_suffix': '.md',
'api_host': settings.PUBLIC_API_URL,
'ad_free': not self.project.show_advertising,
'commit': commit,
'global_analytics_code': (
None if self.project.analytics_disabled else settings.GLOBAL_ANALYTICS_CODE
"project": self.version.project.slug,
"version": self.version.slug,
"language": self.version.project.language,
"programming_language": self.version.project.programming_language,
"page": None,
"theme": self.get_theme_name(mkdocs_config),
"builder": "mkdocs",
"docroot": docs_dir,
"source_suffix": ".md",
"api_host": settings.PUBLIC_API_URL,
"ad_free": not self.project.show_advertising,
"commit": commit,
"global_analytics_code": (
None
if self.project.analytics_disabled
else settings.GLOBAL_ANALYTICS_CODE
),
"user_analytics_code": analytics_code,
"proxied_static_path": self.project.proxied_static_path,
"proxied_api_host": self.project.proxied_api_host,
}

data_ctx = {
'readthedocs_data': readthedocs_data,
'current_version': readthedocs_data['version'],
'slug': readthedocs_data['project'],
'html_theme': readthedocs_data['theme'],
'pagename': None,
"readthedocs_data": readthedocs_data,
"current_version": readthedocs_data["version"],
"slug": readthedocs_data["project"],
"html_theme": readthedocs_data["theme"],
"pagename": None,
}
tmpl = template_loader.get_template('doc_builder/data.js.tmpl')
return tmpl.render(data_ctx)
Expand Down Expand Up @@ -342,7 +327,6 @@ def get_theme_name(self, mkdocs_config):


class MkdocsHTML(BaseMkdocs):

builder = "build"
build_dir = "_readthedocs/html"

Expand Down Expand Up @@ -391,7 +375,9 @@ def represent_name(self, data):
return self.represent_scalar("tag:yaml.org,2002:python/name:" + data.value, "")


SafeLoader.add_multi_constructor("tag:yaml.org,2002:python/name:", SafeLoader.construct_python_name)
SafeLoader.add_multi_constructor(
"tag:yaml.org,2002:python/name:", SafeLoader.construct_python_name
)
SafeLoader.add_constructor(None, SafeLoader.ignore_unknown)
SafeDumper.add_representer(ProxyPythonName, SafeDumper.represent_name)

Expand Down
105 changes: 37 additions & 68 deletions readthedocs/doc_builder/backends/sphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import structlog
from django.conf import settings
from django.template import loader as template_loader
from django.template.loader import render_to_string
from django.urls import reverse
from requests.exceptions import ConnectionError

Expand All @@ -24,7 +23,6 @@
from readthedocs.projects.exceptions import ProjectConfigurationError, UserFileNotFound
from readthedocs.projects.models import Feature
from readthedocs.projects.templatetags.projects_tags import sort_version_aware
from readthedocs.projects.utils import safe_write

from ..base import BaseBuilder
from ..constants import PDF_RE
Expand Down Expand Up @@ -113,24 +111,6 @@ def __init__(self, *args, **kwargs):
# because Read the Docs will automatically create one for it.
pass

def _write_config(self, master_doc='index'):
"""Create ``conf.py`` if it doesn't exist."""
log.info(
'Creating default Sphinx config file for project.',
project_slug=self.project.slug,
version_slug=self.version.slug,
)
docs_dir = self.docs_dir()
conf_template = render_to_string(
'sphinx/conf.py.conf',
{
'project': self.project,
'version': self.version,
'master_doc': master_doc,
},
)
conf_file = os.path.join(docs_dir, 'conf.py')
safe_write(conf_file, conf_template)
stsewd marked this conversation as resolved.
Show resolved Hide resolved

def get_config_params(self):
"""Get configuration parameters to be rendered into the conf file."""
Expand Down Expand Up @@ -191,30 +171,27 @@ def get_config_params(self):
version_slug=self.version.slug,
)

build_id = self.build_env.build.get('id')
build_id = self.build_env.build.get("id")
build_url = None
if build_id:
build_url = reverse(
'builds_detail',
"builds_detail",
kwargs={
'project_slug': self.project.slug,
'build_pk': build_id,
"project_slug": self.project.slug,
"build_pk": build_id,
},
)
protocol = 'http' if settings.DEBUG else 'https'
build_url = f'{protocol}://{settings.PRODUCTION_DOMAIN}{build_url}'
protocol = "http" if settings.DEBUG else "https"
build_url = f"{protocol}://{settings.PRODUCTION_DOMAIN}{build_url}"

vcs_url = None
if self.version.is_external:
vcs_url = self.version.vcs_url

commit = (
self.project.vcs_repo(
version=self.version.slug,
environment=self.build_env,
)
.commit
)
commit = self.project.vcs_repo(
version=self.version.slug,
environment=self.build_env,
).commit

data = {
"current_version": self.version.verbose_name,
Expand Down Expand Up @@ -267,34 +244,26 @@ def get_config_params(self):

def append_conf(self):
"""
Find or create a ``conf.py`` and appends default content.
Find a ``conf.py`` and appends default content.

The default content is rendered from ``doc_builder/conf.py.tmpl``.
"""
if self.config_file is None:
raise ProjectConfigurationError(ProjectConfigurationError.NOT_FOUND)

# Generate a `conf.py` from a template
#
# TODO: we should remove this feature at some point to move forward
# with the idea of remove magic from the builders.
if not self.config_file:
self._write_config()
self.config_file = self.config_file or self.project.conf_file(self.version.slug)

try:
self.config_file = (
self.config_file or self.project.conf_file(self.version.slug)
if not os.path.exists(self.config_file):
raise UserFileNotFound(
UserFileNotFound.FILE_NOT_FOUND.format(self.config_file)
)
# Allow symlinks, but only the ones that resolve inside the base directory.
outfile = safe_open(
self.config_file, "a", allow_symlinks=True, base_path=self.project_path
)
if not outfile:
raise UserFileNotFound(
UserFileNotFound.FILE_NOT_FOUND.format(self.config_file)
)
except IOError as exc:
raise ProjectConfigurationError(
ProjectConfigurationError.NOT_FOUND
) from exc

# Allow symlinks, but only the ones that resolve inside the base directory.
# NOTE: if something goes wrong,
# `safe_open` raises an exception that's clearly communicated to the user.
outfile = safe_open(
self.config_file, "a", allow_symlinks=True, base_path=self.project_path
)

# Append config to project conf file
tmpl = template_loader.get_template('doc_builder/conf.py.tmpl')
Expand All @@ -319,8 +288,8 @@ def build(self):
project = self.project
build_command = [
*self.get_sphinx_cmd(),
'-T',
'-E',
"-T",
"-E",
]
if self.config.sphinx.fail_on_warning:
build_command.extend(["-W", "--keep-going"])
Expand Down Expand Up @@ -354,9 +323,9 @@ def build(self):

def get_sphinx_cmd(self):
return (
self.python_env.venv_bin(filename='python'),
'-m',
'sphinx',
self.python_env.venv_bin(filename="python"),
"-m",
"sphinx",
)


Expand Down Expand Up @@ -576,19 +545,19 @@ def _build_latexmk(self, cwd):
latex_class = LatexBuildCommand

cmd = [
'latexmk',
'-r',
"latexmk",
"-r",
rcfile,
# FIXME: check for platex here as well
'-pdfdvi' if self.project.language == 'ja' else '-pdf',
"-pdfdvi" if self.project.language == "ja" else "-pdf",
# When ``-f`` is used, latexmk will continue building if it
# encounters errors. We still receive a failure exit code in this
# case, but the correct steps should run.
'-f',
'-dvi-',
'-ps-',
f'-jobname={self.project.slug}',
'-interaction=nonstopmode',
"-f",
"-dvi-",
"-ps-",
f"-jobname={self.project.slug}",
"-interaction=nonstopmode",
]

cmd_ret = self.build_env.run_command_class(
Expand Down
3 changes: 1 addition & 2 deletions readthedocs/doc_builder/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import structlog


log = structlog.get_logger(__name__)


Expand Down Expand Up @@ -53,7 +52,7 @@ def _post_build(self):

def docs_dir(self):
"""Handle creating a custom docs_dir if it doesn't exist."""
for doc_dir_name in ['docs', 'doc', 'Doc', 'book']:
for doc_dir_name in ["docs", "doc", "Doc", "book"]:
possible_path = os.path.join(self.project_path, doc_dir_name)
if os.path.exists(possible_path):
return possible_path
Expand Down
Loading