9
9
import structlog
10
10
import yaml
11
11
from django .conf import settings
12
- from django .template import loader as template_loader
13
12
14
13
from readthedocs .core .utils .filesystem import safe_open
15
14
from readthedocs .doc_builder .base import BaseBuilder
16
- from readthedocs .doc_builder .exceptions import MkDocsYAMLParseError
17
15
from readthedocs .projects .constants import MKDOCS , MKDOCS_HTML
18
- from readthedocs .projects .exceptions import UserFileNotFound
19
- from readthedocs .projects .models import Feature
20
16
21
17
log = structlog .get_logger (__name__ )
22
18
@@ -49,31 +45,23 @@ def __init__(self, *args, **kwargs):
49
45
# This is the *MkDocs* yaml file
50
46
self .yaml_file = self .get_yaml_config ()
51
47
52
- # README: historically, the default theme was ``readthedocs`` but in
53
- # https://github.com/rtfd/readthedocs.org/pull/4556 we change it to
54
- # ``mkdocs`` to maintain the same behavior in Read the Docs than
55
- # building locally. Although, we can't apply this into the Corporate
56
- # site. To keep the same default theme there, we created a Feature flag
57
- # for these project that were building with MkDocs in the Corporate
58
- # site.
59
- if self .project .has_feature (Feature .MKDOCS_THEME_RTD ):
60
- self .DEFAULT_THEME_NAME = "readthedocs"
61
- log .warning (
62
- "Project using readthedocs theme as default for MkDocs." ,
63
- project_slug = self .project .slug ,
64
- )
65
- else :
66
- self .DEFAULT_THEME_NAME = "mkdocs"
67
-
68
48
def get_final_doctype (self ):
69
49
"""
70
50
Select a doctype based on the ``use_directory_urls`` setting.
71
51
72
52
https://www.mkdocs.org/user-guide/configuration/#use_directory_urls
73
53
"""
54
+
55
+ # TODO: we should eventually remove this method completely and stop
56
+ # relying on "loading the `mkdocs.yml` file in a safe way just to know
57
+ # if it's a MKDOCS or MKDOCS_HTML documentation type".
58
+
74
59
# Allow symlinks, but only the ones that resolve inside the base directory.
75
60
with safe_open (
76
- self .yaml_file , "r" , allow_symlinks = True , base_path = self .project_path
61
+ self .yaml_file ,
62
+ "r" ,
63
+ allow_symlinks = True ,
64
+ base_path = self .project_path ,
77
65
) as fh :
78
66
config = yaml_load_safely (fh )
79
67
use_directory_urls = config .get ("use_directory_urls" , True )
@@ -89,192 +77,23 @@ def get_yaml_config(self):
89
77
mkdocs_path ,
90
78
)
91
79
92
- def load_yaml_config (self ):
93
- """
94
- Load a YAML config.
95
-
96
- :raises: ``MkDocsYAMLParseError`` if failed due to syntax errors.
97
- """
98
- try :
99
- # Allow symlinks, but only the ones that resolve inside the base directory.
100
- result = safe_open (
101
- self .yaml_file , "r" , allow_symlinks = True , base_path = self .project_path
102
- )
103
- if not result :
104
- raise UserFileNotFound (
105
- message_id = UserFileNotFound .FILE_NOT_FOUND ,
106
- format_values = {
107
- "filename" : self .yaml_file ,
108
- },
109
- )
110
-
111
- config = yaml_load_safely (result )
112
-
113
- if not config :
114
- raise MkDocsYAMLParseError (MkDocsYAMLParseError .EMPTY_CONFIG )
115
- if not isinstance (config , dict ):
116
- raise MkDocsYAMLParseError (MkDocsYAMLParseError .CONFIG_NOT_DICT )
117
- return config
118
-
119
- except IOError :
120
- raise MkDocsYAMLParseError (MkDocsYAMLParseError .NOT_FOUND )
121
- except yaml .YAMLError as exc :
122
- note = ""
123
- if hasattr (exc , "problem_mark" ):
124
- mark = exc .problem_mark
125
- note = " (line %d, column %d)" % (
126
- mark .line + 1 ,
127
- mark .column + 1 ,
128
- )
129
- raise MkDocsYAMLParseError (
130
- MkDocsYAMLParseError .SYNTAX_ERROR ,
131
- ) from exc
132
-
133
80
def append_conf (self ):
134
81
"""
135
- Set mkdocs config values .
82
+ Call `cat mkdocs.yaml` only .
136
83
137
- :raises: ``MkDocsYAMLParseError`` if failed due to known type errors
138
- (i.e. expecting a list and a string is found).
139
- """
140
- user_config = self .load_yaml_config ()
141
-
142
- # Handle custom docs dirs
143
- docs_dir = user_config .get ("docs_dir" , "docs" )
144
- if not isinstance (docs_dir , (type (None ), str )):
145
- raise MkDocsYAMLParseError (
146
- MkDocsYAMLParseError .INVALID_DOCS_DIR_CONFIG ,
147
- )
148
-
149
- user_config ["docs_dir" ] = docs_dir
150
- static_url = self .project .proxied_static_path
151
-
152
- # Set mkdocs config values.
153
- extra_assets = {
154
- "extra_javascript" : [
155
- "readthedocs-data.js" ,
156
- f"{ static_url } core/js/readthedocs-doc-embed.js" ,
157
- f"{ static_url } javascript/readthedocs-analytics.js" ,
158
- ],
159
- "extra_css" : [
160
- f"{ static_url } css/badge_only.css" ,
161
- f"{ static_url } css/readthedocs-doc-embed.css" ,
162
- ],
163
- }
164
-
165
- for config , extras in extra_assets .items ():
166
- value = user_config .get (config , [])
167
- if value is None :
168
- value = []
169
- if not isinstance (value , list ):
170
- raise MkDocsYAMLParseError (
171
- message_id = MkDocsYAMLParseError .INVALID_EXTRA_CONFIG ,
172
- format_values = {
173
- "extra_config" : config ,
174
- },
175
- )
176
- # Add the static file only if isn't already in the list.
177
- value .extend ([extra for extra in extras if extra not in value ])
178
- user_config [config ] = value
179
-
180
- # The docs path is relative to the location
181
- # of the mkdocs configuration file.
182
- docs_path = os .path .join (
183
- os .path .dirname (self .yaml_file ),
184
- docs_dir ,
185
- )
186
-
187
- # if user puts an invalid `docs_dir` path raise an Exception
188
- if not os .path .exists (docs_path ):
189
- raise MkDocsYAMLParseError (
190
- MkDocsYAMLParseError .INVALID_DOCS_DIR_PATH ,
191
- )
192
-
193
- # RTD javascript writing
194
- rtd_data = self .generate_rtd_data (
195
- docs_dir = os .path .relpath (docs_path , self .project_path ),
196
- mkdocs_config = user_config ,
197
- )
198
- with safe_open (
199
- os .path .join (docs_path , "readthedocs-data.js" ), "w" , encoding = "utf-8"
200
- ) as f :
201
- f .write (rtd_data )
202
-
203
- # Use Read the Docs' analytics setup rather than mkdocs'
204
- # This supports using RTD's privacy improvements around analytics
205
- user_config ["google_analytics" ] = None
206
-
207
- # README: make MkDocs to use ``readthedocs`` theme as default if the
208
- # user didn't specify a specific theme manually
209
- if self .project .has_feature (Feature .MKDOCS_THEME_RTD ):
210
- if "theme" not in user_config :
211
- # mkdocs<0.17 syntax
212
- user_config ["theme" ] = self .DEFAULT_THEME_NAME
213
-
214
- # Write the modified mkdocs configuration
215
- with safe_open (self .yaml_file , "w" , encoding = "utf-8" ) as f :
216
- yaml_dump_safely (
217
- user_config ,
218
- f ,
219
- )
84
+ This behavior has changed. We used to parse the YAML file and append
85
+ some configs automatically, but we have been removing that magic from
86
+ our builders as much as we can.
220
87
88
+ This method will eventually removed completely.
89
+ """
221
90
# Write the mkdocs.yml to the build logs
222
91
self .run (
223
92
"cat" ,
224
93
os .path .relpath (self .yaml_file , self .project_path ),
225
94
cwd = self .project_path ,
226
95
)
227
96
228
- def generate_rtd_data (self , docs_dir , mkdocs_config ):
229
- """Generate template properties and render readthedocs-data.js."""
230
- # Use the analytics code from mkdocs.yml
231
- # if it isn't set already by Read the Docs,
232
- analytics_code = self .version .project .analytics_code
233
- if not analytics_code and mkdocs_config .get ("google_analytics" ):
234
- # http://www.mkdocs.org/user-guide/configuration/#google_analytics
235
- analytics_code = mkdocs_config ["google_analytics" ][0 ]
236
-
237
- commit = (
238
- self .version .project .vcs_repo (
239
- version = self .version .slug ,
240
- environment = self .build_env ,
241
- ).commit ,
242
- )
243
-
244
- # Will be available in the JavaScript as READTHEDOCS_DATA.
245
- readthedocs_data = {
246
- "project" : self .version .project .slug ,
247
- "version" : self .version .slug ,
248
- "language" : self .version .project .language ,
249
- "programming_language" : self .version .project .programming_language ,
250
- "page" : None ,
251
- "theme" : self .get_theme_name (mkdocs_config ),
252
- "builder" : "mkdocs" ,
253
- "docroot" : docs_dir ,
254
- "source_suffix" : ".md" ,
255
- "api_host" : settings .PUBLIC_API_URL ,
256
- "ad_free" : not self .project .show_advertising ,
257
- "commit" : commit ,
258
- "global_analytics_code" : (
259
- None
260
- if self .project .analytics_disabled
261
- else settings .GLOBAL_ANALYTICS_CODE
262
- ),
263
- "user_analytics_code" : analytics_code ,
264
- "proxied_static_path" : self .project .proxied_static_path ,
265
- "proxied_api_host" : self .project .proxied_api_host ,
266
- }
267
-
268
- data_ctx = {
269
- "readthedocs_data" : readthedocs_data ,
270
- "current_version" : readthedocs_data ["version" ],
271
- "slug" : readthedocs_data ["project" ],
272
- "html_theme" : readthedocs_data ["theme" ],
273
- "pagename" : None ,
274
- }
275
- tmpl = template_loader .get_template ("doc_builder/data.js.tmpl" )
276
- return tmpl .render (data_ctx )
277
-
278
97
def build (self ):
279
98
build_command = [
280
99
self .python_env .venv_bin (filename = "python" ),
@@ -296,42 +115,12 @@ def build(self):
296
115
)
297
116
return cmd_ret .successful
298
117
299
- def get_theme_name (self , mkdocs_config ):
300
- """
301
- Get the theme configuration in the mkdocs_config.
302
-
303
- In v0.17.0, the theme configuration switched
304
- from two separate configs (both optional) to a nested directive.
305
-
306
- :see: http://www.mkdocs.org/about/release-notes/#theme-customization-1164
307
- :returns: the name of the theme RTD will use
308
- """
309
- theme_setting = mkdocs_config .get ("theme" )
310
- if isinstance (theme_setting , dict ):
311
- # Full nested theme config (the new configuration)
312
- return theme_setting .get ("name" ) or self .DEFAULT_THEME_NAME
313
-
314
- if theme_setting :
315
- # A string which is the name of the theme
316
- return theme_setting
317
-
318
- theme_dir = mkdocs_config .get ("theme_dir" )
319
- if theme_dir :
320
- # Use the name of the directory in this project's custom theme directory
321
- return theme_dir .rstrip ("/" ).split ("/" )[- 1 ]
322
-
323
- return self .DEFAULT_THEME_NAME
324
-
325
118
326
119
class MkdocsHTML (BaseMkdocs ):
327
120
builder = "build"
328
121
build_dir = "_readthedocs/html"
329
122
330
123
331
- # TODO: find a better way to integrate with MkDocs.
332
- # See https://github.com/readthedocs/readthedocs.org/issues/7844
333
-
334
-
335
124
class ProxyPythonName (yaml .YAMLObject ):
336
125
def __init__ (self , value ):
337
126
self .value = value
@@ -389,8 +178,3 @@ def yaml_load_safely(content):
389
178
information loss.
390
179
"""
391
180
return yaml .load (content , Loader = SafeLoader )
392
-
393
-
394
- def yaml_dump_safely (content , stream = None ):
395
- """Uses ``SafeDumper`` dumper to write YAML contents."""
396
- return yaml .dump (content , stream = stream , Dumper = SafeDumper )
0 commit comments