From cd57f077b21fbf686f7b735fc36f30fb35e5125e Mon Sep 17 00:00:00 2001 From: Dividesbyzer0 <54127744+zoomdbz@users.noreply.github.com> Date: Fri, 26 Jun 2026 15:35:01 -0400 Subject: [PATCH] fix(cookbook): activate local Windows venv in bash runner --- routes/cookbook_helpers.py | 21 +++++++++++++++++++++ routes/cookbook_routes.py | 6 +++--- tests/test_cookbook_helpers.py | 11 +++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/routes/cookbook_helpers.py b/routes/cookbook_helpers.py index e724b2dc1..3cdebfc4a 100644 --- a/routes/cookbook_helpers.py +++ b/routes/cookbook_helpers.py @@ -1204,6 +1204,27 @@ def _safe_env_prefix(ep: str | None) -> str | None: return f'[ -f "{path}" ] && source "{path}" || true' +def _local_windows_bash_env_prefix(ep: str | None) -> str | None: + """Convert a frontend PowerShell venv prefix for the local Git Bash runner.""" + if not ep: + return ep + try: + parts = shlex.split(ep, posix=True) + except ValueError: + return ep + if len(parts) != 2 or parts[0] != "&": + return ep + path = parts[1] + if not re.search(r"[/\\]Activate\.ps1$", path, re.IGNORECASE): + return ep + bash_path = path.replace("\\", "/") + bash_path = re.sub(r"/Activate\.ps1$", "/activate", bash_path, flags=re.IGNORECASE) + m = re.fullmatch(r"([A-Za-z]):/(.*)", bash_path) + if m: + bash_path = f"/{m.group(1).lower()}/{m.group(2)}" + return "source " + shlex.quote(bash_path) + + def _ssh_ps(host, script_path, port=None): """Build SSH command to run a PowerShell script on a Windows remote.""" pf = f"-p {port} " if port and port != "22" else "" diff --git a/routes/cookbook_routes.py b/routes/cookbook_routes.py index 1d79ba809..e2f1a184e 100644 --- a/routes/cookbook_routes.py +++ b/routes/cookbook_routes.py @@ -50,7 +50,7 @@ from routes.cookbook_helpers import ( _SESSION_ID_RE, _validate_repo_id, _validate_serve_model_id, _validate_include, _validate_token, _validate_local_dir, _validate_gpus, _shell_path, _ps_squote, _bash_squote, _validate_serve_cmd, _parse_serve_phase, OLLAMA_MISSING_HINT, - _safe_env_prefix, _local_tooling_path_export, _append_serve_preflight_exit_lines, + _safe_env_prefix, _local_windows_bash_env_prefix, _local_tooling_path_export, _append_serve_preflight_exit_lines, _append_serve_exit_code_lines, _append_llama_cpp_linux_accel_build_lines, _cached_model_scan_script, load_stored_hf_token, _append_vllm_linux_preflight_lines, _ollama_bind_from_cmd, _pip_install_fallback_chain, @@ -1298,7 +1298,7 @@ def setup_cookbook_routes() -> APIRouter: # Local: run hf download in the background (tmux on POSIX, a detached # process + logfile on Windows where tmux doesn't exist). if req.env_prefix: - lines.append(_safe_env_prefix(req.env_prefix)) + lines.append(_safe_env_prefix(_local_windows_bash_env_prefix(req.env_prefix) if local_windows else req.env_prefix)) else: lines.append("deactivate 2>/dev/null; hash -r") # Show whether the HF token reached this run (masked) — tells a gated @@ -2128,7 +2128,7 @@ def setup_cookbook_routes() -> APIRouter: if req.gpus: runner_lines.append(f"export CUDA_VISIBLE_DEVICES='{req.gpus}'") if req.env_prefix: - runner_lines.append(_safe_env_prefix(req.env_prefix)) + runner_lines.append(_safe_env_prefix(_local_windows_bash_env_prefix(req.env_prefix) if local_windows else req.env_prefix)) else: runner_lines.append("deactivate 2>/dev/null; hash -r") _append_venv_nvidia_library_path_lines(runner_lines, cmd=req.cmd) diff --git a/tests/test_cookbook_helpers.py b/tests/test_cookbook_helpers.py index bf6c47d4b..63d27c0ce 100644 --- a/tests/test_cookbook_helpers.py +++ b/tests/test_cookbook_helpers.py @@ -16,6 +16,7 @@ from routes.cookbook_helpers import ( _llama_cpp_rebuild_cmd, _append_vllm_linux_preflight_lines, _local_tooling_path_export, + _local_windows_bash_env_prefix, _pip_install_attempt, _pip_install_fallback_chain, _ollama_bind_from_cmd, @@ -107,6 +108,16 @@ def test_safe_env_prefix_accepts_powershell_activation_path(): ) +def test_local_windows_bash_env_prefix_converts_powershell_venv_activation(): + prefix = _local_windows_bash_env_prefix("& 'C:\\Users\\me\\venv\\Scripts\\Activate.ps1'") + + assert prefix == "source /c/Users/me/venv/Scripts/activate" + assert ( + _safe_env_prefix(prefix) + == '[ -f "/c/Users/me/venv/Scripts/activate" ] && source "/c/Users/me/venv/Scripts/activate" || true' + ) + + def test_validate_local_dir_accepts_external_drive_paths_with_spaces(): path = "/Volumes/T7 2TB/AI Models/llamacpp"