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." )
@@ -797,7 +797,7 @@ def build_venv(self):
797
797
run ([venv_path / "bin" / "python" , "-m" , "pip" , "freeze" , "--all" ])
798
798
self .venv = venv_path
799
799
800
- def copy_build_to_webroot (self ) :
800
+ def copy_build_to_webroot (self , http : urllib3 . PoolManager ) -> None :
801
801
"""Copy a given build to the appropriate webroot with appropriate rights."""
802
802
logging .info ("Publishing start." )
803
803
self .www_root .mkdir (parents = True , exist_ok = True )
@@ -909,9 +909,9 @@ def copy_build_to_webroot(self):
909
909
prefixes = run (["find" , "-L" , targets_dir , "-samefile" , target ]).stdout
910
910
prefixes = prefixes .replace (targets_dir + "/" , "" )
911
911
prefixes = [prefix + "/" for prefix in prefixes .split ("\n " ) if prefix ]
912
- purge (* prefixes )
912
+ purge (http , * prefixes )
913
913
for prefix in prefixes :
914
- purge (* [prefix + p for p in changed ])
914
+ purge (http , * [prefix + p for p in changed ])
915
915
logging .info ("Publishing done" )
916
916
917
917
def should_rebuild (self ):
@@ -977,7 +977,15 @@ def save_state(self, build_duration: float):
977
977
state_file .write_text (tomlkit .dumps (states ), encoding = "UTF-8" )
978
978
979
979
980
- def symlink (www_root : Path , language : Language , directory : str , name : str , group : str , skip_cache_invalidation : bool ):
980
+ def symlink (
981
+ www_root : Path ,
982
+ language : Language ,
983
+ directory : str ,
984
+ name : str ,
985
+ group : str ,
986
+ skip_cache_invalidation : bool ,
987
+ http : urllib3 .PoolManager ,
988
+ ) -> None :
981
989
"""Used by major_symlinks and dev_symlink to maintain symlinks."""
982
990
if language .tag == "en" : # English is rooted on /, no /en/
983
991
path = www_root
@@ -994,12 +1002,17 @@ def symlink(www_root: Path, language: Language, directory: str, name: str, group
994
1002
link .symlink_to (directory )
995
1003
run (["chown" , "-h" , ":" + group , str (link )])
996
1004
if not skip_cache_invalidation :
997
- purge_path (www_root , link )
1005
+ purge_path (http , www_root , link )
998
1006
999
1007
1000
1008
def major_symlinks (
1001
- www_root : Path , group , versions : Iterable [Version ], languages : Iterable [Language ], skip_cache_invalidation : bool
1002
- ):
1009
+ www_root : Path ,
1010
+ group : str ,
1011
+ versions : Iterable [Version ],
1012
+ languages : Iterable [Language ],
1013
+ skip_cache_invalidation : bool ,
1014
+ http : urllib3 .PoolManager ,
1015
+ ) -> None :
1003
1016
"""Maintains the /2/ and /3/ symlinks for each language.
1004
1017
1005
1018
Like:
@@ -1009,11 +1022,26 @@ def major_symlinks(
1009
1022
"""
1010
1023
current_stable = Version .current_stable (versions ).name
1011
1024
for language in languages :
1012
- symlink (www_root , language , current_stable , "3" , group , skip_cache_invalidation )
1013
- symlink (www_root , language , "2.7" , "2" , group , skip_cache_invalidation )
1025
+ symlink (
1026
+ www_root ,
1027
+ language ,
1028
+ current_stable ,
1029
+ "3" ,
1030
+ group ,
1031
+ skip_cache_invalidation ,
1032
+ http ,
1033
+ )
1034
+ symlink (www_root , language , "2.7" , "2" , group , skip_cache_invalidation , http )
1014
1035
1015
1036
1016
- def dev_symlink (www_root : Path , group , versions , languages , skip_cache_invalidation : bool ):
1037
+ def dev_symlink (
1038
+ www_root : Path ,
1039
+ group ,
1040
+ versions ,
1041
+ languages ,
1042
+ skip_cache_invalidation : bool ,
1043
+ http : urllib3 .PoolManager ,
1044
+ ) -> None :
1017
1045
"""Maintains the /dev/ symlinks for each language.
1018
1046
1019
1047
Like:
@@ -1023,10 +1051,18 @@ def dev_symlink(www_root: Path, group, versions, languages, skip_cache_invalidat
1023
1051
"""
1024
1052
current_dev = Version .current_dev (versions ).name
1025
1053
for language in languages :
1026
- symlink (www_root , language , current_dev , "dev" , group , skip_cache_invalidation )
1054
+ symlink (
1055
+ www_root ,
1056
+ language ,
1057
+ current_dev ,
1058
+ "dev" ,
1059
+ group ,
1060
+ skip_cache_invalidation ,
1061
+ http ,
1062
+ )
1027
1063
1028
1064
1029
- def purge (* paths ) :
1065
+ def purge (http : urllib3 . PoolManager , * paths : Path | str ) -> None :
1030
1066
"""Remove one or many paths from docs.python.org's CDN.
1031
1067
1032
1068
To be used when a file changes, so the CDN fetches the new one.
@@ -1035,20 +1071,22 @@ def purge(*paths):
1035
1071
for path in paths :
1036
1072
url = urljoin (base , str (path ))
1037
1073
logging .debug ("Purging %s from CDN" , url )
1038
- requests .request ("PURGE" , url , timeout = 30 )
1074
+ http .request ("PURGE" , url , timeout = 30 )
1039
1075
1040
1076
1041
- def purge_path (www_root : Path , path : Path ):
1077
+ def purge_path (http : urllib3 . PoolManager , www_root : Path , path : Path ) -> None :
1042
1078
"""Recursively remove a path from docs.python.org's CDN.
1043
1079
1044
1080
To be used when a directory changes, so the CDN fetches the new one.
1045
1081
"""
1046
- purge (* [file .relative_to (www_root ) for file in path .glob ("**/*" )])
1047
- purge (path .relative_to (www_root ))
1048
- purge (str (path .relative_to (www_root )) + "/" )
1082
+ purge (http , * [file .relative_to (www_root ) for file in path .glob ("**/*" )])
1083
+ purge (http , path .relative_to (www_root ))
1084
+ purge (http , str (path .relative_to (www_root )) + "/" )
1049
1085
1050
1086
1051
- def proofread_canonicals (www_root : Path , skip_cache_invalidation : bool ) -> None :
1087
+ def proofread_canonicals (
1088
+ www_root : Path , skip_cache_invalidation : bool , http : urllib3 .PoolManager
1089
+ ) -> None :
1052
1090
"""In www_root we check that all canonical links point to existing contents.
1053
1091
1054
1092
It can happen that a canonical is "broken":
@@ -1070,11 +1108,12 @@ def proofread_canonicals(www_root: Path, skip_cache_invalidation: bool) -> None:
1070
1108
html = html .replace (canonical .group (0 ), "" )
1071
1109
file .write_text (html , encoding = "UTF-8" , errors = "surrogateescape" )
1072
1110
if not skip_cache_invalidation :
1073
- purge (str (file ).replace ("/srv/docs.python.org/" , "" ))
1111
+ purge (http , str (file ).replace ("/srv/docs.python.org/" , "" ))
1074
1112
1075
1113
1076
- def parse_versions_from_devguide ():
1077
- releases = requests .get (
1114
+ def parse_versions_from_devguide (http : urllib3 .PoolManager ) -> list [Version ]:
1115
+ releases = http .request (
1116
+ "GET" ,
1078
1117
"https://raw.githubusercontent.com/"
1079
1118
"python/devguide/main/include/release-cycle.json" ,
1080
1119
timeout = 30 ,
@@ -1104,7 +1143,8 @@ def parse_languages_from_config():
1104
1143
1105
1144
def build_docs (args ) -> bool :
1106
1145
"""Build all docs (each language and each version)."""
1107
- versions = parse_versions_from_devguide ()
1146
+ http = urllib3 .PoolManager ()
1147
+ versions = parse_versions_from_devguide (http )
1108
1148
languages = parse_languages_from_config ()
1109
1149
todo = [
1110
1150
(version , language )
@@ -1132,19 +1172,38 @@ def build_docs(args) -> bool:
1132
1172
builder = DocBuilder (
1133
1173
version , versions , language , languages , cpython_repo , ** vars (args )
1134
1174
)
1135
- all_built_successfully &= builder .run ()
1175
+ all_built_successfully &= builder .run (http )
1136
1176
logging .root .handlers [0 ].setFormatter (
1137
1177
logging .Formatter ("%(asctime)s %(levelname)s: %(message)s" )
1138
1178
)
1139
1179
1140
1180
build_sitemap (versions , languages , args .www_root , args .group )
1141
1181
build_404 (args .www_root , args .group )
1142
1182
build_robots_txt (
1143
- versions , languages , args .www_root , args .group , args .skip_cache_invalidation
1183
+ versions ,
1184
+ languages ,
1185
+ args .www_root ,
1186
+ args .group ,
1187
+ args .skip_cache_invalidation ,
1188
+ http ,
1189
+ )
1190
+ major_symlinks (
1191
+ args .www_root ,
1192
+ args .group ,
1193
+ versions ,
1194
+ languages ,
1195
+ args .skip_cache_invalidation ,
1196
+ http ,
1197
+ )
1198
+ dev_symlink (
1199
+ args .www_root ,
1200
+ args .group ,
1201
+ versions ,
1202
+ languages ,
1203
+ args .skip_cache_invalidation ,
1204
+ http ,
1144
1205
)
1145
- major_symlinks (args .www_root , args .group , versions , languages , args .skip_cache_invalidation )
1146
- dev_symlink (args .www_root , args .group , versions , languages , args .skip_cache_invalidation )
1147
- proofread_canonicals (args .www_root , args .skip_cache_invalidation )
1206
+ proofread_canonicals (args .www_root , args .skip_cache_invalidation , http )
1148
1207
1149
1208
return all_built_successfully
1150
1209
0 commit comments