@@ -14,6 +14,7 @@ use serde::Serialize;
14
14
use std:: borrow:: Cow ;
15
15
use std:: env;
16
16
use std:: fmt;
17
+ use std:: fs;
17
18
use std:: path:: { Path , PathBuf } ;
18
19
use std:: process:: Command ;
19
20
use std:: str;
@@ -812,6 +813,8 @@ pub fn fetch(
812
813
// request we're about to issue.
813
814
maybe_gc_repo ( repo) ?;
814
815
816
+ clean_repo_temp_files ( repo) ;
817
+
815
818
// Translate the reference desired here into an actual list of refspecs
816
819
// which need to get fetched. Additionally record if we're fetching tags.
817
820
let mut refspecs = Vec :: new ( ) ;
@@ -1001,6 +1004,43 @@ fn maybe_gc_repo(repo: &mut git2::Repository) -> CargoResult<()> {
1001
1004
reinitialize ( repo)
1002
1005
}
1003
1006
1007
+ /// Removes temporary files left from previous activity.
1008
+ ///
1009
+ /// If libgit2 is interrupted while indexing pack files, it will leave behind
1010
+ /// some temporary files that it doesn't clean up. These can be quite large in
1011
+ /// size, so this tries to clean things up.
1012
+ ///
1013
+ /// This intentionally ignores errors. This is only an opportunistic cleaning,
1014
+ /// and we don't really care if there are issues (there's unlikely anything
1015
+ /// that can be done).
1016
+ ///
1017
+ /// The git CLI has similar behavior (its temp files look like
1018
+ /// `objects/pack/tmp_pack_9kUSA8`). Those files are normally deleted via `git
1019
+ /// prune` which is run by `git gc`. However, it doesn't know about libgit2's
1020
+ /// filenames, so they never get cleaned up.
1021
+ fn clean_repo_temp_files ( repo : & git2:: Repository ) {
1022
+ let path = repo. path ( ) . join ( "objects/pack/pack_git2_*" ) ;
1023
+ let pattern = match path. to_str ( ) {
1024
+ Some ( p) => p,
1025
+ None => {
1026
+ log:: warn!( "cannot convert {path:?} to a string" ) ;
1027
+ return ;
1028
+ }
1029
+ } ;
1030
+ let paths = match glob:: glob ( pattern) {
1031
+ Ok ( paths) => paths,
1032
+ Err ( _) => return ,
1033
+ } ;
1034
+ for path in paths {
1035
+ if let Ok ( path) = path {
1036
+ match fs:: remove_file ( & path) {
1037
+ Ok ( _) => log:: debug!( "removed stale temp git file {path:?}" ) ,
1038
+ Err ( e) => log:: warn!( "failed to remove {path:?} while cleaning temp files: {e}" ) ,
1039
+ }
1040
+ }
1041
+ }
1042
+ }
1043
+
1004
1044
fn reinitialize ( repo : & mut git2:: Repository ) -> CargoResult < ( ) > {
1005
1045
// Here we want to drop the current repository object pointed to by `repo`,
1006
1046
// so we initialize temporary repository in a sub-folder, blow away the
0 commit comments