2424 options. It only scans arguments before Bazel's "--" delimiter for --jobs,
2525 and when --jobs is absent inserts the adaptive --jobs value immediately before
2626 that delimiter or at the end of the argument list.
27+ - Only adapt commands that accept --jobs: build, test, run, coverage, fetch,
28+ cquery, and aquery. Other Bazel commands are exec'd directly without adding or
29+ rewriting --jobs, so the wrapper can be used as a general Bazel entry point.
30+ The detector is conservative around unknown startup options with separate
31+ values; ambiguous commands pass through unchanged.
2732- Read the action timeout from BAZEL_ADAPTIVE_BUILD_TIMEOUT as a bare positive
2833 number of seconds; default to 150 seconds. This applies to builds and tests
2934 and is independent of Bazel's --test_timeout.
306311DEFAULT_ACTION_TIMEOUT_SECONDS = 150
307312BUILD_TIMEOUT_ENV = "BAZEL_ADAPTIVE_BUILD_TIMEOUT"
308313
314+ JOBS_COMMANDS = frozenset ({"build" , "test" , "run" , "coverage" , "fetch" , "cquery" , "aquery" })
315+
309316DEFAULT_LOW_MEMORY_THRESHOLD_MB = 1024
310317LOW_MEMORY_THRESHOLD_ENV = "BAZEL_ADAPTIVE_LOW_MEMORY_THRESHOLD_MB"
311318
@@ -624,6 +631,7 @@ class ParsedArgs:
624631 initial_jobs : int
625632 action_timeout : int
626633 job_locations : list [tuple [str , int ]]
634+ supports_jobs : bool
627635
628636
629637@dataclass
@@ -806,27 +814,44 @@ def bazel_option_end(args: list[str]) -> int:
806814 return len (args )
807815
808816
817+ def bazel_command_supports_jobs (args : list [str ]) -> bool :
818+ end = bazel_option_end (args )
819+ skip_possible_option_value = False
820+ for arg in args [:end ]:
821+ if skip_possible_option_value :
822+ skip_possible_option_value = False
823+ continue
824+ if arg .startswith ("-" ):
825+ if "=" not in arg :
826+ skip_possible_option_value = True
827+ continue
828+ return arg in JOBS_COMMANDS
829+ return False
830+
831+
809832# Parse Bazel arguments enough to find the initial jobs cap.
810833def parse_bazel_args (args : list [str ], action_timeout : int | None = None ) -> ParsedArgs :
811834 initial_jobs = None
812835 job_locations : list [tuple [str , int ]] = []
836+ supports_jobs = bazel_command_supports_jobs (args )
813837
814838 end = bazel_option_end (args )
815- i = 0
816- while i < end :
817- arg = args [i ]
818- if arg .startswith ("--jobs=" ):
819- job_locations .append (("equals" , i ))
820- parsed = jobs_value (arg .split ("=" , 1 )[1 ])
821- if parsed is not None :
822- initial_jobs = parsed
823- elif arg == "--jobs" and i + 1 < end :
824- job_locations .append (("separate" , i ))
825- parsed = jobs_value (args [i + 1 ])
826- if parsed is not None :
827- initial_jobs = parsed
839+ if supports_jobs :
840+ i = 0
841+ while i < end :
842+ arg = args [i ]
843+ if arg .startswith ("--jobs=" ):
844+ job_locations .append (("equals" , i ))
845+ parsed = jobs_value (arg .split ("=" , 1 )[1 ])
846+ if parsed is not None :
847+ initial_jobs = parsed
848+ elif arg == "--jobs" and i + 1 < end :
849+ job_locations .append (("separate" , i ))
850+ parsed = jobs_value (args [i + 1 ])
851+ if parsed is not None :
852+ initial_jobs = parsed
853+ i += 1
828854 i += 1
829- i += 1
830855
831856 if initial_jobs is None :
832857 initial_jobs = os .cpu_count () or 1
@@ -838,12 +863,15 @@ def parse_bazel_args(args: list[str], action_timeout: int | None = None) -> Pars
838863 initial_jobs = initial_jobs ,
839864 action_timeout = action_timeout ,
840865 job_locations = job_locations ,
866+ supports_jobs = supports_jobs ,
841867 )
842868
843869
844870# Return Bazel args with this attempt's concrete --jobs value applied.
845871def bazel_args_with_jobs (parsed : ParsedArgs , jobs : int ) -> list [str ]:
846872 bazel_args = list (parsed .original_args )
873+ if not parsed .supports_jobs :
874+ return bazel_args
847875 if parsed .job_locations :
848876 for kind , index in parsed .job_locations :
849877 if kind == "equals" :
@@ -3406,6 +3434,9 @@ def begin_upscale(next_jobs: int, running_actions_seconds: float | None) -> None
34063434
34073435# Retry Bazel attempts while adapting the current jobs value.
34083436def run_adaptive (bazel_path : str , parsed : ParsedArgs ) -> int :
3437+ if not parsed .supports_jobs :
3438+ os .execvpe (bazel_path , [bazel_path , * parsed .original_args ], os .environ )
3439+
34093440 jobs = parsed .initial_jobs
34103441 max_jobs = parsed .initial_jobs
34113442 context = BuildContext (os .getcwd ())
@@ -3576,6 +3607,9 @@ def main(argv: list[str]) -> int:
35763607 )
35773608 return normalize_returncode (exit_code )
35783609
3610+ if not bazel_command_supports_jobs (argv ):
3611+ os .execvpe (bazel_path , [bazel_path , * argv ], os .environ )
3612+
35793613 try :
35803614 action_timeout = build_timeout_from_env ()
35813615 low_memory_threshold_kb ()
0 commit comments