@@ -407,33 +407,57 @@ async fn unmount_fs(repo: &str, cl: Option<&str>) -> Result<bool, Box<dyn Error
407407 Ok ( true )
408408}
409409
410+ /// Since buck2 targets needs to statx every directory,
411+ /// which is extremely time-consuming on FUSE, we are using ls first to pre-warm the metadata cache.
412+ /// The targets logic will be migrated to the monolith later.
413+ // TODO: Rewrite the targets logic.
414+ fn preheat ( repo_path : & Path ) -> anyhow:: Result < ( ) > {
415+ let preheat_status = std:: process:: Command :: new ( "ls" )
416+ . arg ( "-lR" )
417+ . current_dir ( repo_path)
418+ . stdout ( std:: process:: Stdio :: null ( ) )
419+ . stderr ( std:: process:: Stdio :: null ( ) )
420+ . status ( ) ?;
421+
422+ if !preheat_status. success ( ) {
423+ tracing:: warn!( "Preheat command finished with non-zero status, continuing anyway..." ) ;
424+ }
425+ Ok ( ( ) )
426+ }
427+
410428/// Get target of a specific repo under tmp directory.
411429fn get_repo_targets ( file_name : & str , repo_path : & Path ) -> anyhow:: Result < Targets > {
412430 tracing:: debug!( "Get targets for repo {repo_path:?}" ) ;
431+ preheat ( repo_path) ?;
413432 let mut command = std:: process:: Command :: new ( "buck2" ) ;
414433 command. args ( targets_arguments ( ) ) ;
415434 command. current_dir ( repo_path) ;
416435 let ( mut child, stdout) = spawn ( command) ?;
417- let mut writer = file_writer ( Path :: new ( file_name) ) ?;
436+ let jsonl_path = PathBuf :: from ( repo_path) . join ( file_name) ;
437+ let mut writer = file_writer ( & jsonl_path) ?;
418438 std:: io:: copy ( & mut BufReader :: new ( stdout) , & mut writer)
419439 . map_err ( |err| anyhow ! ( "Failed to copy output to stdout: {}" , err) ) ?;
420440 writer
421441 . flush ( )
422442 . map_err ( |err| anyhow ! ( "Failed to flush writer: {}" , err) ) ?;
423443 child. wait ( ) ?;
424- Targets :: from_file ( Path :: new ( file_name ) )
444+ Targets :: from_file ( & jsonl_path )
425445}
426446
427447/// Run buck2-change-detector to get targets to build.
428448///
429449/// # Note
430450/// `mount_point` must be a mounted repository or CL path.
431451async fn get_build_targets (
452+ old_repo_mount_point : & str ,
432453 mount_point : & str ,
433454 mega_changes : Vec < Status < ProjectRelativePath > > ,
434455) -> anyhow:: Result < Vec < TargetLabel > > {
435456 tracing:: info!( "Get cells at {:?}" , mount_point) ;
436457 let mount_path = PathBuf :: from ( mount_point) ;
458+ let old_repo = PathBuf :: from ( old_repo_mount_point) ;
459+ tracing:: debug!( "Analyzing changes {mega_changes:?}" ) ;
460+
437461 let mut buck2 = Buck2 :: with_root ( "buck2" . to_string ( ) , mount_path. clone ( ) ) ;
438462 let mut cells = CellInfo :: parse (
439463 & buck2
@@ -448,11 +472,13 @@ async fn get_build_targets(
448472 . map_err ( |err| anyhow ! ( "Fail to get config: {}" , err) ) ?,
449473 ) ?;
450474
451- let base = get_repo_targets ( "base.jsonl" , & mount_path ) ?;
475+ let base = get_repo_targets ( "base.jsonl" , & old_repo ) ?;
452476 let changes = Changes :: new ( & cells, mega_changes) ?;
477+ tracing:: debug!( "Changes {changes:?}" ) ;
453478 let diff = get_repo_targets ( "diff.jsonl" , & mount_path) ?;
454479
455480 tracing:: debug!( "Base targets number: {}" , base. len_targets_upperbound( ) ) ;
481+ tracing:: debug!( "Diff targets number: {}" , diff. len_targets_upperbound( ) ) ;
456482
457483 let immediate = diff:: immediate_target_changes ( & base, & diff, & changes, false ) ;
458484 let recursive = diff:: recursive_target_changes ( & diff, & changes, & immediate, None , |_| true ) ;
@@ -543,35 +569,35 @@ pub async fn build(
543569 sender : UnboundedSender < WSMessage > ,
544570 changes : Vec < Status < ProjectRelativePath > > ,
545571) -> Result < ExitStatus , Box < dyn Error + Send + Sync > > {
546- tracing:: info!( "[Task {}] Building in repo '{}' " , id, repo ) ;
572+ tracing:: info!( "[Task {}] Building in repo / " , id) ;
547573
548574 // Mount the repository root requested by the task so target discovery matches repo layout.
549575 // Handle empty cl string as None to mount the base repo without a CL layer.
550576 let cl_trimmed = cl. trim ( ) ;
551577 let cl_arg = ( !cl_trimmed. is_empty ( ) ) . then_some ( cl_trimmed) ;
552- let repo_path = {
553- let trimmed = repo. trim ( ) ;
554- if trimmed. is_empty ( ) || trimmed == "/" {
555- "/" . to_string ( )
556- } else {
557- let mut normalized = if trimmed. starts_with ( '/' ) {
558- trimmed. to_string ( )
559- } else {
560- format ! ( "/{trimmed}" )
561- } ;
562- normalized = normalized. trim_end_matches ( '/' ) . to_string ( ) ;
563- if normalized. is_empty ( ) {
564- "/" . to_string ( )
565- } else {
566- normalized
567- }
568- }
569- } ;
578+
579+ // We will analyze the whole repo
580+ let repo_path = "/" . to_string ( ) ;
581+ // Used to change ProjectRelativePath relative to root
582+ let repo_prefix = repo. strip_prefix ( "/" ) . unwrap_or ( & repo) ;
583+ let changes = changes
584+ . into_iter ( )
585+ . map ( |p| p. into_map ( |rp| ProjectRelativePath :: new ( repo_prefix) . join ( rp. as_str ( ) ) ) )
586+ . collect ( ) ;
587+
588+ // We should also mount the repo before cl, for build target analyzing.
589+ let id_for_old_repo = format ! ( "{id}-old" ) ;
590+ let ( old_repo_mount_point, mount_id_old_repo) =
591+ mount_antares_fs ( & id_for_old_repo, & repo_path, None ) . await ?;
592+ let mount_guard_old_repo = MountGuard :: new ( mount_id_old_repo, id_for_old_repo) ;
593+
570594 let ( mount_point, mount_id) = mount_antares_fs ( & id, & repo_path, cl_arg) . await ?;
571595 let mount_guard = MountGuard :: new ( mount_id. clone ( ) , id. clone ( ) ) ;
572596
597+ tracing:: info!( "[Task {}] Filesystem mounted successfully." , id) ;
598+
573599 let build_result = async {
574- let targets = match get_build_targets ( & mount_point, changes) . await {
600+ let targets = match get_build_targets ( & old_repo_mount_point , & mount_point, changes) . await {
575601 Ok ( targets) => targets,
576602 Err ( e) => {
577603 let error_msg = format ! ( "Error getting build targets: {}" , e) ;
@@ -588,8 +614,6 @@ pub async fn build(
588614 }
589615 } ;
590616
591- tracing:: info!( "[Task {}] Filesystem mounted successfully." , id) ;
592-
593617 let mut cmd = Command :: new ( "buck2" ) ;
594618 let cmd = cmd
595619 . arg ( "build" )
@@ -669,6 +693,7 @@ pub async fn build(
669693 . await ;
670694
671695 mount_guard. unmount ( ) . await ;
696+ mount_guard_old_repo. unmount ( ) . await ;
672697
673698 build_result
674699}
0 commit comments