diff --git a/qmk_cli/helpers.py b/qmk_cli/helpers.py index 35c704e..2865c51 100644 --- a/qmk_cli/helpers.py +++ b/qmk_cli/helpers.py @@ -1,7 +1,10 @@ """Useful helper functions. """ import os +import sys +import stat import json +import shutil from functools import lru_cache from pathlib import Path @@ -18,6 +21,20 @@ def AbsPath(arg): # noqa: N802 return arg +def rmtree(path): + """Safe version of shutil.rmtree which handles errors on Windows where some of the files have their read-only bit set.""" + def remove_readonly(func, path, _): + """Clear the readonly bit and reattempt the removal.""" + os.chmod(path, stat.S_IWRITE) + func(path) + + if sys.version_info >= (3, 12): + # See https://docs.python.org/3.12/whatsnew/3.12.html#shutil + return shutil.rmtree(path, onexc=remove_readonly) + else: + return shutil.rmtree(path, onerror=remove_readonly) + + def is_qmk_firmware(qmk_firmware): """Returns True if the given Path() is a qmk_firmware clone. """ diff --git a/qmk_cli/subcommands/setup.py b/qmk_cli/subcommands/setup.py index fbc655c..a13566c 100644 --- a/qmk_cli/subcommands/setup.py +++ b/qmk_cli/subcommands/setup.py @@ -5,12 +5,11 @@ import shlex import subprocess import sys from pathlib import Path -from shutil import rmtree from milc import cli from milc.questions import choice, question, yesno from qmk_cli.git import git_clone -from qmk_cli.helpers import AbsPath, is_qmk_firmware +from qmk_cli.helpers import AbsPath, is_qmk_firmware, rmtree default_base = 'https://github.com' default_repo = 'qmk_firmware'