11import json
2+ import multiprocessing as mp
23import os
34import shlex
45import shutil
56import subprocess
67from dataclasses import dataclass , field
8+ from functools import partial
79from pathlib import Path
810from sys import platform
911from tempfile import NamedTemporaryFile
1012from typing import Any , Final
1113
1214from .allow import AllowedFeatures
1315from .errors import NixpkgsReviewError
14- from .utils import ROOT , escape_attr , info , sh , warn
16+ from .utils import ROOT , System , info , sh , warn
1517
1618
1719@dataclass
@@ -56,9 +58,9 @@ def is_test(self) -> bool:
5658
5759
5860def nix_shell (
59- attrs : list [str ],
61+ attrs_per_system : dict [ System , list [str ] ],
6062 cache_directory : Path ,
61- system : str ,
63+ local_system : str ,
6264 build_graph : str ,
6365 nix_path : str ,
6466 nixpkgs_config : Path ,
@@ -71,7 +73,10 @@ def nix_shell(
7173 raise RuntimeError (f"{ build_graph } not found in PATH" )
7274
7375 shell_file_args = build_shell_file_args (
74- cache_directory , attrs , system , nixpkgs_config
76+ cache_dir = cache_directory ,
77+ attrs_per_system = attrs_per_system ,
78+ local_system = local_system ,
79+ nixpkgs_config = nixpkgs_config ,
7580 )
7681 if sandbox :
7782 args = _nix_shell_sandbox (
@@ -266,28 +271,66 @@ def nix_eval(
266271 os .unlink (attr_json .name )
267272
268273
269- def nix_build (
274+ def nix_eval_thread (
275+ system : System ,
270276 attr_names : set [str ],
277+ allow : AllowedFeatures ,
278+ nix_path : str ,
279+ ) -> tuple [System , list [Attr ]]:
280+ return system , nix_eval (attr_names , system , allow , nix_path )
281+
282+
283+ def multi_system_eval (
284+ attr_names_per_system : dict [System , set [str ]],
285+ allow : AllowedFeatures ,
286+ nix_path : str ,
287+ n_procs : int ,
288+ ) -> dict [System , list [Attr ]]:
289+ nix_eval_partial = partial (
290+ nix_eval_thread ,
291+ allow = allow ,
292+ nix_path = nix_path ,
293+ )
294+
295+ args : list [tuple [System , set [str ]]] = list (attr_names_per_system .items ())
296+ with mp .Pool (n_procs ) as pool :
297+ results : list [tuple [System , list [Attr ]]] = pool .starmap (nix_eval_partial , args )
298+
299+ return {system : attrs for system , attrs in results }
300+
301+
302+ def nix_build (
303+ attr_names_per_system : dict [System , set [str ]],
271304 args : str ,
272305 cache_directory : Path ,
273- system : str ,
306+ systems : set [System ],
307+ local_system : System ,
274308 allow : AllowedFeatures ,
275309 build_graph : str ,
276310 nix_path : str ,
277311 nixpkgs_config : Path ,
278- ) -> list [Attr ]:
279- if not attr_names :
312+ n_procs_eval : int ,
313+ ) -> dict [System , list [Attr ]]:
314+ if not attr_names_per_system :
280315 info ("Nothing to be built." )
281- return []
316+ return {}
282317
283- attrs = nix_eval (attr_names , system , allow , nix_path )
284- filtered = []
285- for attr in attrs :
286- if not (attr .broken or attr .blacklisted ):
287- filtered .append (attr .name )
318+ attrs_per_system : dict [System , list [Attr ]] = multi_system_eval (
319+ attr_names_per_system ,
320+ allow ,
321+ nix_path ,
322+ n_procs = n_procs_eval ,
323+ )
288324
289- if len (filtered ) == 0 :
290- return attrs
325+ filtered_per_system : dict [System , list [str ]] = {}
326+ for system , attrs in attrs_per_system .items ():
327+ filtered_per_system [system ] = []
328+ for attr in attrs :
329+ if not (attr .broken or attr .blacklisted ):
330+ filtered_per_system [system ].append (attr .name )
331+
332+ if all (len (filtered ) == 0 for filtered in filtered_per_system .values ()):
333+ return attrs_per_system
291334
292335 command = [
293336 build_graph ,
@@ -314,26 +357,37 @@ def nix_build(
314357 ]
315358
316359 command += build_shell_file_args (
317- cache_directory , filtered , system , nixpkgs_config
360+ cache_dir = cache_directory ,
361+ attrs_per_system = filtered_per_system ,
362+ local_system = local_system ,
363+ nixpkgs_config = nixpkgs_config ,
318364 ) + shlex .split (args )
319365
320366 sh (command )
321- return attrs
367+ return attrs_per_system
322368
323369
324370def build_shell_file_args (
325- cache_dir : Path , attrs : list [str ], system : str , nixpkgs_config : Path
371+ cache_dir : Path ,
372+ attrs_per_system : dict [System , list [str ]],
373+ local_system : str ,
374+ nixpkgs_config : Path ,
326375) -> list [str ]:
327376 attrs_file = cache_dir .joinpath ("attrs.nix" )
328377 with open (attrs_file , "w+" , encoding = "utf-8" ) as f :
329- f .write ("pkgs: with pkgs; [\n " )
330- f .write ("\n " .join (f" { escape_attr (a )} " for a in attrs ))
331- f .write ("\n ]" )
378+ f .write ("{\n " )
379+ for system , attrs in attrs_per_system .items ():
380+ f .write (f" { system } = [\n " )
381+ for attr in attrs :
382+ f .write (f' "{ attr } "\n ' )
383+ f .write (" ];\n " )
384+ f .write ("}" )
385+ print (f .read ())
332386
333387 return [
334388 "--argstr" ,
335- "system" ,
336- system ,
389+ "local- system" ,
390+ local_system ,
337391 "--argstr" ,
338392 "nixpkgs-path" ,
339393 str (cache_dir .joinpath ("nixpkgs/" )),
0 commit comments