Skip to content

Commit

Permalink
Stop creating a conf.py automatically and doing magic around README h…
Browse files Browse the repository at this point in the history
…andling (#5609)

* Stop creating a conf.py file automatically for users and doing magic around README handling

* remove readme text

* Auto generating mkdocs.yaml removed

* create_index added

* fixed error msg

* tests updated

* Updated Error msg

* Lint

* Test: remove old test

* Lint

* Delete `conf.py` template

* Build: fail the build if `docs/conf.py` doesn't exist

* Build: raise exception if no config file

---------

Co-authored-by: Manuel Kaufmann <humitos@gmail.com>
  • Loading branch information
saadmk11 and humitos authored Aug 22, 2023
1 parent 040a8cb commit 97b3b25
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 365 deletions.
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)

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

0 comments on commit 97b3b25

Please sign in to comment.