Issue #9993: When the source and destination are on different filesystems,
and the source is a symlink, shutil.move() now recreates a symlink on the destination instead of copying the file contents. Patch by Jonathan Niehof and Hynek Schlawack.
This commit is contained in:
parent
deec7566ae
commit
0a08d7a095
|
@ -196,7 +196,12 @@ Directory and files operations
|
|||
|
||||
If the destination is on the current filesystem, then :func:`os.rename` is
|
||||
used. Otherwise, *src* is copied (using :func:`copy2`) to *dst* and then
|
||||
removed.
|
||||
removed. In case of symlinks, a new symlink pointing to the target of *src*
|
||||
will be created in or as *dst* and *src* will be removed.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added explicit symlink handling for foreign filesystems, thus adapting
|
||||
it to the behavior of GNU's :program:`mv`.
|
||||
|
||||
.. function:: disk_usage(path)
|
||||
|
||||
|
|
|
@ -356,7 +356,10 @@ def move(src, dst):
|
|||
overwritten depending on os.rename() semantics.
|
||||
|
||||
If the destination is on our current filesystem, then rename() is used.
|
||||
Otherwise, src is copied to the destination and then removed.
|
||||
Otherwise, src is copied to the destination and then removed. Symlinks are
|
||||
recreated under the new name if os.rename() fails because of cross
|
||||
filesystem renames.
|
||||
|
||||
A lot more could be done here... A look at a mv.c shows a lot of
|
||||
the issues this implementation glosses over.
|
||||
|
||||
|
@ -375,7 +378,11 @@ def move(src, dst):
|
|||
try:
|
||||
os.rename(src, real_dst)
|
||||
except OSError:
|
||||
if os.path.isdir(src):
|
||||
if os.path.islink(src):
|
||||
linkto = os.readlink(src)
|
||||
os.symlink(linkto, real_dst)
|
||||
os.unlink(src)
|
||||
elif os.path.isdir(src):
|
||||
if _destinsrc(src, dst):
|
||||
raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst))
|
||||
copytree(src, real_dst, symlinks=True)
|
||||
|
|
|
@ -1104,6 +1104,49 @@ class TestMove(unittest.TestCase):
|
|||
finally:
|
||||
shutil.rmtree(TESTFN, ignore_errors=True)
|
||||
|
||||
@support.skip_unless_symlink
|
||||
@mock_rename
|
||||
def test_move_file_symlink(self):
|
||||
dst = os.path.join(self.src_dir, 'bar')
|
||||
os.symlink(self.src_file, dst)
|
||||
shutil.move(dst, self.dst_file)
|
||||
self.assertTrue(os.path.islink(self.dst_file))
|
||||
self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
|
||||
|
||||
@support.skip_unless_symlink
|
||||
@mock_rename
|
||||
def test_move_file_symlink_to_dir(self):
|
||||
filename = "bar"
|
||||
dst = os.path.join(self.src_dir, filename)
|
||||
os.symlink(self.src_file, dst)
|
||||
shutil.move(dst, self.dst_dir)
|
||||
final_link = os.path.join(self.dst_dir, filename)
|
||||
self.assertTrue(os.path.islink(final_link))
|
||||
self.assertTrue(os.path.samefile(self.src_file, final_link))
|
||||
|
||||
@support.skip_unless_symlink
|
||||
@mock_rename
|
||||
def test_move_dangling_symlink(self):
|
||||
src = os.path.join(self.src_dir, 'baz')
|
||||
dst = os.path.join(self.src_dir, 'bar')
|
||||
os.symlink(src, dst)
|
||||
dst_link = os.path.join(self.dst_dir, 'quux')
|
||||
shutil.move(dst, dst_link)
|
||||
self.assertTrue(os.path.islink(dst_link))
|
||||
self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
|
||||
|
||||
@support.skip_unless_symlink
|
||||
@mock_rename
|
||||
def test_move_dir_symlink(self):
|
||||
src = os.path.join(self.src_dir, 'baz')
|
||||
dst = os.path.join(self.src_dir, 'bar')
|
||||
os.mkdir(src)
|
||||
os.symlink(src, dst)
|
||||
dst_link = os.path.join(self.dst_dir, 'quux')
|
||||
shutil.move(dst, dst_link)
|
||||
self.assertTrue(os.path.islink(dst_link))
|
||||
self.assertTrue(os.path.samefile(src, dst_link))
|
||||
|
||||
|
||||
class TestCopyFile(unittest.TestCase):
|
||||
|
||||
|
|
|
@ -707,6 +707,7 @@ Max Neunhöffer
|
|||
George Neville-Neil
|
||||
Johannes Nicolai
|
||||
Samuel Nicolary
|
||||
Jonathan Niehof
|
||||
Gustavo Niemeyer
|
||||
Oscar Nierstrasz
|
||||
Hrvoje Niksic
|
||||
|
|
|
@ -422,6 +422,11 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #9993: When the source and destination are on different filesystems,
|
||||
and the source is a symlink, shutil.move() now recreates a symlink on the
|
||||
destination instead of copying the file contents. Patch by Jonathan Niehof
|
||||
and Hynek Schlawack.
|
||||
|
||||
- Issue #12926: Fix a bug in tarfile's link extraction.
|
||||
|
||||
- Issue #13696: Fix the 302 Relative URL Redirection problem.
|
||||
|
|
Loading…
Reference in New Issue