|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | 5 | import asyncio |
| 6 | +import errno |
6 | 7 | import shutil |
| 8 | +import stat |
7 | 9 | import sys |
8 | 10 | import warnings |
9 | 11 | from contextlib import asynccontextmanager |
10 | 12 | from pathlib import Path |
11 | | -from typing import TYPE_CHECKING, AsyncGenerator |
| 13 | +from typing import TYPE_CHECKING, AsyncGenerator, Callable |
12 | 14 | from urllib.parse import urlparse |
13 | 15 |
|
14 | 16 | from gitingest.clone import clone_repo |
|
22 | 24 | from gitingest.utils.query_parser_utils import KNOWN_GIT_HOSTS |
23 | 25 |
|
24 | 26 | if TYPE_CHECKING: |
| 27 | + from types import TracebackType |
| 28 | + |
25 | 29 | from gitingest.schemas import IngestionQuery |
26 | 30 |
|
27 | 31 |
|
@@ -254,11 +258,32 @@ async def _clone_repo_if_remote(query: IngestionQuery, *, token: str | None) -> |
254 | 258 | try: |
255 | 259 | yield |
256 | 260 | finally: |
257 | | - shutil.rmtree(query.local_path.parent) |
| 261 | + shutil.rmtree(query.local_path.parent, onerror=_handle_remove_readonly) |
258 | 262 | else: |
259 | 263 | yield |
260 | 264 |
|
261 | 265 |
|
| 266 | +def _handle_remove_readonly( |
| 267 | + func: Callable, |
| 268 | + path: str, |
| 269 | + exc_info: tuple[type[BaseException], BaseException, TracebackType], |
| 270 | +) -> None: |
| 271 | + """Handle permission errors raised by ``shutil.rmtree()``. |
| 272 | +
|
| 273 | + * Makes the target writable (removes the read-only attribute). |
| 274 | + * Retries the original operation (``func``) once. |
| 275 | +
|
| 276 | + """ |
| 277 | + exc = exc_info[1] |
| 278 | + # Handle only'Permission denied' and 'Operation not permitted' |
| 279 | + if not isinstance(exc, OSError) or exc.errno not in {errno.EACCES, errno.EPERM}: |
| 280 | + raise exc |
| 281 | + |
| 282 | + # Make the target writable |
| 283 | + Path(path).chmod(stat.S_IWRITE) |
| 284 | + func(path) |
| 285 | + |
| 286 | + |
262 | 287 | async def _write_output(tree: str, content: str, target: str | None) -> None: |
263 | 288 | """Write combined output to ``target`` (``"-"`` ⇒ stdout). |
264 | 289 |
|
|
0 commit comments