def moveTo(self, destination):
try:
os.rename(self.path, destination.path)
self.restat(False)
except OSError, ose:
if ose.errno == errno.EXDEV:
# man 2 rename, ubuntu linux 5.10 "breezy":
# oldpath and newpath are not on the same mounted filesystem.
# (Linux permits a filesystem to be mounted at multiple
# points, but rename(2) does not work across different mount
# points, even if the same filesystem is mounted on both.)
# that means it's time to copy trees of directories!
secsib = destination.temporarySibling()
self.copyTo(secsib) # slow
secsib.moveTo(destination) # visible
# done creating new stuff. let's clean me up.
mysecsib = self.temporarySibling()
self.moveTo(mysecsib) # visible
mysecsib.remove() # slow
else:
raise
python类EXDEV的实例源码
def testCrossMountMoveTo(self):
"""
"""
# Bit of a whitebox test - force os.rename, which moveTo tries
# before falling back to a slower method, to fail, forcing moveTo to
# use the slower behavior.
invokedWith = []
def faultyRename(src, dest):
invokedWith.append((src, dest))
if len(invokedWith) == 2:
raise OSError(errno.EXDEV, 'Test-induced failure simulating cross-device rename failure')
return originalRename(src, dest)
originalRename = os.rename
os.rename = faultyRename
try:
self.testMoveTo()
# A bit of a sanity check for this whitebox test - if our rename
# was never invoked, the test has probably fallen into
# disrepair!
self.failUnless(len(invokedWith) >= 2)
finally:
os.rename = originalRename
def duplicate(src, dst):
"""Alternative to shutil.copyfile, this will use os.link when possible.
See shutil.copyfile for documention. Only `src` and `dst` are supported.
Unlike copyfile, this will not overwrite the destination if it exists.
"""
if os.path.isdir(src):
# os.link will give a permission error
raise OSError(errno.EISDIR, "Is a directory", src)
if os.path.isdir(dst):
# os.link will give a FileExists error
raise OSError(errno.EISDIR, "Is a directory", dst)
if os.path.exists(dst):
# shutil.copyfile will overwrite the existing file
raise OSError(errno.EEXIST, "File exists", src, "File exists", dst)
try:
os.link(src, dst)
except OSError as e:
if e.errno == errno.EXDEV: # Invalid cross-device link
shutil.copyfile(src, dst)
else:
raise
def moveTo(self, destination):
try:
os.rename(self.path, destination.path)
self.restat(False)
except OSError, ose:
if ose.errno == errno.EXDEV:
# man 2 rename, ubuntu linux 5.10 "breezy":
# oldpath and newpath are not on the same mounted filesystem.
# (Linux permits a filesystem to be mounted at multiple
# points, but rename(2) does not work across different mount
# points, even if the same filesystem is mounted on both.)
# that means it's time to copy trees of directories!
secsib = destination.temporarySibling()
self.copyTo(secsib) # slow
secsib.moveTo(destination) # visible
# done creating new stuff. let's clean me up.
mysecsib = self.temporarySibling()
self.moveTo(mysecsib) # visible
mysecsib.remove() # slow
else:
raise
def testCrossMountMoveTo(self):
"""
"""
# Bit of a whitebox test - force os.rename, which moveTo tries
# before falling back to a slower method, to fail, forcing moveTo to
# use the slower behavior.
invokedWith = []
def faultyRename(src, dest):
invokedWith.append((src, dest))
if len(invokedWith) == 2:
raise OSError(errno.EXDEV, 'Test-induced failure simulating cross-device rename failure')
return originalRename(src, dest)
originalRename = os.rename
os.rename = faultyRename
try:
self.testMoveTo()
# A bit of a sanity check for this whitebox test - if our rename
# was never invoked, the test has probably fallen into
# disrepair!
self.failUnless(len(invokedWith) >= 2)
finally:
os.rename = originalRename
def hard_link_or_copy(src, dst):
'''
Create a hard link from `src` to `dst` if possible. Otherwise copy `src` to `dst`.
src:
The source file or directory.
dst:
The destination.
'''
try:
os.link(src, dst)
except OSError as exc:
if exc.errno in (errno.EXDEV, errno.EPERM):
# Cannot create the hard link, maybe src is a directory or src and dst are on
# different devices, so we cannot link.
verbose('Failed to link from "%s" to "%s" as they are not different devices. '
'Copying instead.' %
(src, dst))
copy_path(src, dst)
else:
raise
def setUpFaultyRename(self):
"""
Set up a C{os.rename} that will fail with L{errno.EXDEV} on first call.
This is used to simulate a cross-device rename failure.
@return: a list of pair (src, dest) of calls to C{os.rename}
@rtype: C{list} of C{tuple}
"""
invokedWith = []
def faultyRename(src, dest):
invokedWith.append((src, dest))
if len(invokedWith) == 1:
raise OSError(errno.EXDEV, 'Test-induced failure simulating '
'cross-device rename failure')
return originalRename(src, dest)
originalRename = os.rename
self.patch(os, "rename", faultyRename)
return invokedWith
def _rename(src, dst):
LOG.info("Renaming file '%s' -> '%s'", src, dst)
try:
os.rename(src, dst)
except OSError, e: # noqa
if e.errno == errno.EXDEV:
LOG.error("Invalid cross-device link. Perhaps %s and %s should "
"be symlinked on the same filesystem?", src, dst)
raise
def link(source, target):
"""link(source, target) -> None
Attempt to hard link the source file to the target file name.
On OS/2, this creates a complete copy of the source file.
"""
s = os.open(source, os.O_RDONLY | os.O_BINARY)
if os.isatty(s):
raise OSError(errno.EXDEV, 'Cross-device link')
data = os.read(s, 1024)
try:
t = os.open(target, os.O_WRONLY | os.O_BINARY | os.O_CREAT | os.O_EXCL)
except OSError:
os.close(s)
raise
try:
while data:
os.write(t, data)
data = os.read(s, 1024)
except OSError:
os.close(s)
os.close(t)
os.unlink(target)
raise
os.close(s)
os.close(t)
def link(source, target):
"""link(source, target) -> None
Attempt to hard link the source file to the target file name.
On OS/2, this creates a complete copy of the source file.
"""
s = os.open(source, os.O_RDONLY | os.O_BINARY)
if os.isatty(s):
raise OSError, (errno.EXDEV, 'Cross-device link')
data = os.read(s, 1024)
try:
t = os.open(target, os.O_WRONLY | os.O_BINARY | os.O_CREAT | os.O_EXCL)
except OSError:
os.close(s)
raise
try:
while data:
os.write(t, data)
data = os.read(s, 1024)
except OSError:
os.close(s)
os.close(t)
os.unlink(target)
raise
os.close(s)
os.close(t)
def link(source, target):
"""link(source, target) -> None
Attempt to hard link the source file to the target file name.
On OS/2, this creates a complete copy of the source file.
"""
s = os.open(source, os.O_RDONLY | os.O_BINARY)
if os.isatty(s):
raise OSError, (errno.EXDEV, 'Cross-device link')
data = os.read(s, 1024)
try:
t = os.open(target, os.O_WRONLY | os.O_BINARY | os.O_CREAT | os.O_EXCL)
except OSError:
os.close(s)
raise
try:
while data:
os.write(t, data)
data = os.read(s, 1024)
except OSError:
os.close(s)
os.close(t)
os.unlink(target)
raise
os.close(s)
os.close(t)
def test_move_file_exception_unpacking_unlink(self):
# see issue 22182
with patch("os.rename", side_effect=OSError(errno.EXDEV, "wrong")), \
patch("os.unlink", side_effect=OSError("wrong", 1)), \
self.assertRaises(DistutilsFileError):
with open(self.source, 'w') as fobj:
fobj.write('spam eggs')
move_file(self.source, self.target, verbose=0)
def link(source, target):
"""link(source, target) -> None
Attempt to hard link the source file to the target file name.
On OS/2, this creates a complete copy of the source file.
"""
s = os.open(source, os.O_RDONLY | os.O_BINARY)
if os.isatty(s):
raise OSError, (errno.EXDEV, 'Cross-device link')
data = os.read(s, 1024)
try:
t = os.open(target, os.O_WRONLY | os.O_BINARY | os.O_CREAT | os.O_EXCL)
except OSError:
os.close(s)
raise
try:
while data:
os.write(t, data)
data = os.read(s, 1024)
except OSError:
os.close(s)
os.close(t)
os.unlink(target)
raise
os.close(s)
os.close(t)
def test_crossMountMoveTo(self):
"""
C{moveTo} should be able to handle C{EXDEV} error raised by
C{os.rename} when trying to move a file on a different mounted
filesystem.
"""
invokedWith = self.setUpFaultyRename()
# Bit of a whitebox test - force os.rename, which moveTo tries
# before falling back to a slower method, to fail, forcing moveTo to
# use the slower behavior.
self.test_moveTo()
# A bit of a sanity check for this whitebox test - if our rename
# was never invoked, the test has probably fallen into disrepair!
self.assertTrue(invokedWith)
def test_move_file_exception_unpacking_unlink(self):
# see issue 22182
with patch("os.rename", side_effect=OSError(errno.EXDEV, "wrong")), \
patch("os.unlink", side_effect=OSError("wrong", 1)), \
self.assertRaises(DistutilsFileError):
with open(self.source, 'w') as fobj:
fobj.write('spam eggs')
move_file(self.source, self.target, verbose=0)
def _rename(src, dst):
LOG.info("Renaming file '%s' -> '%s'" % (src, dst))
try:
os.rename(src, dst)
except OSError, e: # noqa
if e.errno == errno.EXDEV:
LOG.error("Invalid cross-device link. Perhaps %s and %s should "
"be symlinked on the same filesystem?" % (src, dst))
raise
def rename(src, dst):
try:
os.rename(src, dst)
except OSError as e:
# Handle the case where we tried to rename a file across a
# filesystem boundary.
if e.errno != errno.EXDEV or not os.path.isfile(src):
raise
# Copy the data and metadata into a temporary file in the same
# filesystem as the destination, rename into place, and unlink
# the original.
try:
fd, tmpdst = tempfile.mkstemp(suffix=".pkg5.xdev",
dir=os.path.dirname(dst))
except OSError as e:
# If we don't have sufficient permissions to put the
# file where we want it, then higher levels can deal
# with that effectively, but people will want to know
# the original destination filename.
if e.errno == errno.EACCES:
e.filename=dst
raise
os.close(fd)
shutil.copy2(src, tmpdst)
os.rename(tmpdst, dst)
os.unlink(src)
def move(src, dst):
"""Rewrite of shutil.move() that uses our copy of copytree()."""
# If dst is a directory, then we try to move src into it.
if os.path.isdir(dst):
dst = os.path.join(dst,
os.path.basename(src).rstrip(os.path.sep))
try:
os.rename(src, dst)
except EnvironmentError as e:
# Access to protected member; pylint: disable=W0212
s = os.lstat(src)
if e.errno == errno.EXDEV:
if S_ISDIR(s.st_mode):
copytree(src, dst)
shutil.rmtree(src)
else:
shutil.copyfile(src, dst)
os.chmod(dst, S_IMODE(s.st_mode))
os.chown(dst, s.st_uid, s.st_gid)
os.utime(dst, (s.st_atime, s.st_mtime))
os.unlink(src)
elif e.errno == errno.EINVAL and S_ISDIR(s.st_mode):
raise shutil.Error("Cannot move a directory '{0}' "
"into itself '{1}'.".format(src, dst))
elif e.errno == errno.ENOTDIR and S_ISDIR(s.st_mode):
raise shutil.Error("Destination path '{0}' already "
"exists".format(dst))
else:
raise api_errors._convert_error(e)
def _rename(src, dst):
LOG.info("Renaming file '%s' -> '%s'" % (src, dst))
try:
os.rename(src, dst)
except OSError, e: # noqa
if e.errno == errno.EXDEV:
LOG.error("Invalid cross-device link. Perhaps %s and %s should "
"be symlinked on the same filesystem?" % (src, dst))
raise
def move_file (src, dst, verbose=1, dry_run=0):
"""Move a file 'src' to 'dst'.
If 'dst' is a directory, the file will be moved into it with the same
name; otherwise, 'src' is just renamed to 'dst'. Return the new
full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" % \
(src, dst))
copy_it = 0
try:
os.rename(src, dst)
except os.error, (num, msg):
if num == errno.EXDEV:
copy_it = 1
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except os.error, (num, msg):
try:
os.unlink(dst)
except os.error:
pass
raise DistutilsFileError(
("couldn't move '%s' to '%s' by copy/delete: " +
"delete '%s' failed: %s") %
(src, dst, src, msg))
return dst
def move_file (src, dst, verbose=1, dry_run=0):
"""Move a file 'src' to 'dst'.
If 'dst' is a directory, the file will be moved into it with the same
name; otherwise, 'src' is just renamed to 'dst'. Return the new
full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" % \
(src, dst))
copy_it = 0
try:
os.rename(src, dst)
except os.error, (num, msg):
if num == errno.EXDEV:
copy_it = 1
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except os.error, (num, msg):
try:
os.unlink(dst)
except os.error:
pass
raise DistutilsFileError(
("couldn't move '%s' to '%s' by copy/delete: " +
"delete '%s' failed: %s") %
(src, dst, src, msg))
return dst
def move_file (src, dst, verbose=1, dry_run=0):
"""Move a file 'src' to 'dst'.
If 'dst' is a directory, the file will be moved into it with the same
name; otherwise, 'src' is just renamed to 'dst'. Return the new
full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" % \
(src, dst))
copy_it = 0
try:
os.rename(src, dst)
except os.error, (num, msg):
if num == errno.EXDEV:
copy_it = 1
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except os.error, (num, msg):
try:
os.unlink(dst)
except os.error:
pass
raise DistutilsFileError(
("couldn't move '%s' to '%s' by copy/delete: " +
"delete '%s' failed: %s") %
(src, dst, src, msg))
return dst
def move_file (src, dst, verbose=1, dry_run=0):
"""Move a file 'src' to 'dst'.
If 'dst' is a directory, the file will be moved into it with the same
name; otherwise, 'src' is just renamed to 'dst'. Return the new
full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" % \
(src, dst))
copy_it = 0
try:
os.rename(src, dst)
except os.error, (num, msg):
if num == errno.EXDEV:
copy_it = 1
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except os.error, (num, msg):
try:
os.unlink(dst)
except os.error:
pass
raise DistutilsFileError(
("couldn't move '%s' to '%s' by copy/delete: " +
"delete '%s' failed: %s") %
(src, dst, src, msg))
return dst
def move_file (src, dst, verbose=1, dry_run=0):
"""Move a file 'src' to 'dst'.
If 'dst' is a directory, the file will be moved into it with the same
name; otherwise, 'src' is just renamed to 'dst'. Return the new
full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" % \
(src, dst))
copy_it = 0
try:
os.rename(src, dst)
except os.error, (num, msg):
if num == errno.EXDEV:
copy_it = 1
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except os.error, (num, msg):
try:
os.unlink(dst)
except os.error:
pass
raise DistutilsFileError(
("couldn't move '%s' to '%s' by copy/delete: " +
"delete '%s' failed: %s") %
(src, dst, src, msg))
return dst
def move_file (src, dst, verbose=1, dry_run=0):
"""Move a file 'src' to 'dst'.
If 'dst' is a directory, the file will be moved into it with the same
name; otherwise, 'src' is just renamed to 'dst'. Return the new
full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" % \
(src, dst))
copy_it = 0
try:
os.rename(src, dst)
except os.error, (num, msg):
if num == errno.EXDEV:
copy_it = 1
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except os.error, (num, msg):
try:
os.unlink(dst)
except os.error:
pass
raise DistutilsFileError(
("couldn't move '%s' to '%s' by copy/delete: " +
"delete '%s' failed: %s") %
(src, dst, src, msg))
return dst
def move_file (src, dst,
verbose=1,
dry_run=0):
"""Move a file 'src' to 'dst'. If 'dst' is a directory, the file will
be moved into it with the same name; otherwise, 'src' is just renamed
to 'dst'. Return the new full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" %
(src, dst))
copy_it = False
try:
os.rename(src, dst)
except OSError as e:
(num, msg) = e.args
if num == errno.EXDEV:
copy_it = True
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except OSError as e:
(num, msg) = e.args
try:
os.unlink(dst)
except OSError:
pass
raise DistutilsFileError(
"couldn't move '%s' to '%s' by copy/delete: "
"delete '%s' failed: %s"
% (src, dst, src, msg))
return dst
def move_file (src, dst, verbose=1, dry_run=0):
"""Move a file 'src' to 'dst'.
If 'dst' is a directory, the file will be moved into it with the same
name; otherwise, 'src' is just renamed to 'dst'. Return the new
full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" % \
(src, dst))
copy_it = 0
try:
os.rename(src, dst)
except os.error, (num, msg):
if num == errno.EXDEV:
copy_it = 1
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except os.error, (num, msg):
try:
os.unlink(dst)
except os.error:
pass
raise DistutilsFileError(
("couldn't move '%s' to '%s' by copy/delete: " +
"delete '%s' failed: %s") %
(src, dst, src, msg))
return dst
def move_file (src, dst, verbose=1, dry_run=0):
"""Move a file 'src' to 'dst'.
If 'dst' is a directory, the file will be moved into it with the same
name; otherwise, 'src' is just renamed to 'dst'. Return the new
full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" % \
(src, dst))
copy_it = 0
try:
os.rename(src, dst)
except os.error, (num, msg):
if num == errno.EXDEV:
copy_it = 1
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except os.error, (num, msg):
try:
os.unlink(dst)
except os.error:
pass
raise DistutilsFileError(
("couldn't move '%s' to '%s' by copy/delete: " +
"delete '%s' failed: %s") %
(src, dst, src, msg))
return dst
def moveTo(self, destination, followLinks=True):
"""
Move self to destination - basically renaming self to whatever
destination is named.
If destination is an already-existing directory,
moves all children to destination if destination is empty. If
destination is a non-empty directory, or destination is a file, an
OSError will be raised.
If moving between filesystems, self needs to be copied, and everything
that applies to copyTo applies to moveTo.
@param destination: the destination (a FilePath) to which self
should be copied
@param followLinks: whether symlinks in self should be treated as links
or as their targets (only applicable when moving between
filesystems)
"""
try:
os.rename(self._getPathAsSameTypeAs(destination.path),
destination.path)
except OSError as ose:
if ose.errno == errno.EXDEV:
# man 2 rename, ubuntu linux 5.10 "breezy":
# oldpath and newpath are not on the same mounted filesystem.
# (Linux permits a filesystem to be mounted at multiple
# points, but rename(2) does not work across different mount
# points, even if the same filesystem is mounted on both.)
# that means it's time to copy trees of directories!
secsib = destination.temporarySibling()
self.copyTo(secsib, followLinks) # slow
secsib.moveTo(destination, followLinks) # visible
# done creating new stuff. let's clean me up.
mysecsib = self.temporarySibling()
self.moveTo(mysecsib, followLinks) # visible
mysecsib.remove() # slow
else:
raise
else:
self.changed()
destination.changed()
def move_file (src, dst,
verbose=1,
dry_run=0):
"""Move a file 'src' to 'dst'. If 'dst' is a directory, the file will
be moved into it with the same name; otherwise, 'src' is just renamed
to 'dst'. Return the new full name of the file.
Handles cross-device moves on Unix using 'copy_file()'. What about
other systems???
"""
from os.path import exists, isfile, isdir, basename, dirname
import errno
if verbose >= 1:
log.info("moving %s -> %s", src, dst)
if dry_run:
return dst
if not isfile(src):
raise DistutilsFileError("can't move '%s': not a regular file" % src)
if isdir(dst):
dst = os.path.join(dst, basename(src))
elif exists(dst):
raise DistutilsFileError(
"can't move '%s': destination '%s' already exists" %
(src, dst))
if not isdir(dirname(dst)):
raise DistutilsFileError(
"can't move '%s': destination '%s' not a valid path" %
(src, dst))
copy_it = False
try:
os.rename(src, dst)
except OSError as e:
(num, msg) = e.args
if num == errno.EXDEV:
copy_it = True
else:
raise DistutilsFileError(
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
if copy_it:
copy_file(src, dst, verbose=verbose)
try:
os.unlink(src)
except OSError as e:
(num, msg) = e.args
try:
os.unlink(dst)
except OSError:
pass
raise DistutilsFileError(
"couldn't move '%s' to '%s' by copy/delete: "
"delete '%s' failed: %s"
% (src, dst, src, msg))
return dst