11import argparse
2- import concurrent .futures
2+ import json
3+ import multiprocessing
34import os
45import subprocess
56import sys
89from enum import Enum
910from pathlib import Path
1011from re import Pattern
11- from typing import IO
12+ from typing import IO , Any
1213from xml .etree import ElementTree as ET
1314
15+ from . import eval_ci
1416from .allow import AllowedFeatures
1517from .builddir import Builddir
1618from .errors import NixpkgsReviewError
@@ -207,7 +209,10 @@ def apply_unstaged(self, staged: bool = False) -> None:
207209 sys .exit (1 )
208210
209211 def build_commit (
210- self , base_commit : str , reviewed_commit : str | None , staged : bool = False
212+ self ,
213+ base_commit : str ,
214+ reviewed_commit : str | None ,
215+ staged : bool = False ,
211216 ) -> dict [System , list [Attr ]]:
212217 """
213218 Review a local git commit
@@ -216,45 +221,80 @@ def build_commit(
216221
217222 print ("Local evaluation for computing rebuilds" )
218223
219- # TODO: nix-eval-jobs ?
220- base_packages : dict [System , list [Package ]] = list_packages (
221- self .builddir .nix_path ,
222- self .systems ,
223- self .allow ,
224- n_threads = self .num_parallel_evals ,
225- )
224+ # Source: https://github.com/NixOS/nixpkgs/blob/master/ci/eval/README.md
225+ # TODO: make those overridable
226+ max_jobs : int = len (self .systems )
227+ n_cores : int = multiprocessing .cpu_count () // max_jobs
228+ chunk_size : int = 10_000
229+
230+ with tempfile .TemporaryDirectory () as temp_dir :
231+ before_dir : str = str (temp_dir / Path ("before_eval_results" ))
232+ after_dir : str = str (temp_dir / Path ("after_eval_results" ))
233+ # TODO: handle `self.allow` settings
234+ eval_ci .local_eval (
235+ worktree_dir = self .builddir .worktree_dir ,
236+ systems = self .systems ,
237+ max_jobs = max_jobs ,
238+ n_cores = n_cores ,
239+ chunk_size = chunk_size ,
240+ output_dir = before_dir ,
241+ )
226242
227- if reviewed_commit is None :
228- self .apply_unstaged (staged )
229- elif self .checkout == CheckoutOption .MERGE :
230- self .git_checkout (reviewed_commit )
231- else :
232- self .git_merge (reviewed_commit )
243+ if reviewed_commit is None :
244+ self .apply_unstaged (staged )
245+ elif self .checkout == CheckoutOption .MERGE :
246+ self .git_checkout (reviewed_commit )
247+ else :
248+ self .git_merge (reviewed_commit )
249+
250+ eval_ci .local_eval (
251+ worktree_dir = self .builddir .worktree_dir ,
252+ systems = self .systems ,
253+ max_jobs = max_jobs ,
254+ n_cores = n_cores ,
255+ chunk_size = chunk_size ,
256+ output_dir = after_dir ,
257+ )
233258
234- # TODO: nix-eval-jobs ?
235- merged_packages : dict [System , list [Package ]] = list_packages (
236- self .builddir .nix_path ,
237- self .systems ,
238- self .allow ,
239- n_threads = self .num_parallel_evals ,
240- check_meta = True ,
241- )
259+ # merged_packages: dict[System, list[Package]] = list_packages(
260+ # self.builddir.nix_path,
261+ # self.systems,
262+ # self.allow,
263+ # n_threads=self.num_parallel_evals,
264+ # check_meta=True,
265+ # )
266+
267+ output_dir : Path = temp_dir / Path ("comparison" )
268+ eval_ci .compare (
269+ worktree_dir = self .builddir .worktree_dir ,
270+ before_dir = before_dir ,
271+ after_dir = after_dir ,
272+ output_dir = str (output_dir ),
273+ )
274+
275+ with (output_dir / Path ("changed-paths.json" )).open () as compare_result :
276+ outpaths_dict : dict [str , Any ] = json .load (compare_result )
242277
243278 # Systems ordered correctly (x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin)
244279 sorted_systems : list [System ] = sorted (
245280 self .systems ,
246281 key = system_order_key ,
247282 reverse = True ,
248283 )
284+
249285 changed_attrs : dict [System , set [str ]] = {}
250286 for system in sorted_systems :
251- changed_pkgs , removed_pkgs = differences (
252- base_packages [system ], merged_packages [system ]
287+ print (f"--------- Rebuilds on '{ system } ' ---------" )
288+
289+ rebuilds : set [str ] = set (
290+ outpaths_dict ["rebuildsByPlatform" ].get (system , [])
291+ )
292+ print_packages (
293+ names = list (rebuilds ),
294+ msg = "to rebuild" ,
253295 )
254- print (f"--------- Impacted packages on '{ system } ' ---------" )
255- print_updates (changed_pkgs , removed_pkgs )
256296
257- changed_attrs [system ] = { p . attr_path for p in changed_pkgs }
297+ changed_attrs [system ] = rebuilds
258298
259299 return self .build (changed_attrs , self .build_args )
260300
@@ -451,70 +491,6 @@ def parse_packages_xml(stdout: IO[str]) -> list[Package]:
451491 return packages
452492
453493
454- def _list_packages_system (
455- system : System ,
456- nix_path : str ,
457- allow : AllowedFeatures ,
458- check_meta : bool = False ,
459- ) -> list [Package ]:
460- cmd = [
461- "nix-env" ,
462- "--extra-experimental-features" ,
463- "" if allow .url_literals else "no-url-literals" ,
464- "--option" ,
465- "system" ,
466- system ,
467- "-f" ,
468- "<nixpkgs>" ,
469- "--nix-path" ,
470- nix_path ,
471- "-qaP" ,
472- "--xml" ,
473- "--out-path" ,
474- "--show-trace" ,
475- "--allow-import-from-derivation"
476- if allow .ifd
477- else "--no-allow-import-from-derivation" ,
478- ]
479- if check_meta :
480- cmd .append ("--meta" )
481- info ("$ " + " " .join (cmd ))
482- with tempfile .NamedTemporaryFile (mode = "w" ) as tmp :
483- res = subprocess .run (cmd , stdout = tmp , check = False )
484- if res .returncode != 0 :
485- msg = f"Failed to list packages: nix-env failed with exit code { res .returncode } "
486- raise NixpkgsReviewError (msg )
487- tmp .flush ()
488- with Path (tmp .name ).open () as f :
489- return parse_packages_xml (f )
490-
491-
492- def list_packages (
493- nix_path : str ,
494- systems : set [System ],
495- allow : AllowedFeatures ,
496- n_threads : int ,
497- check_meta : bool = False ,
498- ) -> dict [System , list [Package ]]:
499- results : dict [System , list [Package ]] = {}
500- with concurrent .futures .ThreadPoolExecutor (max_workers = n_threads ) as executor :
501- future_to_system = {
502- executor .submit (
503- _list_packages_system ,
504- system = system ,
505- nix_path = nix_path ,
506- allow = allow ,
507- check_meta = check_meta ,
508- ): system
509- for system in systems
510- }
511- for future in concurrent .futures .as_completed (future_to_system ):
512- system = future_to_system [future ]
513- results [system ] = future .result ()
514-
515- return results
516-
517-
518494def package_attrs (
519495 package_set : set [str ],
520496 system : str ,
0 commit comments