Skip to content

fix: handle read-only .git objects on Windows in shutil.rmtree calls#91

Open
ryanfk wants to merge 2 commits intomicrosoft:mainfrom
ryanfk:fix/windows-rmtree-readonly-git-objects
Open

fix: handle read-only .git objects on Windows in shutil.rmtree calls#91
ryanfk wants to merge 2 commits intomicrosoft:mainfrom
ryanfk:fix/windows-rmtree-readonly-git-objects

Conversation

@ryanfk
Copy link

@ryanfk ryanfk commented Feb 19, 2026

Summary

  • On Windows, Git marks pack files and loose objects as read-only. When APM tries to remove a previously-cloned apm_modules directory or strip the .git folder after cloning, shutil.rmtree raises [WinError 5] Access is denied.
  • Adds a _remove_readonly error handler that clears the read-only flag before retrying the delete.
  • Wires the handler into all five shutil.rmtree calls in github_downloader.py, replacing both bare calls and ignore_errors=True (which silently left files behind on Windows).

Reproduction

apm install dev.azure.com/myorg/myproject/myrepo
# First install fails for any reason (e.g. wrong branch)
# Second install attempt hits:
# ❌ Failed to install myorg/myproject/myrepo: [WinError 5] Access is denied:
#    'C:\...\apm_modules\myorg\myproject\myrepo\.git\objects\02\...'

Fix

def _remove_readonly(func, path, _excinfo):
    """Clear read-only flag on Windows before retrying delete."""
    os.chmod(path, stat.S_IWRITE)
    func(path)

# Before:
shutil.rmtree(target_path)
# After:
shutil.rmtree(target_path, onerror=_remove_readonly)

Test plan

  • Verified on Windows 11 — apm install now succeeds after a previously failed install leaves read-only .git objects in apm_modules/
  • No-op on Linux/macOS — the onerror handler only triggers when the default delete fails, which doesn't happen on systems without read-only git objects

Fixes #90

🤖 Generated with Claude Code

Ryan Fiust-Klink and others added 2 commits February 19, 2026 16:48
Git marks pack files and loose objects as read-only. On Windows this
causes shutil.rmtree to raise [WinError 5] Access is denied when APM
tries to remove a previously-cloned apm_modules directory or strip the
.git folder after cloning.

Add a _remove_readonly error handler that clears the read-only flag
before retrying the delete, and wire it into every shutil.rmtree call
in github_downloader.py.

Fixes microsoft#90

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On Windows, GitPython may hold file handles on .git objects after
cloning.  This causes shutil.rmtree to fail with [WinError 32] when
cleaning up temporary directories.

Extend _remove_readonly to handle WinError 32 by triggering gc.collect()
to release GitPython handles, and explicitly close Repo objects before
temp directory cleanup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] apm install fails with [WinError 5] Access is denied on Windows when processing .git objects

1 participant

Comments