Skip to content

Commit b3fd84b

Browse files
committed
Move max filename length calculation closer to where it is used
1 parent d318685 commit b3fd84b

File tree

2 files changed

+20
-17
lines changed

2 files changed

+20
-17
lines changed

beets/library.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,13 +1125,8 @@ def destination(
11251125
subpath, beets.config["path_sep_replace"].as_str()
11261126
)
11271127

1128-
maxlen = beets.config["max_filename_length"].get(int)
1129-
if not maxlen:
1130-
# When zero, try to determine from filesystem.
1131-
maxlen = util.max_filename_length(db.directory)
1132-
11331128
lib_path_str, fallback = util.legalize_path(
1134-
subpath, db.replacements, maxlen, os.path.splitext(self.path)[1]
1129+
subpath, db.replacements, os.path.splitext(self.path)[1]
11351130
)
11361131
if fallback:
11371132
# Print an error message if legalization fell back to

beets/util/__init__.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from collections import Counter
3131
from contextlib import suppress
3232
from enum import Enum
33+
from functools import cache
3334
from importlib import import_module
3435
from multiprocessing.pool import ThreadPool
3536
from pathlib import Path
@@ -47,6 +48,7 @@
4748

4849
from unidecode import unidecode
4950

51+
import beets
5052
from beets.util import hidden
5153

5254
if TYPE_CHECKING:
@@ -694,25 +696,26 @@ def sanitize_path(path: str, replacements: Replacements | None = None) -> str:
694696
return os.path.join(*comps)
695697

696698

697-
def truncate_path(path: AnyStr, length: int = MAX_FILENAME_LENGTH) -> AnyStr:
699+
def truncate_path(path: AnyStr) -> AnyStr:
698700
"""Given a bytestring path or a Unicode path fragment, truncate the
699701
components to a legal length. In the last component, the extension
700702
is preserved.
701703
"""
704+
max_length = get_max_filename_length()
702705
comps = components(path)
703706

704707
out = [c[:length] for c in comps]
705708
base, ext = os.path.splitext(comps[-1])
706709
if ext:
707710
# Last component has an extension.
708-
base = base[: length - len(ext)]
711+
base = base[: max_length - len(ext)]
709712
out[-1] = base + ext
710713

711714
return os.path.join(*out)
712715

713716

714717
def _legalize_stage(
715-
path: str, replacements: Replacements | None, length: int, extension: str
718+
path: str, replacements: Replacements | None, extension: str
716719
) -> tuple[str, bool]:
717720
"""Perform a single round of path legalization steps
718721
1. sanitation/replacement
@@ -729,13 +732,13 @@ def _legalize_stage(
729732

730733
# Truncate too-long components.
731734
pre_truncate_path = path
732-
path = truncate_path(path, length)
735+
path = truncate_path(path)
733736

734737
return path, path != pre_truncate_path
735738

736739

737740
def legalize_path(
738-
path: str, replacements: Replacements | None, length: int, extension: str
741+
path: str, replacements: Replacements | None, extension: str
739742
) -> tuple[str, bool]:
740743
"""Given a path-like Unicode string, produce a legal path. Return the path
741744
and a flag indicating whether some replacements had to be ignored (see
@@ -755,21 +758,21 @@ def legalize_path(
755758
after it was truncated); the application should probably log some sort of
756759
warning.
757760
"""
758-
args = length, as_string(extension)
761+
suffix = as_string(extension)
759762

760763
first_stage, _ = os.path.splitext(
761-
_legalize_stage(path, replacements, *args)[0]
764+
_legalize_stage(path, replacements, suffix)[0]
762765
)
763766

764767
# Re-sanitize following truncation (including user replacements).
765-
second_stage, truncated = _legalize_stage(first_stage, replacements, *args)
768+
second_stage, truncated = _legalize_stage(first_stage, replacements, suffix)
766769

767770
if not truncated:
768771
return second_stage, False
769772

770773
# If the path was truncated, discard user replacements
771774
# and run through one last legalization stage.
772-
return _legalize_stage(first_stage, None, *args)[0], True
775+
return _legalize_stage(first_stage, None, suffix)[0], True
773776

774777

775778
def str2bool(value: str) -> bool:
@@ -848,16 +851,21 @@ def command_output(cmd: list[BytesOrStr], shell: bool = False) -> CommandOutput:
848851
return CommandOutput(stdout, stderr)
849852

850853

851-
def max_filename_length(path: BytesOrStr, limit=MAX_FILENAME_LENGTH) -> int:
854+
@cache
855+
def get_max_filename_length() -> int:
852856
"""Attempt to determine the maximum filename length for the
853857
filesystem containing `path`. If the value is greater than `limit`,
854858
then `limit` is used instead (to prevent errors when a filesystem
855859
misreports its capacity). If it cannot be determined (e.g., on
856860
Windows), return `limit`.
857861
"""
862+
if length := beets.config["max_filename_length"].get(int):
863+
return length
864+
865+
limit = MAX_FILENAME_LENGTH
858866
if hasattr(os, "statvfs"):
859867
try:
860-
res = os.statvfs(path)
868+
res = os.statvfs(beets.config["directory"].as_str())
861869
except OSError:
862870
return limit
863871
return min(res[9], limit)

0 commit comments

Comments
 (0)