From da44d4267e7d298b4f662b1bdda2f2edac59ad33 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 22 May 2019 11:04:35 -0700 Subject: [PATCH] Fix rmtree for readonly directories --- pre_commit/util.py | 5 +++-- tests/util_test.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pre_commit/util.py b/pre_commit/util.py index 4c390289..eb5411fd 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -158,13 +158,14 @@ def cmd_output(*cmd, **kwargs): def rmtree(path): """On windows, rmtree fails for readonly dirs.""" - def handle_remove_readonly(func, path, exc): # pragma: no cover (windows) + def handle_remove_readonly(func, path, exc): excvalue = exc[1] if ( func in (os.rmdir, os.remove, os.unlink) and excvalue.errno == errno.EACCES ): - os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + for p in (path, os.path.dirname(path)): + os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR) func(path) else: raise diff --git a/tests/util_test.py b/tests/util_test.py index 94c6ae63..c9838c55 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals import os.path +import stat import pytest @@ -8,6 +9,7 @@ from pre_commit.util import CalledProcessError from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output from pre_commit.util import parse_version +from pre_commit.util import rmtree from pre_commit.util import tmpdir @@ -90,3 +92,14 @@ def test_parse_version(): assert parse_version('0.0') == parse_version('0.0') assert parse_version('0.1') > parse_version('0.0') assert parse_version('2.1') >= parse_version('2') + + +def test_rmtree_read_only_directories(tmpdir): + """Simulates the go module tree. See #1042""" + tmpdir.join('x/y/z').ensure_dir().join('a').ensure() + mode = os.stat(str(tmpdir.join('x'))).st_mode + mode_no_w = mode & ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH) + tmpdir.join('x/y/z').chmod(mode_no_w) + tmpdir.join('x/y/z').chmod(mode_no_w) + tmpdir.join('x/y/z').chmod(mode_no_w) + rmtree(str(tmpdir.join('x')))