1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15+ import datetime
1516import errno
1617import filecmp
1718import glob
@@ -3073,8 +3074,13 @@ def _FastForward(self, head, ffonly=False, quiet=True):
30733074 raise GitError (f"{ self .name } merge { head } " , project = self .name )
30743075
30753076 def _InitGitDir (self , mirror_git = None , force_sync = False , quiet = False ):
3077+ # Prefix for temporary directories created during gitdir initialization.
3078+ TMP_GITDIR_PREFIX = ".tmp-project-initgitdir-"
30763079 init_git_dir = not os .path .exists (self .gitdir )
30773080 init_obj_dir = not os .path .exists (self .objdir )
3081+ tmp_gitdir = None
3082+ curr_gitdir = self .gitdir
3083+ curr_config = self .config
30783084 try :
30793085 # Initialize the bare repository, which contains all of the objects.
30803086 if init_obj_dir :
@@ -3094,27 +3100,33 @@ def _InitGitDir(self, mirror_git=None, force_sync=False, quiet=False):
30943100 # well.
30953101 if self .objdir != self .gitdir :
30963102 if init_git_dir :
3097- os .makedirs (self .gitdir )
3103+ os .makedirs (os .path .dirname (self .gitdir ), exist_ok = True )
3104+ tmp_gitdir = tempfile .mkdtemp (
3105+ prefix = TMP_GITDIR_PREFIX ,
3106+ dir = os .path .dirname (self .gitdir ),
3107+ )
3108+ curr_config = GitConfig .ForRepository (
3109+ gitdir = tmp_gitdir , defaults = self .manifest .globalConfig
3110+ )
3111+ curr_gitdir = tmp_gitdir
30983112
30993113 if init_obj_dir or init_git_dir :
31003114 self ._ReferenceGitDir (
3101- self .objdir , self . gitdir , copy_all = True
3115+ self .objdir , curr_gitdir , copy_all = True
31023116 )
31033117 try :
3104- self ._CheckDirReference (self .objdir , self . gitdir )
3118+ self ._CheckDirReference (self .objdir , curr_gitdir )
31053119 except GitError as e :
31063120 if force_sync :
3107- logger .error (
3108- "Retrying clone after deleting %s" , self .gitdir
3109- )
31103121 try :
3111- platform_utils .rmtree (os .path .realpath (self .gitdir ))
3112- if self .worktree and os .path .exists (
3113- os .path .realpath (self .worktree )
3114- ):
3115- platform_utils .rmtree (
3116- os .path .realpath (self .worktree )
3117- )
3122+ rm_dirs = (
3123+ tmp_gitdir ,
3124+ self .gitdir ,
3125+ self .worktree ,
3126+ )
3127+ for d in rm_dirs :
3128+ if d and os .path .exists (d ):
3129+ platform_utils .rmtree (os .path .realpath (d ))
31183130 return self ._InitGitDir (
31193131 mirror_git = mirror_git ,
31203132 force_sync = False ,
@@ -3165,18 +3177,21 @@ def _expanded_ref_dirs():
31653177 m = self .manifest .manifestProject .config
31663178 for key in ["user.name" , "user.email" ]:
31673179 if m .Has (key , include_defaults = False ):
3168- self . config .SetString (key , m .GetString (key ))
3180+ curr_config .SetString (key , m .GetString (key ))
31693181 if not self .manifest .EnableGitLfs :
3170- self . config .SetString (
3182+ curr_config .SetString (
31713183 "filter.lfs.smudge" , "git-lfs smudge --skip -- %f"
31723184 )
3173- self . config .SetString (
3185+ curr_config .SetString (
31743186 "filter.lfs.process" , "git-lfs filter-process --skip"
31753187 )
3176- self . config .SetBoolean (
3188+ curr_config .SetBoolean (
31773189 "core.bare" , True if self .manifest .IsMirror else None
31783190 )
31793191
3192+ if tmp_gitdir :
3193+ platform_utils .rename (tmp_gitdir , self .gitdir )
3194+ tmp_gitdir = None
31803195 if not init_obj_dir :
31813196 # The project might be shared (obj_dir already initialized), but
31823197 # such information is not available here. Instead of passing it,
@@ -3193,6 +3208,27 @@ def _expanded_ref_dirs():
31933208 if init_git_dir and os .path .exists (self .gitdir ):
31943209 platform_utils .rmtree (self .gitdir )
31953210 raise
3211+ finally :
3212+ # Clean up the temporary directory created during the process,
3213+ # as well as any stale ones left over from previous attempts.
3214+ if tmp_gitdir and os .path .exists (tmp_gitdir ):
3215+ platform_utils .rmtree (tmp_gitdir )
3216+
3217+ age_threshold = datetime .timedelta (days = 1 )
3218+ now = datetime .datetime .now ()
3219+ for tmp_dir in glob .glob (
3220+ os .path .join (
3221+ os .path .dirname (self .gitdir ), f"{ TMP_GITDIR_PREFIX } *"
3222+ )
3223+ ):
3224+ try :
3225+ mtime = datetime .datetime .fromtimestamp (
3226+ os .path .getmtime (tmp_dir )
3227+ )
3228+ if now - mtime > age_threshold :
3229+ platform_utils .rmtree (tmp_dir )
3230+ except OSError :
3231+ pass
31963232
31973233 def _UpdateHooks (self , quiet = False ):
31983234 if os .path .exists (self .objdir ):
0 commit comments