mirror of
https://github.com/beetbox/beets.git
synced 2026-01-30 20:13:37 +01:00
Introduce atomic move and write of file
The idea of this changes is simple: let move file to some temporary name inside distance folder, and after the file is already copy it renames to expected name. When someone tries to save anything it also moves file to trigger OS level notification for change FS. This commit also enforce that `beets.util.move` shouldn't be used to move directories as it described in comment. Thus, this is fixed #3849
This commit is contained in:
parent
be82fd0f4a
commit
8d50301be5
1 changed files with 17 additions and 3 deletions
|
|
@ -19,6 +19,7 @@ import sys
|
|||
import errno
|
||||
import locale
|
||||
import re
|
||||
import tempfile
|
||||
import shutil
|
||||
import fnmatch
|
||||
import functools
|
||||
|
|
@ -478,6 +479,11 @@ def move(path, dest, replace=False):
|
|||
instead, in which case metadata will *not* be preserved. Paths are
|
||||
translated to system paths.
|
||||
"""
|
||||
if os.path.isdir(path):
|
||||
raise FilesystemError(u'source is directory', 'move', (path, dest))
|
||||
if os.path.isdir(dest):
|
||||
raise FilesystemError(u'destination is directory', 'move',
|
||||
(path, dest))
|
||||
if samefile(path, dest):
|
||||
return
|
||||
path = syspath(path)
|
||||
|
|
@ -487,15 +493,23 @@ def move(path, dest, replace=False):
|
|||
|
||||
# First, try renaming the file.
|
||||
try:
|
||||
os.rename(path, dest)
|
||||
os.replace(path, dest)
|
||||
except OSError:
|
||||
# Otherwise, copy and delete the original.
|
||||
tmp = tempfile.mktemp(suffix='.beets',
|
||||
prefix=py3_path(b'.' + os.path.basename(dest)),
|
||||
dir=py3_path(os.path.dirname(dest)))
|
||||
tmp = syspath(tmp)
|
||||
try:
|
||||
shutil.copyfile(path, dest)
|
||||
shutil.copyfile(path, tmp)
|
||||
os.replace(tmp, dest)
|
||||
tmp = None
|
||||
os.remove(path)
|
||||
except OSError as exc:
|
||||
raise FilesystemError(exc, 'move', (path, dest),
|
||||
traceback.format_exc())
|
||||
finally:
|
||||
if tmp is not None:
|
||||
os.remove(tmp)
|
||||
|
||||
|
||||
def link(path, dest, replace=False):
|
||||
|
|
|
|||
Loading…
Reference in a new issue