@@ -266,121 +266,6 @@ pub async fn execute_command(command: &str, suppress_error: bool) -> String {
266266 stdout. to_string ( )
267267}
268268
269- fn save_commit_map (
270- file_commit_map : & HashMap < String , String > ,
271- ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
272- let commit_map_path = "/tmp/commit_map.json" ;
273- let file = File :: create ( commit_map_path) ?;
274- serde_json:: to_writer ( file, file_commit_map) ?;
275- println ! ( "Commit map saved to: {}" , commit_map_path) ;
276- Ok ( ( ) )
277- }
278-
279- fn delete_except ( files : & str , base_dir : & Path ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
280- println ! ( "Deleting all files except the following:" ) ;
281- println ! ( "__________________________________________ {:?}" , files) ;
282- let files_to_keep: Vec < PathBuf > = files
283- . lines ( )
284- . map ( |line| base_dir. join ( line. trim ( ) ) )
285- . collect ( ) ;
286-
287- traverse_and_delete ( base_dir, & files_to_keep) ?;
288-
289- Ok ( ( ) )
290- }
291-
292- fn traverse_and_delete ( base_dir : & Path , files_to_keep : & [ PathBuf ] ) -> Result < ( ) , std:: io:: Error > {
293- for entry in fs:: read_dir ( base_dir) ? {
294- let entry = entry?;
295- let path = entry. path ( ) ;
296-
297- // Skip the .git directory
298- if path. is_dir ( ) && path. file_name ( ) . map_or ( false , |name| name == ".git" ) {
299- continue ;
300- }
301-
302- if path. is_dir ( ) {
303- traverse_and_delete ( & path, files_to_keep) ?;
304- }
305-
306- // Check if the path should be deleted (only delete files)
307- if path. is_file ( ) && !files_to_keep. contains ( & path. canonicalize ( ) ?) {
308- fs:: remove_file ( & path) ?;
309- }
310- }
311-
312- Ok ( ( ) )
313- }
314-
315- fn delete_empty_directories ( start_dir : & Path ) -> Result < ( ) , std:: io:: Error > {
316- for entry in fs:: read_dir ( start_dir) ? {
317- let entry = entry?;
318- let path = entry. path ( ) ;
319-
320- // Skip the .git directory
321- if path. is_dir ( ) && path. file_name ( ) . map_or ( false , |name| name == ".git" ) {
322- continue ;
323- }
324-
325- if path. is_dir ( ) {
326- delete_empty_directories ( & path) ?;
327- if fs:: read_dir ( & path) ?. next ( ) . is_none ( ) {
328- fs:: remove_dir ( & path) ?;
329- }
330- }
331- }
332-
333- Ok ( ( ) )
334- }
335-
336- fn get_cumulative_pr_files (
337- base_branch : Option < & str > ,
338- pr_branch : Option < & str > ,
339- ) -> Result < Vec < String > , Box < dyn std:: error:: Error > > {
340- if let Some ( base) = base_branch {
341- // Step 1: Create and checkout a temporary branch from the base branch
342- Command :: new ( "git" ) . args ( & [ "checkout" , base] ) . output ( ) ?;
343- Command :: new ( "git" )
344- . args ( & [ "checkout" , "-b" , "temp_pr_merge_branch" ] )
345- . output ( ) ?;
346-
347- if let Some ( pr) = pr_branch {
348- // Step 2: Merge the PR branch without fast-forwarding
349- let merge_output = Command :: new ( "git" )
350- . args ( & [ "merge" , "--no-ff" , pr] )
351- . output ( ) ?;
352- if !merge_output. status . success ( ) {
353- let error_msg = String :: from_utf8_lossy ( & merge_output. stderr ) ;
354- return Err ( format ! ( "Failed to merge PR branch: {}" , error_msg) . into ( ) ) ;
355- }
356-
357- // Step 3: Get the list of changed files in the cumulative diff
358- let output = Command :: new ( "git" )
359- . args ( & [ "diff" , "--name-only" , base, "temp_pr_merge_branch" ] )
360- . output ( ) ?;
361- if !output. status . success ( ) {
362- let error_msg = String :: from_utf8_lossy ( & output. stderr ) ;
363- return Err ( format ! ( "Failed to get cumulative PR files: {}" , error_msg) . into ( ) ) ;
364- }
365-
366- let files = String :: from_utf8_lossy ( & output. stdout ) ;
367- let file_names = files. lines ( ) . map ( String :: from) . collect ( ) ;
368-
369- // Cleanup: Delete the temporary branch
370- Command :: new ( "git" ) . args ( & [ "checkout" , base] ) . output ( ) ?;
371- Command :: new ( "git" )
372- . args ( & [ "branch" , "-D" , "temp_pr_merge_branch" ] )
373- . output ( ) ?;
374-
375- Ok ( file_names)
376- } else {
377- Err ( "PR branch is required when base branch is specified." . into ( ) )
378- }
379- } else {
380- Err ( "Base branch is required." . into ( ) )
381- }
382- }
383-
384269pub fn checkout (
385270 clone_url : & str ,
386271 clone_path : & str ,
@@ -401,16 +286,20 @@ pub fn checkout(
401286
402287 // Set the working directory to the cloned path
403288 let cloned_path = Path :: new ( clone_path) . canonicalize ( ) ?;
289+ let repo_path = cloned_path. to_str ( ) . unwrap ( ) ;
404290 env:: set_current_dir ( & cloned_path) ?;
405291
406292 // Configure Git user for commits in this repository
407293 Command :: new ( "git" )
408- . args ( & [ "config" , "user.email" , "ci@hela.int " ] )
294+ . args ( & [ "config" , "user.email" , "ci@example.com " ] )
409295 . output ( ) ?;
410296 Command :: new ( "git" )
411297 . args ( & [ "config" , "user.name" , "CI Bot" ] )
412298 . output ( ) ?;
413299
300+ // Store the set of changed files
301+ let mut changed_files = HashSet :: new ( ) ;
302+
414303 // If a pr_branch is provided, fetch it as a local branch and compare with the base branch
415304 if let Some ( pr_branch_name) = pr_branch {
416305 // Fetch the PR branch and create a local branch
@@ -441,16 +330,11 @@ pub fn checkout(
441330 return Err ( format ! ( "Failed to diff branches: {}" , error_msg) . into ( ) ) ;
442331 }
443332
444- // Parse the diff output
445- let changed_files = String :: from_utf8_lossy ( & diff_output. stdout )
446- . lines ( )
447- . map ( String :: from)
448- . collect :: < Vec < String > > ( ) ;
449-
450- println ! (
451- "Changed files in PR branch '{}': {:?}" ,
452- pr_branch_name, changed_files
453- ) ;
333+ // Parse the diff output into a set of changed files
334+ let diff_output_str = String :: from_utf8_lossy ( & diff_output. stdout ) ;
335+ for line in diff_output_str. lines ( ) {
336+ changed_files. insert ( line. trim ( ) . to_string ( ) ) ;
337+ }
454338 } else {
455339 // If no PR branch, list all files in the base branch
456340 let list_output = Command :: new ( "git" )
@@ -462,18 +346,79 @@ pub fn checkout(
462346 return Err ( format ! ( "Failed to list files in base branch: {}" , error_msg) . into ( ) ) ;
463347 }
464348
465- let files = String :: from_utf8_lossy ( & list_output. stdout )
466- . lines ( )
467- . map ( String :: from)
468- . collect :: < Vec < String > > ( ) ;
349+ // Parse the list output into a set of files
350+ let list_output_str = String :: from_utf8_lossy ( & list_output. stdout ) ;
351+ for line in list_output_str. lines ( ) {
352+ changed_files. insert ( line. trim ( ) . to_string ( ) ) ;
353+ }
354+ }
355+
356+ // Print the changed files for debugging purposes
357+ println ! ( "Changed files:\n {:#?}" , changed_files) ;
469358
470- println ! (
471- "Files in branch '{}': {:?}" ,
472- branch. unwrap_or( "default branch" ) ,
473- files
474- ) ;
359+ // Ensure the working directory is up-to-date before checking out files
360+ Command :: new ( "git" )
361+ . args ( & [ "checkout" , pr_branch. unwrap_or ( "HEAD" ) ] )
362+ . output ( ) ?;
363+
364+ // Ensure each changed file is checked out from the PR branch
365+ for file in & changed_files {
366+ let checkout_output = Command :: new ( "git" )
367+ . args ( & [ "checkout" , pr_branch. unwrap_or ( "HEAD" ) , "--" , file] )
368+ . output ( ) ?;
369+
370+ if !checkout_output. status . success ( ) {
371+ let error_msg = String :: from_utf8_lossy ( & checkout_output. stderr ) ;
372+ println ! ( "Failed to checkout file '{}': {}" , file, error_msg) ;
373+ }
475374 }
476375
376+ // Remove all files not in the `changed_files` set
377+ remove_unwanted_files ( repo_path, & changed_files) ?;
378+
379+ println ! ( "Only the changed files have been kept locally." ) ;
380+
381+ Ok ( ( ) )
382+ }
383+
384+ /// Removes all files that are not in the `files_to_keep` set, but preserves directories.
385+ ///
386+ /// # Arguments
387+ ///
388+ /// * `repo_path` - The path of the repository.
389+ /// * `files_to_keep` - A set of file paths to keep relative to the `repo_path`.
390+ fn remove_unwanted_files (
391+ repo_path : & str ,
392+ files_to_keep : & HashSet < String > ,
393+ ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
394+ // Recursively remove unwanted files
395+ for entry in fs:: read_dir ( repo_path) ? {
396+ let entry = entry?;
397+ let path = entry. path ( ) ;
398+
399+ // Skip the .git directory to preserve repository integrity
400+ if path. is_dir ( ) && path. file_name ( ) . map_or ( false , |name| name == ".git" ) {
401+ continue ;
402+ }
403+
404+ // Determine the relative path
405+ let relative_path = path. strip_prefix ( repo_path) ?. to_str ( ) . unwrap ( ) . to_string ( ) ;
406+
407+ // Check if the file should be kept or removed
408+ if path. is_file ( ) && !files_to_keep. contains ( & relative_path) {
409+ println ! ( "Removing file: {}" , relative_path) ;
410+ fs:: remove_file ( & path) ?;
411+ } else if path. is_dir ( ) {
412+ // Recursively clean up subdirectories
413+ remove_unwanted_files ( path. to_str ( ) . unwrap ( ) , files_to_keep) ?;
414+
415+ // Check if the directory is empty and remove it
416+ if fs:: read_dir ( & path) ?. next ( ) . is_none ( ) {
417+ println ! ( "Removing empty directory: {}" , relative_path) ;
418+ fs:: remove_dir ( & path) ?;
419+ }
420+ }
421+ }
477422 Ok ( ( ) )
478423}
479424
0 commit comments