]> granicus.if.org Git - python/commitdiff
Issue #21697: shutil.copytree() now correctly handles symbolic links that point to...
authorBerker Peksag <berker.peksag@gmail.com>
Sat, 25 Jul 2015 11:53:48 +0000 (14:53 +0300)
committerBerker Peksag <berker.peksag@gmail.com>
Sat, 25 Jul 2015 11:53:48 +0000 (14:53 +0300)
Patch by Eduardo Seabra and Thomas Kluyver.

Lib/shutil.py
Lib/test/test_shutil.py
Misc/NEWS

index ac06ae5e6cd84689580b81d7c0c1fac6d0a0acc8..e87d18e9c8054eec034c1cae64b5ac509dbd0293 100644 (file)
@@ -321,7 +321,11 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
                     if not os.path.exists(linkto) and ignore_dangling_symlinks:
                         continue
                     # otherwise let the copy occurs. copy2 will raise an error
-                    copy_function(srcname, dstname)
+                    if os.path.isdir(srcname):
+                        copytree(srcname, dstname, symlinks, ignore,
+                                 copy_function)
+                    else:
+                        copy_function(srcname, dstname)
             elif os.path.isdir(srcname):
                 copytree(srcname, dstname, symlinks, ignore, copy_function)
             else:
index 9325bc7dc15821da4694c5ada9bd11b29a3559f6..ca2bfc4bfeb4f5a84878bacee5483ed9453328a4 100644 (file)
@@ -895,6 +895,26 @@ class TestShutil(unittest.TestCase):
         shutil.copytree(src_dir, dst_dir, symlinks=True)
         self.assertIn('test.txt', os.listdir(dst_dir))
 
+    @support.skip_unless_symlink
+    def test_copytree_symlink_dir(self):
+        src_dir = self.mkdtemp()
+        dst_dir = os.path.join(self.mkdtemp(), 'destination')
+        os.mkdir(os.path.join(src_dir, 'real_dir'))
+        with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
+            pass
+        os.symlink(os.path.join(src_dir, 'real_dir'),
+                   os.path.join(src_dir, 'link_to_dir'),
+                   target_is_directory=True)
+
+        shutil.copytree(src_dir, dst_dir, symlinks=False)
+        self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
+        self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
+
+        dst_dir = os.path.join(self.mkdtemp(), 'destination2')
+        shutil.copytree(src_dir, dst_dir, symlinks=True)
+        self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
+        self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
+
     def _copy_file(self, method):
         fname = 'test.txt'
         tmpdir = self.mkdtemp()
index 1a67632e9188cad8bb68de0ea7fd50da0384a8c0..a347b940bb2d12e360a98655e1e8fab0ec5a8f65 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -66,6 +66,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #21697: shutil.copytree() now correctly handles symbolic links that
+  point to directories.  Patch by Eduardo Seabra and Thomas Kluyver.
+
 - Issue #24620: Random.setstate() now validates the value of state last element.
 
 - Issue #22153: Improve unittest docs. Patch from Martin Panter and evilzero.