mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
Handle missing reflink dependency in the business logic
This commit is contained in:
parent
255ac4bc2f
commit
fee959c500
2 changed files with 21 additions and 20 deletions
|
|
@ -13,6 +13,7 @@
|
||||||
# included in all copies or substantial portions of the Software.
|
# included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
"""Miscellaneous utility functions."""
|
"""Miscellaneous utility functions."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
|
|
@ -29,6 +30,7 @@ import traceback
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from importlib import import_module
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from multiprocessing.pool import ThreadPool
|
from multiprocessing.pool import ThreadPool
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -615,31 +617,33 @@ def reflink(
|
||||||
Raise an `OSError` if `dest` already exists, unless `replace` is
|
Raise an `OSError` if `dest` already exists, unless `replace` is
|
||||||
True. If `path` == `dest`, then do nothing.
|
True. If `path` == `dest`, then do nothing.
|
||||||
|
|
||||||
If reflinking fails and `fallback` is enabled, try copying the file
|
If `fallback` is enabled, ignore errors and copy the file instead.
|
||||||
instead. Otherwise, raise an error without trying a plain copy.
|
Otherwise, errors are re-raised as FilesystemError with an explanation.
|
||||||
|
|
||||||
May raise an `ImportError` if the `reflink` module is not available.
|
|
||||||
"""
|
"""
|
||||||
import reflink as pyreflink
|
|
||||||
|
|
||||||
if samefile(path, dest):
|
if samefile(path, dest):
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.exists(syspath(dest)) and not replace:
|
if os.path.exists(syspath(dest)) and not replace:
|
||||||
raise FilesystemError("file exists", "rename", (path, dest))
|
raise FilesystemError("file exists", "rename", (path, dest))
|
||||||
|
|
||||||
|
if fallback:
|
||||||
|
with suppress(Exception):
|
||||||
|
return import_module("reflink").reflink(path, dest)
|
||||||
|
return copy(path, dest, replace)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pyreflink.reflink(path, dest)
|
import_module("reflink").reflink(path, dest)
|
||||||
except (NotImplementedError, pyreflink.ReflinkImpossibleError):
|
except (ImportError, OSError):
|
||||||
if fallback:
|
raise
|
||||||
copy(path, dest, replace)
|
except Exception as exc:
|
||||||
else:
|
msg = {
|
||||||
raise FilesystemError(
|
"EXDEV": "Cannot reflink across devices",
|
||||||
"OS/filesystem does not support reflinks.",
|
"EOPNOTSUPP": "Device does not support reflinks",
|
||||||
"link",
|
}.get(str(exc), "OS does not support reflinks")
|
||||||
(path, dest),
|
|
||||||
traceback.format_exc(),
|
raise FilesystemError(
|
||||||
)
|
msg, "reflink", (path, dest), traceback.format_exc()
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
def unique_path(path: bytes) -> bytes:
|
def unique_path(path: bytes) -> bytes:
|
||||||
|
|
|
||||||
|
|
@ -86,12 +86,10 @@ class MoveTest(BeetsTestCase):
|
||||||
self.i.move(operation=MoveOperation.COPY)
|
self.i.move(operation=MoveOperation.COPY)
|
||||||
self.assertExists(self.path)
|
self.assertExists(self.path)
|
||||||
|
|
||||||
@NEEDS_REFLINK
|
|
||||||
def test_reflink_arrives(self):
|
def test_reflink_arrives(self):
|
||||||
self.i.move(operation=MoveOperation.REFLINK_AUTO)
|
self.i.move(operation=MoveOperation.REFLINK_AUTO)
|
||||||
self.assertExists(self.dest)
|
self.assertExists(self.dest)
|
||||||
|
|
||||||
@NEEDS_REFLINK
|
|
||||||
def test_reflink_does_not_depart(self):
|
def test_reflink_does_not_depart(self):
|
||||||
self.i.move(operation=MoveOperation.REFLINK_AUTO)
|
self.i.move(operation=MoveOperation.REFLINK_AUTO)
|
||||||
self.assertExists(self.path)
|
self.assertExists(self.path)
|
||||||
|
|
@ -584,7 +582,6 @@ class SafeMoveCopyTest(BeetsTestCase):
|
||||||
with pytest.raises(util.FilesystemError):
|
with pytest.raises(util.FilesystemError):
|
||||||
util.copy(self.path, self.otherpath)
|
util.copy(self.path, self.otherpath)
|
||||||
|
|
||||||
@NEEDS_REFLINK
|
|
||||||
def test_unsuccessful_reflink(self):
|
def test_unsuccessful_reflink(self):
|
||||||
with pytest.raises(util.FilesystemError):
|
with pytest.raises(util.FilesystemError):
|
||||||
util.reflink(self.path, self.otherpath)
|
util.reflink(self.path, self.otherpath)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue