From a7e9030c12a6c623e480e9f65055fe8956a9ea3a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 29 Dec 2020 10:48:26 +0530 Subject: [PATCH] Make finding ImageMagick a bit more robust on macOS --- kittens/tui/images.py | 21 ++++++++++++++++++++- kitty/utils.py | 26 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/kittens/tui/images.py b/kittens/tui/images.py index 7ec30ff46..2b48b8126 100644 --- a/kittens/tui/images.py +++ b/kittens/tui/images.py @@ -14,6 +14,7 @@ from typing import ( Union ) +from kitty.constants import is_macos from kitty.typing import ( CompletedProcess, GRT_a, GRT_d, GRT_f, GRT_m, GRT_o, GRT_t, HandlerType ) @@ -75,6 +76,21 @@ def identify(path: str) -> ImageData: return ImageData(parts[0].lower(), int(parts[1]), int(parts[2]), mode) +def find_exe(name: str) -> Optional[str]: + import shutil + ans = shutil.which(name) + if ans is None: + # In case PATH is messed up + if is_macos: + from kitty.utils import system_paths_on_macos + paths = system_paths_on_macos() + else: + paths = ['/usr/local/bin', '/opt/bin', '/usr/bin', '/bin'] + path = os.pathsep.join(paths) + os.pathsep + os.defpath + ans = shutil.which(name, path=path) + return ans + + def convert( path: str, m: ImageData, available_width: int, available_height: int, @@ -83,7 +99,10 @@ def convert( ) -> Tuple[str, int, int]: from tempfile import NamedTemporaryFile width, height = m.width, m.height - cmd = ['convert', '-background', 'none', '--', path] + exe = find_exe('convert') + if exe is None: + raise OSError('Failed to find the ImageMagick convert executable, make sure it is present in PATH') + cmd = [exe, '-background', 'none', '--', path] scaled = False if scale_up: if width < available_width: diff --git a/kitty/utils.py b/kitty/utils.py index e435770f7..3155dec70 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -511,6 +511,32 @@ def resolved_shell(opts: Optional[Options] = None) -> List[str]: return ans +@lru_cache(maxsize=2) +def system_paths_on_macos() -> List[str]: + entries, seen = [], set() + + def add_from_file(x: str) -> None: + try: + f = open(x) + except FileNotFoundError: + return + with f: + for line in f: + line = line.strip() + if line and not line.startswith('#') and line not in seen: + if os.path.isdir(line): + seen.add(line) + entries.append(line) + try: + files = os.listdir('/etc/paths.d') + except FileNotFoundError: + files = [] + for name in sorted(files): + add_from_file(os.path.join('/etc/paths.d', name)) + add_from_file('/etc/paths') + return entries + + def read_shell_environment(opts: Optional[Options] = None) -> Dict[str, str]: ans: Optional[Dict[str, str]] = getattr(read_shell_environment, 'ans', None) if ans is None: