|
23 | 23 | from __future__ import annotations
|
24 | 24 |
|
25 | 25 | import argparse
|
| 26 | +import concurrent.futures |
26 | 27 | import dataclasses
|
27 | 28 | import datetime as dt
|
28 | 29 | import filecmp
|
@@ -1262,21 +1263,41 @@ def proofread_canonicals(
|
1262 | 1263 | /3/whatsnew/3.11.html, which may not exist yet.
|
1263 | 1264 | """
|
1264 | 1265 | logging.info("Checking canonical links...")
|
1265 |
| - canonical_re = re.compile( |
1266 |
| - """<link rel="canonical" href="https://docs.python.org/([^"]*)" />""" |
1267 |
| - ) |
1268 |
| - for file in www_root.glob("**/*.html"): |
1269 |
| - html = file.read_text(encoding="UTF-8", errors="surrogateescape") |
1270 |
| - canonical = canonical_re.search(html) |
1271 |
| - if not canonical: |
1272 |
| - continue |
1273 |
| - target = canonical.group(1) |
1274 |
| - if not (www_root / target).exists(): |
1275 |
| - logging.info("Removing broken canonical from %s to %s", file, target) |
1276 |
| - html = html.replace(canonical.group(0), "") |
1277 |
| - file.write_text(html, encoding="UTF-8", errors="surrogateescape") |
1278 |
| - if not skip_cache_invalidation: |
1279 |
| - purge(http, str(file).replace("/srv/docs.python.org/", "")) |
| 1266 | + worker_count = (os.cpu_count() or 1) + 2 |
| 1267 | + with concurrent.futures.ThreadPoolExecutor(worker_count) as executor: |
| 1268 | + futures = { |
| 1269 | + executor.submit(_check_canonical_rel, file, www_root) |
| 1270 | + for file in www_root.glob("**/*.html") |
| 1271 | + } |
| 1272 | + paths_to_purge = { |
| 1273 | + res.relative_to(www_root) # strip the leading /srv/docs.python.org |
| 1274 | + for fut in concurrent.futures.as_completed(futures) |
| 1275 | + if (res := fut.result()) is not None |
| 1276 | + } |
| 1277 | + if not skip_cache_invalidation: |
| 1278 | + purge(http, *paths_to_purge) |
| 1279 | + |
| 1280 | + |
| 1281 | +_canonical_re = re.compile( |
| 1282 | + """<link rel="canonical" href="https://docs.python.org/([^"]*)" />""" |
| 1283 | +) |
| 1284 | + |
| 1285 | + |
| 1286 | +def _check_canonical_rel(file: Path, www_root: Path): |
| 1287 | + # Check for a canonical relation link in the HTML. |
| 1288 | + # If one exists, ensure that the target exists |
| 1289 | + # or otherwise remove the canonical link element. |
| 1290 | + html = file.read_text(encoding="UTF-8", errors="surrogateescape") |
| 1291 | + canonical = _canonical_re.search(html) |
| 1292 | + if canonical is None: |
| 1293 | + return None |
| 1294 | + target = canonical.group(1) |
| 1295 | + if (www_root / target).exists(): |
| 1296 | + return None |
| 1297 | + logging.info("Removing broken canonical from %s to %s", file, target) |
| 1298 | + html = html.replace(canonical.group(0), "") |
| 1299 | + file.write_text(html, encoding="UTF-8", errors="surrogateescape") |
| 1300 | + return file |
1280 | 1301 |
|
1281 | 1302 |
|
1282 | 1303 | def purge(http: urllib3.PoolManager, *paths: Path | str) -> None:
|
|
0 commit comments