2222import os
2323import re
2424import shutil
25+ import subprocess
2526import sys
27+ import time
2628from functools import cache
2729from pathlib import Path
2830from typing import NamedTuple
@@ -1117,6 +1119,50 @@ def install_airflow_and_providers(
11171119 console .print ("\n [green]Done!" )
11181120
11191121
1122+ def _run_uv_install_with_retry (
1123+ cmd : list [str ],
1124+ github_actions : bool ,
1125+ check : bool = True ,
1126+ max_attempts : int = 3 ,
1127+ sleep_seconds : int = 30 ,
1128+ ) -> subprocess .CompletedProcess :
1129+ """Run a uv pip install command with retry logic for cargo-related transient failures.
1130+
1131+ Workaround for https://github.com/astral-sh/uv/issues/18801 — uv can fail with cargo-related
1132+ errors during package builds. When a failure contains "cargo" or "maturin" in the output, we retry up to
1133+ max_attempts times. Non-cargo failures are returned immediately without retry.
1134+ """
1135+ for attempt in range (1 , max_attempts + 1 ):
1136+ console .print (f"[bright_blue]Attempt { attempt } of { max_attempts } for uv install" )
1137+ result = run_command (
1138+ cmd ,
1139+ github_actions = github_actions ,
1140+ check = False ,
1141+ stdout = subprocess .PIPE ,
1142+ stderr = subprocess .STDOUT ,
1143+ )
1144+ output = result .stdout .decode () if result .stdout else ""
1145+ if output :
1146+ console .print (output )
1147+ if result .returncode == 0 :
1148+ return result
1149+ if "cargo" not in output and "maturin" not in output :
1150+ console .print ("[yellow]Failure is not cargo-related, not retrying." )
1151+ if check :
1152+ sys .exit (result .returncode )
1153+ return result
1154+ if attempt < max_attempts :
1155+ console .print (
1156+ f"[yellow]Attempt { attempt } failed with cargo-related error. Sleeping { sleep_seconds } s before retry..."
1157+ )
1158+ time .sleep (sleep_seconds )
1159+ else :
1160+ console .print (f"[red]All { max_attempts } attempts failed." )
1161+ if check :
1162+ sys .exit (result .returncode )
1163+ return result
1164+
1165+
11201166def _install_airflow_and_optionally_providers_together (
11211167 installation_spec : InstallationSpec , github_actions : bool
11221168):
@@ -1161,15 +1207,17 @@ def _install_airflow_and_optionally_providers_together(
11611207 )
11621208 install_providers_command .extend (["--constraint" , installation_spec .provider_constraints_location ])
11631209 console .print ()
1164- result = run_command (install_providers_command , github_actions = github_actions , check = False )
1210+ result = _run_uv_install_with_retry (
1211+ install_providers_command , github_actions = github_actions , check = False
1212+ )
11651213 if result .returncode != 0 :
11661214 console .print (
11671215 "[warning]Installation with constraints failed - might be because pre-installed provider"
11681216 " has conflicting dependencies in PyPI. Falling back to a non-constraint installation."
11691217 )
1170- run_command (base_install_cmd , github_actions = github_actions , check = True )
1218+ _run_uv_install_with_retry (base_install_cmd , github_actions = github_actions , check = True )
11711219 else :
1172- run_command (base_install_cmd , github_actions = github_actions , check = True )
1220+ _run_uv_install_with_retry (base_install_cmd , github_actions = github_actions , check = True )
11731221
11741222
11751223def _install_airflow_ctl_with_constraints (installation_spec : InstallationSpec , github_actions : bool ):
@@ -1192,13 +1240,13 @@ def _install_airflow_ctl_with_constraints(installation_spec: InstallationSpec, g
11921240 console .print (f"[bright_blue]Use constraints: { installation_spec .airflow_ctl_constraints_location } " )
11931241 install_airflow_ctl_cmd .extend (["--constraint" , installation_spec .airflow_ctl_constraints_location ])
11941242 console .print ()
1195- result = run_command (install_airflow_ctl_cmd , github_actions = github_actions , check = True )
1243+ result = _run_uv_install_with_retry (install_airflow_ctl_cmd , github_actions = github_actions , check = False )
11961244 if result .returncode != 0 :
11971245 console .print (
11981246 "[warning]Installation with constraints failed - might be because there are"
11991247 " conflicting dependencies in PyPI. Falling back to a non-constraint installation."
12001248 )
1201- run_command (base_install_airflow_ctl_cmd , github_actions = github_actions , check = True )
1249+ _run_uv_install_with_retry (base_install_airflow_ctl_cmd , github_actions = github_actions , check = True )
12021250
12031251
12041252def _install_only_airflow_airflow_core_task_sdk_with_constraints (
@@ -1247,13 +1295,13 @@ def _install_only_airflow_airflow_core_task_sdk_with_constraints(
12471295 console .print (f"[bright_blue]Use constraints: { installation_spec .airflow_constraints_location } " )
12481296 install_airflow_cmd .extend (["--constraint" , installation_spec .airflow_constraints_location ])
12491297 console .print ()
1250- result = run_command (install_airflow_cmd , github_actions = github_actions , check = False )
1298+ result = _run_uv_install_with_retry (install_airflow_cmd , github_actions = github_actions , check = False )
12511299 if result .returncode != 0 :
12521300 console .print (
12531301 "[warning]Installation with constraints failed - might be because pre-installed provider"
12541302 " has conflicting dependencies in PyPI. Falling back to a non-constraint installation."
12551303 )
1256- run_command (base_install_airflow_cmd , github_actions = github_actions , check = True )
1304+ _run_uv_install_with_retry (base_install_airflow_cmd , github_actions = github_actions , check = True )
12571305
12581306
12591307if __name__ == "__main__" :
0 commit comments