45
45
from typing import Iterable
46
46
from urllib .parse import urljoin
47
47
48
- import zc .lockfile
49
48
import jinja2
50
- import requests
51
49
import tomlkit
52
-
50
+ import urllib3
51
+ import zc .lockfile
53
52
54
53
try :
55
54
from os import EX_OK , EX_SOFTWARE as EX_FAILURE
@@ -433,7 +432,8 @@ def build_robots_txt(
433
432
www_root : Path ,
434
433
group ,
435
434
skip_cache_invalidation ,
436
- ):
435
+ http : urllib3 .PoolManager ,
436
+ ) -> None :
437
437
"""Disallow crawl of EOL versions in robots.txt."""
438
438
if not www_root .exists ():
439
439
logging .info ("Skipping robots.txt generation (www root does not even exist)." )
@@ -448,7 +448,7 @@ def build_robots_txt(
448
448
robots_file .chmod (0o775 )
449
449
run (["chgrp" , group , robots_file ])
450
450
if not skip_cache_invalidation :
451
- purge ("robots.txt" )
451
+ purge (http , "robots.txt" )
452
452
453
453
454
454
def build_sitemap (
@@ -641,7 +641,7 @@ def full_build(self):
641
641
"""
642
642
return not self .quick and not self .language .html_only
643
643
644
- def run (self ) -> bool :
644
+ def run (self , http : urllib3 . PoolManager ) -> bool :
645
645
"""Build and publish a Python doc, for a language, and a version."""
646
646
start_time = perf_counter ()
647
647
logging .info ("Running." )
@@ -652,7 +652,7 @@ def run(self) -> bool:
652
652
if self .should_rebuild ():
653
653
self .build_venv ()
654
654
self .build ()
655
- self .copy_build_to_webroot ()
655
+ self .copy_build_to_webroot (http )
656
656
self .save_state (build_duration = perf_counter () - start_time )
657
657
except Exception as err :
658
658
logging .exception ("Badly handled exception, human, please help." )
@@ -798,7 +798,7 @@ def build_venv(self):
798
798
run ([venv_path / "bin" / "python" , "-m" , "pip" , "freeze" , "--all" ])
799
799
self .venv = venv_path
800
800
801
- def copy_build_to_webroot (self ) :
801
+ def copy_build_to_webroot (self , http : urllib3 . PoolManager ) -> None :
802
802
"""Copy a given build to the appropriate webroot with appropriate rights."""
803
803
logging .info ("Publishing start." )
804
804
start_time = perf_counter ()
@@ -911,9 +911,9 @@ def copy_build_to_webroot(self):
911
911
prefixes = run (["find" , "-L" , targets_dir , "-samefile" , target ]).stdout
912
912
prefixes = prefixes .replace (targets_dir + "/" , "" )
913
913
prefixes = [prefix + "/" for prefix in prefixes .split ("\n " ) if prefix ]
914
- purge (* prefixes )
914
+ purge (http , * prefixes )
915
915
for prefix in prefixes :
916
- purge (* [prefix + p for p in changed ])
916
+ purge (http , * [prefix + p for p in changed ])
917
917
logging .info (
918
918
"Publishing done (%s)." , format_seconds (perf_counter () - start_time )
6D40
919
919
)
@@ -981,7 +981,15 @@ def save_state(self, build_duration: float):
981
981
state_file .write_text (tomlkit .dumps (states ), encoding = "UTF-8" )
982
982
983
983
984
- def symlink (www_root : Path , language : Language , directory : str , name : str , group : str , skip_cache_invalidation : bool ):
984
+ def symlink (
985
+ www_root : Path ,
986
+ language : Language ,
987
+ directory : str ,
988
+ name : str ,
989
+ group : str ,
990
+ skip_cache_invalidation : bool ,
991
+ http : urllib3 .PoolManager ,
992
+ ) -> None :
985
993
"""Used by major_symlinks and dev_symlink to maintain symlinks."""
986
994
if language .tag == "en" : # English is rooted on /, no /en/
987
995
path = www_root
@@ -998,12 +1006,17 @@ def symlink(www_root: Path, language: Language, directory: str, name: str, group
998
1006
link .symlink_to (directory )
999
1007
run (["chown" , "-h" , ":" + group , str (link )])
1000
1008
if not skip_cache_invalidation :
1001
- purge_path (www_root , link )
1009
+ purge_path (http , www_root , link )
1002
1010
1003
1011
1004
1012
def major_symlinks (
1005
- www_root : Path , group , versions : Iterable [Version ], languages : Iterable [Language ], skip_cache_invalidation : bool
1006
- ):
1013
+ www_root : Path ,
1014
+ group : str ,
1015
+ versions : Iterable [Version ],
1016
+ languages : Iterable [Language ],
1017
+ skip_cache_invalidation : bool ,
1018
+ http : urllib3 .PoolManager ,
1019
+ ) -> None :
1007
1020
"""Maintains the /2/ and /3/ symlinks for each language.
1008
1021
1009
1022
Like:
@@ -1013,11 +1026,26 @@ def major_symlinks(
1013
1026
"""
1014
1027
current_stable = Version .current_stable (versions ).name
1015
1028
for language in languages :
1016
- symlink (www_root , language , current_stable , "3" , group , skip_cache_invalidation )
1017
- symlink (www_root , language , "2.7" , "2" , group , skip_cache_invalidation )
1029
+ symlink (
1030
+ www_root ,
1031
+ language ,
1032
+ current_stable ,
1033
+ "3" ,
1034
+ group ,
1035
+ skip_cache_invalidation ,
1036
+ http ,
1037
+ )
1038
+ symlink (www_root , language , "2.7" , "2" , group , skip_cache_invalidation , http )
1018
1039
1019
1040
1020
- def dev_symlink (www_root : Path , group , versions , languages , skip_cache_invalidation : bool ):
1041
+ def dev_symlink (
1042
+ www_root : Path ,
1043
+ group ,
1044
+ versions ,
1045
+ languages ,
1046
+ skip_cache_invalidation : bool ,
1047
+ http : urllib3 .PoolManager ,
1048
+ ) -> None :
1021
1049
"""Maintains the /dev/ symlinks for each language.
1022
1050
1023
1051
Like:
@@ -1027,10 +1055,18 @@ def dev_symlink(www_root: Path, group, versions, languages, skip_cache_invalidat
1027
1055
"""
1028
1056
current_dev = Version .current_dev (versions ).name
1029
1057
for language in languages :
1030
- symlink (www_root , language , current_dev , "dev" , group , skip_cache_invalidation )
1058
+ symlink (
1059
+ www_root ,
1060
+ language ,
1061
+ current_dev ,
1062
+ "dev" ,
1063
+ group ,
1064
+ skip_cache_invalidation ,
1065
+ http ,
1066
+ )
1031
1067
1032
1068
1033
- def purge (* paths ) :
1069
+ def purge (http : urllib3 . PoolManager , * paths : Path | str ) -> None :
1034
1070
"""Remove one or many paths from docs.python.org's CDN.
1035
1071
1036
1072
To be used when a file changes, so the CDN fetches the new one.
@@ -1039,20 +1075,22 @@ def purge(*paths):
1039
1075
for path in paths :
1040
1076
url = urljoin (base , str (path ))
1041
1077
logging .debug ("Purging %s from CDN" , url )
1042
- requests .request ("PURGE" , url , timeout = 30 )
1078
+ http .request ("PURGE" , url , timeout = 30 )
1043
1079
1044
1080
1045
- def purge_path (www_root : Path , path : Path ):
1081
+ def purge_path (http : urllib3 . PoolManager , www_root : Path , path : Path ) -> None :
1046
1082
"""Recursively remove a path from docs.python.org's CDN.
1047
1083
1048
1084
To be used when a directory changes, so the CDN fetches the new one.
1049
1085
"""
1050
- purge (* [file .relative_to (www_root ) for file in path .glob ("**/*" )])
1051
- purge (path .relative_to (www_root ))
1052
- purge (str (path .relative_to (www_root )) + "/" )
1086
+ purge (http , * [file .relative_to (www_root ) for file in path .glob ("**/*" )])
1087
+ purge (http , path .relative_to (www_root ))
1088
+ purge (http , str (path .relative_to (www_root )) + "/" )
1053
1089
1054
1090
1055
- def proofread_canonicals (www_root : Path , skip_cache_invalidation : bool ) -> None :
1091
+ def proofread_canonicals (
1092
+ www_root : Path , skip_cache_invalidation : bool , http : urllib3 .PoolManager
1093
+ ) -> None :
1056
1094
"""In www_root we check that all canonical links point to existing contents.
1057
1095
1058
1096
It can happen that a canonical is "broken":
@@ -1074,11 +1112,12 @@ def proofread_canonicals(www_root: Path, skip_cache_invalidation: bool) -> None:
1074
1112
html = html .replace (canonical .group (0 ), "" )
1075
1113
file .write_text (html , encoding = "UTF-8" , errors = "surrogateescape" )
1076
1114
if not skip_cache_invalidation :
1077
- purge (str (file ).replace ("/srv/docs.python.org/" , "" ))
1115
+ purge (http , str (file ).replace ("/srv/docs.python.org/" , "" ))
1078
1116
1079
1117
1080
- def parse_versions_from_devguide ():
1081
- releases = requests .get (
1118
+ def parse_versions_from_devguide (http : urllib3 .PoolManager ) -> list [Version ]:
1119
+ releases = http .request (
1120
+ "GET" ,
1082
1121
"https://raw.githubusercontent.com/"
1083
1122
"python/devguide/main/include/release-cycle.json" ,
1084
1123
timeout = 30 ,
@@ -1124,7 +1163,8 @@ def build_docs(args) -> bool:
1124
1163
"""Build all docs (each language and each version)."""
1125
1164
logging .info ("Full build start." )
1126
1165
start_time = perf_counter ()
1127
- versions = parse_versions_from_devguide ()
1166
+ http = urllib3 .PoolManager ()
1167
+ versions = parse_versions_from_devguide (http )
1128
1168
languages = parse_languages_from_config ()
1129
1169
todo = [
1130
1170
(version , language )
@@ -1137,7 +1177,6 @@ def build_docs(args) -> bool:
1137
1177
cpython_repo = Repository (
1138
1178
"https://github.com/python/cpython.git" , args .build_root / "cpython"
1139
1179
)
1140
- cpython_repo .update ()
1141
1180
while todo :
1142
1181
version , language = todo .pop ()
1143
1182
logging .root .handlers [0 ].setFormatter (
@@ -1149,22 +1188,42 @@ def build_docs(args) -> bool:
1149
1188
scope = sentry_sdk .get_isolation_scope ()
1150
1189
scope .set_tag ("version" , version .name )
1151
1190
scope .set_tag ("language" , language .tag )
1191
+ cpython_repo .update ()
1152
1192
builder = DocBuilder (
1153
1193
version , versions , language , languages , cpython_repo , ** vars (args )
1154
1194
)
1155
- all_built_successfully &= builder .run ()
1195
+ all_built_successfully &= builder .run (http )
1156
1196
logging .root .handlers [0 ].setFormatter (
1157
1197
logging .Formatter ("%(asctime)s %(levelname)s: %(message)s" )
1158
1198
)
1159
1199
1160
1200
build_sitemap (versions , languages , args .www_root , args .group )
1161
1201
build_404 (args .www_root , args .group )
1162
1202
build_robots_txt (
1163
- versions , languages , args .www_root , args .group , args .skip_cache_invalidation
1203
+ versions ,
1204
+ languages ,
1205
+ args .www_root ,
1206
+ args .group ,
1207
+ args .skip_cache_invalidation ,
1208
+ http ,
1209
+ )
1210
+ major_symlinks (
1211
+ args .www_root ,
1212
+ args .group ,
1213
+ versions ,
1214
+ languages ,
1215
+ args .skip_cache_invalidation ,
1216
+ http ,
1217
+ )
1218
+ dev_symlink (
1219
+ args .www_root ,
1220
+ args .group ,
1221
+ versions ,
1222
+ languages ,
1223
+ args .skip_cache_invalidation ,
1224
+ http ,
1164
1225
)
1165
- major_symlinks (args .www_root , args .group , versions , languages , args .skip_cache_invalidation )
1166
- dev_symlink (args .www_root , args .group , versions , languages , args .skip_cache_invalidation )
1167
- proofread_canonicals (args .www_root , args .skip_cache_invalidation )
1226
+ proofread_canonicals (args .www_root , args .skip_cache_invalidation , http )
1168
1227
1169
1228
logging .info ("Full build done (%s)." , format_seconds (perf_counter () - start_time ))
1170
1229
0 commit comments