|
19 | 19 | import logging |
20 | 20 | import random |
21 | 21 | import re |
| 22 | +import zipfile |
22 | 23 | from io import BytesIO |
23 | 24 | from urllib.parse import quote |
24 | 25 |
|
@@ -105,8 +106,23 @@ def get_bootstrap_instructions(request: Request): |
105 | 106 | machine with no internet access. |
106 | 107 | """ |
107 | 108 |
|
| 109 | + # Constructs the netloc (hostname + port) and proxy path depending on if the |
| 110 | + # request was forwarded via proxy |
| 111 | + netloc = ( |
| 112 | + f"{request.headers['X-Forwarded-Host']}:{request.headers['X-Forwarded-Port']}" |
| 113 | + if request.headers.get("X-Forwarded-Host") |
| 114 | + and request.headers.get("X-Forwarded-Port") |
| 115 | + else request.url.netloc |
| 116 | + ) |
| 117 | + # Additional bit in URL path after the netloc caused by the proxy reroute |
| 118 | + proxy_path = request.url.path.removesuffix(f"{bootstrap.prefix}/") |
| 119 | + |
108 | 120 | return respond_with_template( |
109 | 121 | request=request, |
| 122 | + parameters={ |
| 123 | + "netloc": netloc, |
| 124 | + "proxy_path": proxy_path, |
| 125 | + }, |
110 | 126 | filename="bootstrap.html", |
111 | 127 | ) |
112 | 128 |
|
@@ -314,7 +330,80 @@ def parse_cygwin_request( |
314 | 330 | ) |
315 | 331 |
|
316 | 332 |
|
317 | | -@msys2.get("/distrib/{setup_file}", response_class=StreamingResponse) |
| 333 | +@msys2.get("/config/pacman.d.zip", response_class=StreamingResponse) |
| 334 | +def get_pacman_mirrors(request: Request): |
| 335 | + """ |
| 336 | + Dynamically generates a zip file containing mirrorlist files that have been set |
| 337 | + up to mirror the MSYS2 package database for each environment. |
| 338 | +
|
| 339 | + The files in this folder should be pasted into, and overwrite, the 'mirrorlist' |
| 340 | + files present in the %MSYS64%\\etc\\pacman.d folder. The default path to this |
| 341 | + folder is C:\\msys64\\etc\\pacman.d. |
| 342 | + """ |
| 343 | + |
| 344 | + # Check if this is a forwarded request from somewhere else and construct netloc |
| 345 | + netloc = ( |
| 346 | + f"{request.headers['X-Forwarded-Host']}:{request.headers['X-Forwarded-Port']}" |
| 347 | + if request.headers.get("X-Forwarded-Host") |
| 348 | + and request.headers.get("X-Forwarded-Port") |
| 349 | + else request.url.netloc |
| 350 | + ) |
| 351 | + |
| 352 | + # Find path to Rust router using current URL Path |
| 353 | + path_to_router = request.url.path.removesuffix("/config/pacman.d.zip") |
| 354 | + |
| 355 | + # Construct base URL for subsequent use |
| 356 | + base_url = f"{request.url.scheme}://{netloc}{path_to_router}" |
| 357 | + logger.debug(f"Base URL to MSYS2 sub-router determined to be {base_url}") |
| 358 | + |
| 359 | + # Construct package database mirrors |
| 360 | + # Files are called mirrorlist.{environment} |
| 361 | + # URL format: {scheme}://{netloc}{proxy_path}/{router_prefix}/path/to/repo |
| 362 | + url_paths = { |
| 363 | + "clang64": "mingw/clang64", |
| 364 | + "mingw": "mingw/$repo", |
| 365 | + "mingw32": "mingw/i686", |
| 366 | + "mingw64": "mingw/x86_64", |
| 367 | + "msys": "msys/$arch", |
| 368 | + "ucrt64": "mingw/ucrt64", |
| 369 | + } |
| 370 | + # Construct file names and contents |
| 371 | + mirror_lists = { |
| 372 | + f"mirrorlist.{env}": "\n".join( |
| 373 | + [ |
| 374 | + "# See https://www.msys2.org/dev/mirrors", |
| 375 | + "", |
| 376 | + "## Primary", |
| 377 | + f"Server = {base_url}/repo/{repo_path}", |
| 378 | + "", |
| 379 | + ] |
| 380 | + ) |
| 381 | + for env, repo_path in url_paths.items() |
| 382 | + } |
| 383 | + |
| 384 | + # Create in-memory buffer for the ZIP file |
| 385 | + zip_buffer = BytesIO() |
| 386 | + |
| 387 | + # Create a zip file in the buffer |
| 388 | + with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file: |
| 389 | + for file_name, content in mirror_lists.items(): |
| 390 | + zip_file.writestr(file_name, content) |
| 391 | + zip_buffer.seek(0) # Move object pointer back to start |
| 392 | + |
| 393 | + # Construct and return streaming response |
| 394 | + headers = { |
| 395 | + "Content-Disposition": "attachment; filename=pacman.d.zip", |
| 396 | + "Content-Length": str(zip_buffer.getbuffer().nbytes), |
| 397 | + } |
| 398 | + return StreamingResponse( |
| 399 | + zip_buffer, |
| 400 | + status_code=200, |
| 401 | + headers=headers, |
| 402 | + media_type="application/zip", |
| 403 | + ) |
| 404 | + |
| 405 | + |
| 406 | +@msys2.get("/repo/distrib/{setup_file}", response_class=StreamingResponse) |
318 | 407 | def get_msys2_setup( |
319 | 408 | request: Request, |
320 | 409 | setup_file: str, |
@@ -351,7 +440,7 @@ def get_msys2_setup( |
351 | 440 | ) |
352 | 441 |
|
353 | 442 |
|
354 | | -@msys2.get("/", response_class=Response) |
| 443 | +@msys2.get("/repo/", response_class=Response) |
355 | 444 | def get_msys2_main_index( |
356 | 445 | request: Request, |
357 | 446 | ) -> Response: |
@@ -391,7 +480,7 @@ def get_msys2_main_index( |
391 | 480 | ) |
392 | 481 |
|
393 | 482 |
|
394 | | -@msys2.get("/{system}/", response_class=Response) |
| 483 | +@msys2.get("/repo/{system}/", response_class=Response) |
395 | 484 | def get_msys2_environment_index( |
396 | 485 | request: Request, |
397 | 486 | system: str, |
@@ -435,7 +524,7 @@ def get_msys2_environment_index( |
435 | 524 | ) |
436 | 525 |
|
437 | 526 |
|
438 | | -@msys2.get("/{system}/{environment}/", response_class=Response) |
| 527 | +@msys2.get("/repo/{system}/{environment}/", response_class=Response) |
439 | 528 | def get_msys2_package_index( |
440 | 529 | request: Request, |
441 | 530 | system: str, |
@@ -464,7 +553,7 @@ def get_msys2_package_index( |
464 | 553 | ) |
465 | 554 |
|
466 | 555 |
|
467 | | -@msys2.get("/{system}/{environment}/{package}", response_class=StreamingResponse) |
| 556 | +@msys2.get("/repo/{system}/{environment}/{package}", response_class=StreamingResponse) |
468 | 557 | def get_msys2_package_file( |
469 | 558 | request: Request, |
470 | 559 | system: str, |
|
0 commit comments