Skip to content

Commit

Permalink
Introduce atomic move and write of file
Browse files Browse the repository at this point in the history
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
  • Loading branch information
catap committed Sep 17, 2021
1 parent 7548820 commit 1a5ddf8
Showing 1 changed file with 16 additions and 3 deletions.
19 changes: 16 additions & 3 deletions beets/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import errno
import locale
import re
import tempfile
import shutil
import fnmatch
import functools
Expand Down Expand Up @@ -482,6 +483,10 @@ 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'distance is directory', 'move', (path, dest))
if samefile(path, dest):
return
path = syspath(path)
Expand All @@ -491,15 +496,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, IOError) 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):
Expand Down

0 comments on commit 1a5ddf8

Please sign in to comment.