From 6cc80fdeaa9d1c3130345f89a8c3dfe01b01b4e6 Mon Sep 17 00:00:00 2001 From: Martin Oswald <73196164+oswdm@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:00:21 +0200 Subject: [PATCH] fix fish shell support (#10445) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexey Stern stern.alexey@gmail.com Co-authored-by: Saugat Pachhai (सौगात) --- dvc/stage/run.py | 69 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/dvc/stage/run.py b/dvc/stage/run.py index 40369780e..703c397c8 100644 --- a/dvc/stage/run.py +++ b/dvc/stage/run.py @@ -2,6 +2,9 @@ import os import signal import subprocess import threading +from functools import cache + +from packaging.version import InvalidVersion, Version from dvc.log import logger from dvc.utils import fix_env @@ -12,25 +15,59 @@ from .exceptions import StageCmdFailedError logger = logger.getChild(__name__) +@cache +def _fish_supports_no_config(executable) -> bool: + """ + Check if the fish shell supports the --no-config option. + + Parameters: + executable (str): The path to the fish shell executable. + + Returns: + bool: True if the fish version is greater than 3.3.0, False otherwise. + """ + try: + output = subprocess.check_output( + [executable, "--version"], # noqa: S603 + text=True, + ) + version = Version(output.split(" ")[-1].strip()) + version_to_check = Version("3.3.0") + return version >= version_to_check + except (subprocess.CalledProcessError, IndexError, InvalidVersion): + logger.trace("could not check fish version, defaulting to False") + return False + + +def _warn_if_fish(executable): + if ( + executable is None + or os.path.basename(executable) != "fish" + or _fish_supports_no_config(executable) + ): + return + logger.warning( + "DVC detected that you are using a version of fish shell below 3.3.0 " + "Be aware that it might cause problems by overwriting " + "your current environment variables with values defined " + "in 'config.fish', which might affect your command. See " + "https://github.com/iterative/dvc/issues/1307. " + ) + + def _make_cmd(executable, cmd): if executable is None: return cmd - opts = {"zsh": ["--no-rcs"], "bash": ["--noprofile", "--norc"]} + opts = { + "zsh": ["--no-rcs"], + "bash": ["--noprofile", "--norc"], + "fish": [], + } name = os.path.basename(executable).lower() - return [executable, *opts.get(name, []), "-c", cmd] - - -def warn_if_fish(executable): - if executable is None or os.path.basename(os.path.realpath(executable)) != "fish": - return - - logger.warning( - "DVC detected that you are using fish as your default " - "shell. Be aware that it might cause problems by overwriting " - "your current environment variables with values defined " - "in '.fishrc', which might affect your command. See " - "https://github.com/iterative/dvc/issues/1307. " - ) + opt = opts.get(name, []) + if name == "fish" and _fish_supports_no_config(executable): + opt.append("--no-config") + return [executable, *opt, "-c", cmd] def _enforce_cmd_list(cmd): @@ -106,7 +143,7 @@ def cmd_run(stage, dry=False, run_env=None): executable = get_executable() if not dry: - warn_if_fish(executable) + _warn_if_fish(executable) for cmd in commands: display_command(cmd)