-
Notifications
You must be signed in to change notification settings - Fork 59
/
Copy pathnoxfile.py
333 lines (278 loc) · 12.3 KB
/
noxfile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
import os
import pathlib
import shutil
import nox
import sys
import subprocess
# for some reason necessary to correctly import conf from cwd
sys.path.insert(0, str(pathlib.Path(__file__).parent.absolute()))
import conf
## Sphinx related options
# Sphinx output and source directories
BUILD_DIR = '_build'
OUTPUT_DIR = pathlib.Path(BUILD_DIR, "html")
SOURCE_DIR = pathlib.Path(".")
# Location of the translation templates
TRANSLATION_TEMPLATE_DIR = pathlib.Path(BUILD_DIR, "gettext")
TRANSLATION_LOCALES_DIR = pathlib.Path("locales")
# Sphinx build commands
SPHINX_BUILD = "sphinx-build"
SPHINX_AUTO_BUILD = "sphinx-autobuild"
# Sphinx parameters used to build the guide
BUILD_PARAMETERS = ["-b", "html"]
# Sphinx parameters used to test the build of the guide
TEST_PARAMETERS = ['--keep-going', '-E', '-a']
# Sphinx parameters to generate translation templates
TRANSLATION_TEMPLATE_PARAMETERS = ["-b", "gettext"]
# Sphinx-autobuild ignore and include parameters
AUTOBUILD_IGNORE = [
"_build",
".nox",
"build_assets",
"tmp",
]
AUTOBUILD_INCLUDE = [
pathlib.Path("_static", "pyos.css")
]
## Localization options (translations)
# List of languages for which locales will be generated in (/locales/<lang>)
LANGUAGES = conf.languages
# List of languages that should be built when releasing the guide (docs or docs-test sessions)
RELEASE_LANGUAGES = conf.release_languages
# allowable values of `SPHINX_ENV`
SPHINX_ENVS = ('production', 'development')
@nox.session
def docs(session):
"""Build the packaging guide."""
session.install("-e", ".")
sphinx_env = _sphinx_env(session)
session.run(SPHINX_BUILD, *BUILD_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs)
# When building the guide, also build the translations in RELEASE_LANGUAGES
session.notify("build-release-languages", session.posargs)
@nox.session(name="docs-test")
def docs_test(session):
"""
Build the packaging guide with more restricted parameters.
Note: this is the session used in CI/CD to release the guide.
"""
session.install("-e", ".")
session.run(SPHINX_BUILD, *BUILD_PARAMETERS, *TEST_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs,
env={'SPHINX_ENV': 'production'})
# When building the guide with additional parameters, also build the translations in RELEASE_LANGUAGES
# with those same parameters.
session.notify("build-release-languages", [*TEST_PARAMETERS, *session.posargs])
def _autobuild_cmd(posargs: list[str], output_dir = OUTPUT_DIR) -> list[str]:
cmd = [SPHINX_AUTO_BUILD, *BUILD_PARAMETERS, str(SOURCE_DIR), str(output_dir), *posargs]
for folder in AUTOBUILD_IGNORE:
cmd.extend(["--ignore", f"*/{folder}/*"])
return cmd
@nox.session(name="docs-live")
def docs_live(session):
"""
Build and launch a local copy of the guide.
This session will use sphinx-autobuild to build the guide and launch a local server so you can
browse it locally. It will automatically rebuild the guide when changes are detected in the source.
It can be used with the language parameter to build a specific translation, for example:
nox -s docs-live -- -D language=es
Note: The docs-live-lang session below is provided as a convenience session for beginner contributors
so they don't need to remember the specific sphinx-build parameters to build a different language.
"""
session.install("-e", ".")
cmd = _autobuild_cmd(session.posargs)
# This part was commented in the previous version of the nox file, keeping the same here
# for folder in AUTOBUILD_INCLUDE:
# cmd.extend(["--watch", folder])
session.run(*cmd, env={'SPHINX_ENV': "development"})
@nox.session(name="docs-live-lang")
def docs_live_lang(session):
"""
A convenience session for beginner contributors to use the docs-live session with
a specific language.
It expects the language code to be passed as the first positional argument, so it needs
to be called with from the command line with the following syntax:
nox -s docs-live-lang -- LANG
where LANG is one of the available languages defined in LANGUAGES.
For example, for Spanish: nox -s docs-live-lang -- es
"""
if not session.posargs:
session.error(
"Please provide a language using:\n\n "
"nox -s docs-live-lang -- LANG\n\n "
f" where LANG is one of: {LANGUAGES}"
)
lang = session.posargs[0]
if lang in LANGUAGES:
session.posargs.pop(0)
session.notify("docs-live", ('-D', f"language={lang}", *session.posargs))
else:
session.error(
f"[{lang}] locale is not available. Try using:\n\n "
"nox -s docs-live-lang -- LANG\n\n "
f"where LANG is one of: {LANGUAGES}"
)
@nox.session(name="docs-live-langs")
def docs_live_langs(session):
"""
Like docs-live but build all languages simultaneously
Requires concurrently to run (npm install -g concurrently)
"""
try:
subprocess.check_call(['concurrently'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except subprocess.CalledProcessError:
# handle errors in the called executable
# (aka, was found)
pass
except OSError:
session.error('docs-live-langs requires concurrently (npm install -g concurrently)')
session.install("-e", ".")
cmds = ['"' + " ".join(["SPHINX_ENV=development"] + _autobuild_cmd(session.posargs) + ['--open-browser']) + '"']
for language in LANGUAGES:
cmds.append(
'"' + " ".join(
[f"SPHINX_LANG={language}", "SPHINX_ENV=development"] +
_autobuild_cmd(
session.posargs + ["-D", f"language={language}"],
output_dir=OUTPUT_DIR / language
) + ["--port=0"]
) + '"'
)
cmd = ['concurrently', '--kill-others', '-n', ','.join(["en"] + LANGUAGES), '-c', 'auto', *cmds]
session.run(*cmd)
@nox.session(name="docs-clean")
def clean_dir(session):
"""Clean out the docs directory used in the live build."""
session.warn(f"Cleaning out {OUTPUT_DIR}")
dir_contents = OUTPUT_DIR.glob('*')
for content in dir_contents:
session.log(f'removing {content}')
if content.is_dir():
shutil.rmtree(content)
else:
pathlib.Path(content).unlink()
@nox.session(name="update-release-languages")
def update_release_languages(session):
"""
Update the translation files (./locales/*/.po) for languages in RELEASE_LANGUAGES.
Note: this step is called in the CI to keep release translations up to date with
the latest changes in the guide.
"""
if RELEASE_LANGUAGES:
session.install("-e", ".")
session.install("sphinx-intl")
session.log("Updating templates (.pot)")
session.run(SPHINX_BUILD, *TRANSLATION_TEMPLATE_PARAMETERS, SOURCE_DIR, TRANSLATION_TEMPLATE_DIR, *session.posargs)
for lang in RELEASE_LANGUAGES:
session.log(f"Updating .po files for [{lang}] translation")
session.run("sphinx-intl", "update", "-p", TRANSLATION_TEMPLATE_DIR, "-l", lang)
else:
session.warn("No release languages defined in RELEASE_LANGUAGES")
@nox.session(name="update-language")
def update_language(session):
"""
Update the translation files (./locales/*/.po) for a specific language translation.
Note: this step is used by language coordinators to keep their translation files up to date
with the latest changes in the guide, before the translation is released.
"""
if session.posargs and (lang := session.posargs.pop(0)):
if lang in LANGUAGES:
session.install("-e", ".")
session.install("sphinx-intl")
session.log("Updating templates (.pot)")
session.run(SPHINX_BUILD, *TRANSLATION_TEMPLATE_PARAMETERS, SOURCE_DIR, TRANSLATION_TEMPLATE_DIR, *session.posargs)
session.log(f"Updating .po files for [{lang}] translation")
session.run("sphinx-intl", "update", "-p", TRANSLATION_TEMPLATE_DIR, "-l", lang)
else:
f"[{lang}] locale is not available. Try using:\n\n "
"nox -s docs-live-lang -- LANG\n\n "
f"where LANG is one of: {LANGUAGES}"
else:
session.error(
"Please provide a language using:\n\n "
"nox -s update-language -- LANG\n\n "
f" where LANG is one of: {LANGUAGES}"
)
if not session.posargs:
session.error("Please provide the list of languages to build the translation for")
sphinx_env = _sphinx_env(session)
languages_to_build = session.posargs.pop(0)
@nox.session(name="build-language")
def build_language(session):
"""
Build the guide for a specific language translation
For example: nox -s build-language -- es.
"""
if session.posargs and (lang := session.posargs.pop(0)):
if lang in LANGUAGES:
session.install("-e", ".")
session.log(f"Building [{lang}] guide")
session.run(SPHINX_BUILD, *BUILD_PARAMETERS, "-D", f"language={lang}", ".", OUTPUT_DIR / lang, *session.posargs)
else:
session.error(f"Language {lang} is not in LANGUAGES list.")
else:
session.error(
"Please provide a language using:\n\n "
"nox -s build-language -- LANG\n\n "
f" where LANG is one of: {LANGUAGES}"
)
@nox.session(name="build-release-languages")
def build_release_languages(session):
"""
Build the translations of the guide for the languages in RELEASE_LANGUAGES.
"""
sphinx_env = _sphinx_env(session)
if not RELEASE_LANGUAGES:
session.warn("No release languages defined in RELEASE_LANGUAGES")
return
session.install("-e", ".")
for lang in RELEASE_LANGUAGES:
session.log(f"Building [{lang}] guide")
session.run(SPHINX_BUILD, *BUILD_PARAMETERS, "-D", f"language={lang}", ".", OUTPUT_DIR / lang, *session.posargs)
if lang == 'en':
out_dir = OUTPUT_DIR
else:
out_dir = OUTPUT_DIR / lang
session.run(SPHINX_BUILD, *BUILD_PARAMETERS, "-D", f"language={lang}", ".", out_dir, *session.posargs,
env={"SPHINX_LANG": lang, "SPHINX_ENV": sphinx_env})
session.log(f"Translations built for {RELEASE_LANGUAGES}")
@nox.session(name="build-all-languages")
def build_all_languages(session):
"""
Build the translations of the guide for the languages in LANGUAGES.
"""
if not LANGUAGES:
session.warn("No languages defined in LANGUAGES")
return
session.install("-e", ".")
for lang in LANGUAGES:
session.log(f"Building [{lang}] guide")
session.run(SPHINX_BUILD, *BUILD_PARAMETERS, "-D", f"language={lang}", ".", OUTPUT_DIR / lang, *session.posargs)
session.log(f"Translations built for {LANGUAGES}")
sphinx_env = _sphinx_env(session)
# if running from the docs or docs-test sessions, build only release languages
BUILD_LANGUAGES = RELEASE_LANGUAGES if sphinx_env == "production" else LANGUAGES
# only build languages that have a locale folder
BUILD_LANGUAGES = [lang for lang in BUILD_LANGUAGES if (TRANSLATION_LOCALES_DIR / lang).exists()]
session.log(f"Declared languages: {LANGUAGES}")
session.log(f"Release languages: {RELEASE_LANGUAGES}")
session.log(f"Building languages{' for release' if sphinx_env == 'production' else ''}: {BUILD_LANGUAGES}")
if not BUILD_LANGUAGES:
session.warn("No translations to build")
else:
session.notify("build-languages", [sphinx_env, BUILD_LANGUAGES, *session.posargs])
@nox.session(name="build-all-languages-test")
def build_all_languages_test(session):
"""
Build all translations of the guide with the testing parameters.
This is a convenience session to test the build of all translations with the testing parameters
in the same way docs-test does for the English version.
"""
session.notify("build-all-languages", [*TEST_PARAMETERS])
def _sphinx_env(session) -> str:
"""
Get the sphinx env, from the first positional argument if present or from the
``SPHINX_ENV`` environment variable, defaulting to "development"
"""
if session.posargs and session.posargs[0] in SPHINX_ENVS:
return session.posargs.pop(0)
else:
return os.environ.get('SPHINX_ENV', 'development')