Skip to content

Commit 007bdea

Browse files
authored
Merge pull request #13 from conan-io/hotfix/windows-backup-remove
Remove read-only files on Windows
2 parents 3a72e1d + 3557828 commit 007bdea

File tree

5 files changed

+60
-8
lines changed

5 files changed

+60
-8
lines changed

patch_ng.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import posixpath
5757
import shutil
5858
import sys
59+
import stat
5960

6061

6162
PY3K = sys.version_info >= (3, 0)
@@ -178,6 +179,12 @@ def xstrip(filename):
178179
filename = re.sub(b'^[\\\\/]+', b'', filename)
179180
return filename
180181

182+
183+
def safe_unlink(filepath):
184+
os.chmod(filepath, stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)
185+
os.unlink(filepath)
186+
187+
181188
#-----------------------------------------------
182189
# Main API functions
183190

@@ -976,7 +983,7 @@ def apply(self, strip=0, root=None, fuzz=False):
976983
save(target, new_file)
977984
elif "dev/null" in target:
978985
source = self.strip_path(source, root, strip)
979-
os.unlink(source)
986+
safe_unlink(source)
980987
else:
981988
items.append(item)
982989
self.items = items
@@ -1106,12 +1113,12 @@ def apply(self, strip=0, root=None, fuzz=False):
11061113
shutil.move(filenamen, backupname)
11071114
if self.write_hunks(backupname if filenameo == filenamen else filenameo, filenamen, p.hunks):
11081115
info("successfully patched %d/%d:\t %s" % (i+1, total, filenamen))
1109-
os.unlink(backupname)
1116+
safe_unlink(backupname)
11101117
if new == b'/dev/null':
11111118
# check that filename is of size 0 and delete it.
11121119
if os.path.getsize(filenamen) > 0:
11131120
warning("expected patched file to be empty as it's marked as deletion:\t %s" % filenamen)
1114-
os.unlink(filenamen)
1121+
safe_unlink(filenamen)
11151122
else:
11161123
errors += 1
11171124
warning("error patching file %s" % filenamen)

tests/11permission/11permission.patch

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--- some_file
2+
+++ some_file
3+
@@ -2,6 +2,7 @@
4+
line 2
5+
line 3
6+
line 4
7+
+line 5
8+
line 6
9+
line 7
10+
line 8

tests/11permission/[result]/some_file

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
line 1
2+
line 2
3+
line 3
4+
line 4
5+
line 5
6+
line 6
7+
line 7
8+
line 8
9+
line 9
10+
line 10

tests/11permission/some_file

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
line 1
2+
line 2
3+
line 3
4+
line 4
5+
line 6
6+
line 7
7+
line 8
8+
line 9
9+
line 10

tests/run_tests.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
import shutil
3838
import unittest
3939
import copy
40-
from os import listdir
40+
import stat
41+
from os import listdir, chmod
4142
from os.path import abspath, dirname, exists, join, isdir, isfile
4243
from tempfile import mkdtemp
4344
try:
@@ -171,9 +172,7 @@ def _run_test(self, testname):
171172
self._assert_dirs_equal(join(basepath, "[result]"),
172173
tmpdir,
173174
ignore=["%s.patch" % testname, ".svn", ".gitkeep", "[result]"])
174-
175-
176-
shutil.rmtree(tmpdir)
175+
remove_tree_force(tmpdir)
177176
return 0
178177

179178

@@ -362,7 +361,7 @@ def setUp(self):
362361

363362
def tearDown(self):
364363
os.chdir(self.save_cwd)
365-
shutil.rmtree(self.tmpdir)
364+
remove_tree_force(self.tmpdir)
366365

367366
def tmpcopy(self, filenames):
368367
"""copy file(s) from test_dir to self.tmpdir"""
@@ -446,6 +445,17 @@ def test_fuzzy_patch_after(self):
446445
self.assertTrue(pto.apply(root=treeroot, fuzz=True))
447446
self.assertFalse(pto.apply(root=treeroot, fuzz=False))
448447

448+
def test_unlink_backup_windows(self):
449+
""" Apply patch to a read-only file and don't change its filemode
450+
"""
451+
treeroot = join(self.tmpdir, 'rootparent')
452+
shutil.copytree(join(TESTS, '11permission'), treeroot)
453+
pto = patch_ng.fromfile(join(TESTS, '11permission', '11permission.patch'))
454+
some_file = join(treeroot, 'some_file')
455+
chmod(some_file, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
456+
self.assertTrue(pto.apply(root=treeroot))
457+
self.assertTrue(os.stat(some_file).st_mode, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
458+
449459

450460
class TestHelpers(unittest.TestCase):
451461
# unittest setting
@@ -478,6 +488,12 @@ def test_pathstrip(self):
478488
self.assertEqual(patch_ng.pathstrip(b'path/name.diff', 1), b'name.diff')
479489
self.assertEqual(patch_ng.pathstrip(b'path/name.diff', 0), b'path/name.diff')
480490

491+
def remove_tree_force(folder):
492+
for root, _, files in os.walk(folder):
493+
for it in files:
494+
chmod(os.path.join(root, it), stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)
495+
shutil.rmtree(folder, ignore_errors=True)
496+
481497
# ----------------------------------------------------------------------------
482498

483499
if __name__ == '__main__':

0 commit comments

Comments
 (0)