5050
5151TYPE_CHECKING = False
5252if TYPE_CHECKING :
53- from collections .abc import Iterator , Sequence
53+ from collections .abc import Iterator , Sequence , Set
5454 from typing import Literal
5555
5656try :
@@ -1063,7 +1063,9 @@ def build_docs(args: argparse.Namespace) -> bool:
10631063 ]
10641064 del args .branch
10651065 del args .languages
1066- all_built_successfully = True
1066+
1067+ build_succeeded = set ()
1068+ build_failed = set ()
10671069 cpython_repo = Repository (
10681070 "https://github.com/python/cpython.git" ,
10691071 args .build_root / _checkout_name (args .select_output ),
@@ -1083,7 +1085,12 @@ def build_docs(args: argparse.Namespace) -> bool:
10831085 builder = DocBuilder (
10841086 version , versions , language , languages , cpython_repo , ** vars (args )
10851087 )
1086- all_built_successfully &= builder .run (http )
1088+ built_successfully = builder .run (http )
1089+ if built_successfully :
1090+ build_succeeded .add ((version .name , language .tag ))
1091+ else :
1092+ build_failed .add ((version .name , language .tag ))
1093+
10871094 logging .root .handlers [0 ].setFormatter (
10881095 logging .Formatter ("%(asctime)s %(levelname)s: %(message)s" )
10891096 )
@@ -1096,27 +1103,20 @@ def build_docs(args: argparse.Namespace) -> bool:
10961103 args .skip_cache_invalidation ,
10971104 http ,
10981105 )
1099- major_symlinks (
1100- args .www_root ,
1101- args .group ,
1102- versions ,
1103- languages ,
1104- args .skip_cache_invalidation ,
1105- http ,
1106- )
1107- dev_symlink (
1106+ make_symlinks (
11081107 args .www_root ,
11091108 args .group ,
11101109 versions ,
11111110 languages ,
1111+ build_succeeded ,
11121112 args .skip_cache_invalidation ,
11131113 http ,
11141114 )
11151115 proofread_canonicals (args .www_root , args .skip_cache_invalidation , http )
11161116
11171117 logging .info ("Full build done (%s)." , format_seconds (perf_counter () - start_time ))
11181118
1119- return all_built_successfully
1119+ return len ( build_failed ) == 0
11201120
11211121
11221122def parse_versions_from_devguide (http : urllib3 .PoolManager ) -> Versions :
@@ -1182,79 +1182,60 @@ def copy_robots_txt(
11821182 purge (http , "robots.txt" )
11831183
11841184
1185- def major_symlinks (
1185+ def make_symlinks (
11861186 www_root : Path ,
11871187 group : str ,
11881188 versions : Versions ,
11891189 languages : Languages ,
1190+ successful_builds : Set [tuple [str , str ]],
11901191 skip_cache_invalidation : bool ,
11911192 http : urllib3 .PoolManager ,
11921193) -> None :
1193- """Maintains the /2/ and /3 / symlinks for each language.
1194+ """Maintains the /2/, /3/, and /dev / symlinks for each language.
11941195
11951196 Like:
1196- - /3/ → /3.9/
1197- - /fr/3/ → /fr/3.9/
1198- - /es/3/ → /es/3.9/
1197+ - /2/ → /2.7/
1198+ - /3/ → /3.12/
1199+ - /dev/ → /3.14/
1200+ - /fr/3/ → /fr/3.12/
1201+ - /es/dev/ → /es/3.14/
11991202 """
1200- logging .info ("Creating major version symlinks..." )
1201- current_stable = versions .current_stable .name
1202- for language in languages :
1203- symlink (
1204- www_root ,
1205- language ,
1206- current_stable ,
1207- "3" ,
1208- group ,
1209- skip_cache_invalidation ,
1210- http ,
1211- )
1212- symlink (www_root , language , "2.7" , "2" , group , skip_cache_invalidation , http )
1213-
1214-
1215- def dev_symlink (
1216- www_root : Path ,
1217- group ,
1218- versions ,
1219- languages ,
1220- skip_cache_invalidation : bool ,
1221- http : urllib3 .PoolManager ,
1222- ) -> None :
1223- """Maintains the /dev/ symlinks for each language.
1224-
1225- Like:
1226- - /dev/ → /3.11/
1227- - /fr/dev/ → /fr/3.11/
1228- - /es/dev/ → /es/3.11/
1229- """
1230- logging .info ("Creating development version symlinks..." )
1231- current_dev = versions .current_dev .name
1232- for language in languages :
1233- symlink (
1234- www_root ,
1235- language ,
1236- current_dev ,
1237- "dev" ,
1238- group ,
1239- skip_cache_invalidation ,
1240- http ,
1241- )
1203+ logging .info ("Creating major and development version symlinks..." )
1204+ for symlink_name , symlink_target in (
1205+ ("3" , versions .current_stable .name ),
1206+ ("2" , "2.7" ),
1207+ ("dev" , versions .current_dev .name ),
1208+ ):
1209+ for language in languages :
1210+ if (symlink_target , language .tag ) in successful_builds :
1211+ symlink (
1212+ www_root ,
1213+ language .tag ,
1214+ symlink_target ,
1215+ symlink_name ,
1216+ group ,
1217+ skip_cache_invalidation ,
1218+ http ,
1219+ )
12421220
12431221
12441222def symlink (
12451223 www_root : Path ,
1246- language : Language ,
1224+ language_tag : str ,
12471225 directory : str ,
12481226 name : str ,
12491227 group : str ,
12501228 skip_cache_invalidation : bool ,
12511229 http : urllib3 .PoolManager ,
12521230) -> None :
12531231 """Used by major_symlinks and dev_symlink to maintain symlinks."""
1254- if language .tag == "en" : # English is rooted on /, no /en/
1232+ msg = "Creating symlink from %s to %s"
1233+ if language_tag == "en" : # English is rooted on /, no /en/
12551234 path = www_root
1235+ logging .debug (msg , name , directory )
12561236 else :
1257- path = www_root / language .tag
1237+ path = www_root / language_tag
1238+ logging .debug (msg , f"{ language_tag } /{ name } " , f"{ language_tag } /{ directory } " )
12581239 link = path / name
12591240 directory_path = path / directory
12601241 if not directory_path .exists ():
@@ -1266,7 +1247,7 @@ def symlink(
12661247 link .symlink_to (directory )
12671248 run (["chown" , "-h" , f":{ group } " , str (link )])
12681249 if not skip_cache_invalidation :
1269- surrogate_key = f"{ language . tag } /{ name } "
1250+ surrogate_key = f"{ language_tag } /{ name } "
12701251 purge_surrogate_key (http , surrogate_key )
12711252
12721253
0 commit comments