فهرست منبع

fix stuff with bun_path (#4688)

* fix stuff with bun_path

* which always return Path object

* try using samefile() for file path comparison

* check for None

* fix tests, maybe

* fix more tests
Thomas Brandého 3 ماه پیش
والد
کامیت
61a6ab9bbd
4فایلهای تغییر یافته به همراه43 افزوده شده و 36 حذف شده
  1. 5 5
      reflex/utils/exec.py
  2. 23 12
      reflex/utils/path_ops.py
  3. 10 13
      reflex/utils/prerequisites.py
  4. 5 6
      tests/units/utils/test_utils.py

+ 5 - 5
reflex/utils/exec.py

@@ -467,19 +467,19 @@ def output_system_info():
 
 
     system = platform.system()
     system = platform.system()
 
 
+    fnm_info = f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]"
+
     if system != "Windows" or (
     if system != "Windows" or (
         system == "Windows" and prerequisites.is_windows_bun_supported()
         system == "Windows" and prerequisites.is_windows_bun_supported()
     ):
     ):
         dependencies.extend(
         dependencies.extend(
             [
             [
-                f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]",
-                f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {config.bun_path})]",
+                fnm_info,
+                f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]",
             ],
             ],
         )
         )
     else:
     else:
-        dependencies.append(
-            f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]",
-        )
+        dependencies.append(fnm_info)
 
 
     if system == "Linux":
     if system == "Linux":
         import distro  # type: ignore
         import distro  # type: ignore

+ 23 - 12
reflex/utils/path_ops.py

@@ -9,7 +9,7 @@ import shutil
 from pathlib import Path
 from pathlib import Path
 
 
 from reflex import constants
 from reflex import constants
-from reflex.config import environment
+from reflex.config import environment, get_config
 
 
 # Shorthand for join.
 # Shorthand for join.
 join = os.linesep.join
 join = os.linesep.join
@@ -118,7 +118,7 @@ def ln(src: str | Path, dest: str | Path, overwrite: bool = False) -> bool:
     return True
     return True
 
 
 
 
-def which(program: str | Path) -> str | Path | None:
+def which(program: str | Path) -> Path | None:
     """Find the path to an executable.
     """Find the path to an executable.
 
 
     Args:
     Args:
@@ -127,7 +127,8 @@ def which(program: str | Path) -> str | Path | None:
     Returns:
     Returns:
         The path to the executable.
         The path to the executable.
     """
     """
-    return shutil.which(str(program))
+    which_result = shutil.which(program)
+    return Path(which_result) if which_result else None
 
 
 
 
 def use_system_node() -> bool:
 def use_system_node() -> bool:
@@ -156,12 +157,12 @@ def get_node_bin_path() -> Path | None:
     """
     """
     bin_path = Path(constants.Node.BIN_PATH)
     bin_path = Path(constants.Node.BIN_PATH)
     if not bin_path.exists():
     if not bin_path.exists():
-        str_path = which("node")
-        return Path(str_path).parent.resolve() if str_path else None
-    return bin_path.resolve()
+        path = which("node")
+        return path.parent.absolute() if path else None
+    return bin_path.absolute()
 
 
 
 
-def get_node_path() -> str | None:
+def get_node_path() -> Path | None:
     """Get the node binary path.
     """Get the node binary path.
 
 
     Returns:
     Returns:
@@ -169,9 +170,8 @@ def get_node_path() -> str | None:
     """
     """
     node_path = Path(constants.Node.PATH)
     node_path = Path(constants.Node.PATH)
     if use_system_node() or not node_path.exists():
     if use_system_node() or not node_path.exists():
-        system_node_path = which("node")
-        return str(system_node_path) if system_node_path else None
-    return str(node_path)
+        node_path = which("node")
+    return node_path
 
 
 
 
 def get_npm_path() -> Path | None:
 def get_npm_path() -> Path | None:
@@ -182,11 +182,22 @@ def get_npm_path() -> Path | None:
     """
     """
     npm_path = Path(constants.Node.NPM_PATH)
     npm_path = Path(constants.Node.NPM_PATH)
     if use_system_node() or not npm_path.exists():
     if use_system_node() or not npm_path.exists():
-        system_npm_path = which("npm")
-        npm_path = Path(system_npm_path) if system_npm_path else None
+        npm_path = which("npm")
     return npm_path.absolute() if npm_path else None
     return npm_path.absolute() if npm_path else None
 
 
 
 
+def get_bun_path() -> Path | None:
+    """Get bun binary path.
+
+    Returns:
+        The path to the bun binary file.
+    """
+    bun_path = get_config().bun_path
+    if use_system_bun() or not bun_path.exists():
+        bun_path = which("bun")
+    return bun_path.absolute() if bun_path else None
+
+
 def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
 def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
     """Update the contents of a json file.
     """Update the contents of a json file.
 
 

+ 10 - 13
reflex/utils/prerequisites.py

@@ -205,10 +205,13 @@ def get_bun_version() -> version.Version | None:
     Returns:
     Returns:
         The version of bun.
         The version of bun.
     """
     """
+    bun_path = path_ops.get_bun_path()
+    if bun_path is None:
+        return None
     try:
     try:
         # Run the bun -v command and capture the output
         # Run the bun -v command and capture the output
-        result = processes.new_process([str(get_config().bun_path), "-v"], run=True)
-        return version.parse(result.stdout)  # type: ignore
+        result = processes.new_process([str(bun_path), "-v"], run=True)
+        return version.parse(str(result.stdout))
     except FileNotFoundError:
     except FileNotFoundError:
         return None
         return None
     except version.InvalidVersion as e:
     except version.InvalidVersion as e:
@@ -1062,9 +1065,7 @@ def install_bun():
             )
             )
 
 
     # Skip if bun is already installed.
     # Skip if bun is already installed.
-    if Path(get_config().bun_path).exists() and get_bun_version() == version.parse(
-        constants.Bun.VERSION
-    ):
+    if get_bun_version() == version.parse(constants.Bun.VERSION):
         console.debug("Skipping bun installation as it is already installed.")
         console.debug("Skipping bun installation as it is already installed.")
         return
         return
 
 
@@ -1085,8 +1086,7 @@ def install_bun():
             show_logs=console.is_debug(),
             show_logs=console.is_debug(),
         )
         )
     else:
     else:
-        unzip_path = path_ops.which("unzip")
-        if unzip_path is None:
+        if path_ops.which("unzip") is None:
             raise SystemPackageMissingError("unzip")
             raise SystemPackageMissingError("unzip")
 
 
         # Run the bun install script.
         # Run the bun install script.
@@ -1290,12 +1290,9 @@ def validate_bun():
     Raises:
     Raises:
         Exit: If custom specified bun does not exist or does not meet requirements.
         Exit: If custom specified bun does not exist or does not meet requirements.
     """
     """
-    # if a custom bun path is provided, make sure its valid
-    # This is specific to non-FHS OS
-    bun_path = get_config().bun_path
-    if path_ops.use_system_bun():
-        bun_path = path_ops.which("bun")
-    if bun_path != constants.Bun.DEFAULT_PATH:
+    bun_path = path_ops.get_bun_path()
+
+    if bun_path and bun_path.samefile(constants.Bun.DEFAULT_PATH):
         console.info(f"Using custom Bun path: {bun_path}")
         console.info(f"Using custom Bun path: {bun_path}")
         bun_version = get_bun_version()
         bun_version = get_bun_version()
         if not bun_version:
         if not bun_version:

+ 5 - 6
tests/units/utils/test_utils.py

@@ -122,13 +122,13 @@ def test_validate_invalid_bun_path(mocker):
     Args:
     Args:
         mocker: Pytest mocker object.
         mocker: Pytest mocker object.
     """
     """
-    mock = mocker.Mock()
-    mocker.patch.object(mock, "bun_path", return_value="/mock/path")
-    mocker.patch("reflex.utils.prerequisites.get_config", mock)
+    mock_path = mocker.Mock()
+    mocker.patch("reflex.utils.path_ops.get_bun_path", return_value=mock_path)
     mocker.patch("reflex.utils.prerequisites.get_bun_version", return_value=None)
     mocker.patch("reflex.utils.prerequisites.get_bun_version", return_value=None)
 
 
     with pytest.raises(typer.Exit):
     with pytest.raises(typer.Exit):
         prerequisites.validate_bun()
         prerequisites.validate_bun()
+    mock_path.samefile.assert_called_once()
 
 
 
 
 def test_validate_bun_path_incompatible_version(mocker):
 def test_validate_bun_path_incompatible_version(mocker):
@@ -137,9 +137,8 @@ def test_validate_bun_path_incompatible_version(mocker):
     Args:
     Args:
         mocker: Pytest mocker object.
         mocker: Pytest mocker object.
     """
     """
-    mock = mocker.Mock()
-    mocker.patch.object(mock, "bun_path", return_value="/mock/path")
-    mocker.patch("reflex.utils.prerequisites.get_config", mock)
+    mock_path = mocker.Mock()
+    mocker.patch("reflex.utils.path_ops.get_bun_path", return_value=mock_path)
     mocker.patch(
     mocker.patch(
         "reflex.utils.prerequisites.get_bun_version",
         "reflex.utils.prerequisites.get_bun_version",
         return_value=version.parse("0.6.5"),
         return_value=version.parse("0.6.5"),