Handle missing reflink dependency in the business logic

This commit is contained in:
Šarūnas Nejus 2024-09-04 20:34:00 +01:00
parent 255ac4bc2f
commit fee959c500
No known key found for this signature in database
GPG key ID: DD28F6704DBE3435
2 changed files with 21 additions and 20 deletions

View file

@ -13,6 +13,7 @@
# included in all copies or substantial portions of the Software.
"""Miscellaneous utility functions."""
from __future__ import annotations
import errno
@ -29,6 +30,7 @@ import traceback
from collections import Counter
from contextlib import suppress
from enum import Enum
from importlib import import_module
from logging import Logger
from multiprocessing.pool import ThreadPool
from pathlib import Path
@ -615,31 +617,33 @@ def reflink(
Raise an `OSError` if `dest` already exists, unless `replace` is
True. If `path` == `dest`, then do nothing.
If reflinking fails and `fallback` is enabled, try copying the file
instead. Otherwise, raise an error without trying a plain copy.
May raise an `ImportError` if the `reflink` module is not available.
If `fallback` is enabled, ignore errors and copy the file instead.
Otherwise, errors are re-raised as FilesystemError with an explanation.
"""
import reflink as pyreflink
if samefile(path, dest):
return
if os.path.exists(syspath(dest)) and not replace:
raise FilesystemError("file exists", "rename", (path, dest))
try:
pyreflink.reflink(path, dest)
except (NotImplementedError, pyreflink.ReflinkImpossibleError):
if fallback:
copy(path, dest, replace)
else:
with suppress(Exception):
return import_module("reflink").reflink(path, dest)
return copy(path, dest, replace)
try:
import_module("reflink").reflink(path, dest)
except (ImportError, OSError):
raise
except Exception as exc:
msg = {
"EXDEV": "Cannot reflink across devices",
"EOPNOTSUPP": "Device does not support reflinks",
}.get(str(exc), "OS does not support reflinks")
raise FilesystemError(
"OS/filesystem does not support reflinks.",
"link",
(path, dest),
traceback.format_exc(),
)
msg, "reflink", (path, dest), traceback.format_exc()
) from exc
def unique_path(path: bytes) -> bytes:

View file

@ -86,12 +86,10 @@ class MoveTest(BeetsTestCase):
self.i.move(operation=MoveOperation.COPY)
self.assertExists(self.path)
@NEEDS_REFLINK
def test_reflink_arrives(self):
self.i.move(operation=MoveOperation.REFLINK_AUTO)
self.assertExists(self.dest)
@NEEDS_REFLINK
def test_reflink_does_not_depart(self):
self.i.move(operation=MoveOperation.REFLINK_AUTO)
self.assertExists(self.path)
@ -584,7 +582,6 @@ class SafeMoveCopyTest(BeetsTestCase):
with pytest.raises(util.FilesystemError):
util.copy(self.path, self.otherpath)
@NEEDS_REFLINK
def test_unsuccessful_reflink(self):
with pytest.raises(util.FilesystemError):
util.reflink(self.path, self.otherpath)