Fix Windows startup and dependency checks (#1709)
* windows check and dev fixes * fix windows startup scripts * fix windows startup scripts --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
parent
e97c8c9943
commit
82c3dbbc6b
11
Makefile
11
Makefile
|
|
@ -2,12 +2,14 @@
|
||||||
|
|
||||||
.PHONY: help config config-upgrade check install dev dev-daemon start stop up down clean docker-init docker-start docker-stop docker-logs docker-logs-frontend docker-logs-gateway
|
.PHONY: help config config-upgrade check install dev dev-daemon start stop up down clean docker-init docker-start docker-stop docker-logs docker-logs-frontend docker-logs-gateway
|
||||||
|
|
||||||
PYTHON ?= python
|
|
||||||
BASH ?= bash
|
BASH ?= bash
|
||||||
|
|
||||||
# Detect OS for Windows compatibility
|
# Detect OS for Windows compatibility
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
SHELL := cmd.exe
|
SHELL := cmd.exe
|
||||||
|
PYTHON ?= python
|
||||||
|
else
|
||||||
|
PYTHON ?= python3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
help:
|
help:
|
||||||
|
|
@ -96,6 +98,7 @@ setup-sandbox:
|
||||||
|
|
||||||
# Start all services in development mode (with hot-reloading)
|
# Start all services in development mode (with hot-reloading)
|
||||||
dev:
|
dev:
|
||||||
|
@$(PYTHON) ./scripts/check.py
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
@call scripts\run-with-git-bash.cmd ./scripts/serve.sh --dev
|
@call scripts\run-with-git-bash.cmd ./scripts/serve.sh --dev
|
||||||
else
|
else
|
||||||
|
|
@ -104,6 +107,7 @@ endif
|
||||||
|
|
||||||
# Start all services in production mode (with optimizations)
|
# Start all services in production mode (with optimizations)
|
||||||
start:
|
start:
|
||||||
|
@$(PYTHON) ./scripts/check.py
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
@call scripts\run-with-git-bash.cmd ./scripts/serve.sh --prod
|
@call scripts\run-with-git-bash.cmd ./scripts/serve.sh --prod
|
||||||
else
|
else
|
||||||
|
|
@ -112,7 +116,12 @@ endif
|
||||||
|
|
||||||
# Start all services in daemon mode (background)
|
# Start all services in daemon mode (background)
|
||||||
dev-daemon:
|
dev-daemon:
|
||||||
|
@$(PYTHON) ./scripts/check.py
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
@call scripts\run-with-git-bash.cmd ./scripts/start-daemon.sh
|
||||||
|
else
|
||||||
@./scripts/start-daemon.sh
|
@./scripts/start-daemon.sh
|
||||||
|
endif
|
||||||
|
|
||||||
# Stop all services
|
# Stop all services
|
||||||
stop:
|
stop:
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed Docker development guide.
|
||||||
If you prefer running services locally:
|
If you prefer running services locally:
|
||||||
|
|
||||||
Prerequisite: complete the "Configuration" steps above first (`make config` and model API keys). `make dev` requires a valid configuration file (defaults to `config.yaml` in the project root; can be overridden via `DEER_FLOW_CONFIG_PATH`).
|
Prerequisite: complete the "Configuration" steps above first (`make config` and model API keys). `make dev` requires a valid configuration file (defaults to `config.yaml` in the project root; can be overridden via `DEER_FLOW_CONFIG_PATH`).
|
||||||
|
On Windows, run the local development flow from Git Bash. Native `cmd.exe` and PowerShell shells are not supported for the bash-based service scripts, and WSL is not guaranteed because some scripts rely on Git for Windows utilities such as `cygpath`.
|
||||||
|
|
||||||
1. **Check prerequisites**:
|
1. **Check prerequisites**:
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,7 @@ make down # 停止并移除容器
|
||||||
如果你更希望直接在本地启动各个服务:
|
如果你更希望直接在本地启动各个服务:
|
||||||
|
|
||||||
前提:先完成上面的“配置”步骤(`make config` 和模型 API key 配置)。`make dev` 需要有效配置文件,默认读取项目根目录下的 `config.yaml`,也可以通过 `DEER_FLOW_CONFIG_PATH` 覆盖。
|
前提:先完成上面的“配置”步骤(`make config` 和模型 API key 配置)。`make dev` 需要有效配置文件,默认读取项目根目录下的 `config.yaml`,也可以通过 `DEER_FLOW_CONFIG_PATH` 覆盖。
|
||||||
|
在 Windows 上,请使用 Git Bash 运行本地开发流程。基于 bash 的服务脚本不支持直接在原生 `cmd.exe` 或 PowerShell 中执行,且 WSL 也不保证可用,因为部分脚本依赖 Git for Windows 的 `cygpath` 等工具。
|
||||||
|
|
||||||
1. **检查依赖环境**:
|
1. **检查依赖环境**:
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,18 @@ def run_command(command: list[str]) -> Optional[str]:
|
||||||
return result.stdout.strip() or result.stderr.strip()
|
return result.stdout.strip() or result.stderr.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def find_pnpm_command() -> Optional[list[str]]:
|
||||||
|
"""Return a pnpm-compatible command that exists on this machine."""
|
||||||
|
candidates = [["pnpm"], ["pnpm.cmd"]]
|
||||||
|
if shutil.which("corepack"):
|
||||||
|
candidates.append(["corepack", "pnpm"])
|
||||||
|
|
||||||
|
for command in candidates:
|
||||||
|
if shutil.which(command[0]):
|
||||||
|
return command
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def parse_node_major(version_text: str) -> Optional[int]:
|
def parse_node_major(version_text: str) -> Optional[int]:
|
||||||
version = version_text.strip()
|
version = version_text.strip()
|
||||||
if version.startswith("v"):
|
if version.startswith("v"):
|
||||||
|
|
@ -55,35 +67,39 @@ def main() -> int:
|
||||||
if node_version:
|
if node_version:
|
||||||
major = parse_node_major(node_version)
|
major = parse_node_major(node_version)
|
||||||
if major is not None and major >= 22:
|
if major is not None and major >= 22:
|
||||||
print(f" ✓ Node.js {node_version.lstrip('v')} (>= 22 required)")
|
print(f" OK Node.js {node_version.lstrip('v')} (>= 22 required)")
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
f" ✗ Node.js {node_version.lstrip('v')} found, but version 22+ is required"
|
f" FAIL Node.js {node_version.lstrip('v')} found, but version 22+ is required"
|
||||||
)
|
)
|
||||||
print(" Install from: https://nodejs.org/")
|
print(" Install from: https://nodejs.org/")
|
||||||
failed = True
|
failed = True
|
||||||
else:
|
else:
|
||||||
print(" ✗ Unable to determine Node.js version")
|
print(" INFO Unable to determine Node.js version")
|
||||||
print(" Install from: https://nodejs.org/")
|
print(" Install from: https://nodejs.org/")
|
||||||
failed = True
|
failed = True
|
||||||
else:
|
else:
|
||||||
print(" ✗ Node.js not found (version 22+ required)")
|
print(" FAIL Node.js not found (version 22+ required)")
|
||||||
print(" Install from: https://nodejs.org/")
|
print(" Install from: https://nodejs.org/")
|
||||||
failed = True
|
failed = True
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print("Checking pnpm...")
|
print("Checking pnpm...")
|
||||||
pnpm_executable = shutil.which("pnpm.cmd") or shutil.which("pnpm")
|
pnpm_command = find_pnpm_command()
|
||||||
if pnpm_executable:
|
if pnpm_command:
|
||||||
pnpm_version = run_command([pnpm_executable, "-v"])
|
pnpm_version = run_command([*pnpm_command, "-v"])
|
||||||
if pnpm_version:
|
if pnpm_version:
|
||||||
print(f" ✓ pnpm {pnpm_version}")
|
if pnpm_command[0] == "corepack":
|
||||||
|
print(f" OK pnpm {pnpm_version} (via Corepack)")
|
||||||
else:
|
else:
|
||||||
print(" ✗ Unable to determine pnpm version")
|
print(f" OK pnpm {pnpm_version}")
|
||||||
|
else:
|
||||||
|
print(" INFO Unable to determine pnpm version")
|
||||||
failed = True
|
failed = True
|
||||||
else:
|
else:
|
||||||
print(" ✗ pnpm not found")
|
print(" FAIL pnpm not found")
|
||||||
print(" Install: npm install -g pnpm")
|
print(" Install: npm install -g pnpm")
|
||||||
|
print(" Or enable Corepack: corepack enable")
|
||||||
print(" Or visit: https://pnpm.io/installation")
|
print(" Or visit: https://pnpm.io/installation")
|
||||||
failed = True
|
failed = True
|
||||||
|
|
||||||
|
|
@ -92,13 +108,14 @@ def main() -> int:
|
||||||
if shutil.which("uv"):
|
if shutil.which("uv"):
|
||||||
uv_version_text = run_command(["uv", "--version"])
|
uv_version_text = run_command(["uv", "--version"])
|
||||||
if uv_version_text:
|
if uv_version_text:
|
||||||
uv_version = uv_version_text.split()[-1]
|
uv_version_parts = uv_version_text.split()
|
||||||
print(f" ✓ uv {uv_version}")
|
uv_version = uv_version_parts[1] if len(uv_version_parts) > 1 else uv_version_text
|
||||||
|
print(f" OK uv {uv_version}")
|
||||||
else:
|
else:
|
||||||
print(" ✗ Unable to determine uv version")
|
print(" INFO Unable to determine uv version")
|
||||||
failed = True
|
failed = True
|
||||||
else:
|
else:
|
||||||
print(" ✗ uv not found")
|
print(" FAIL uv not found")
|
||||||
print(" Visit the official installation guide for your platform:")
|
print(" Visit the official installation guide for your platform:")
|
||||||
print(" https://docs.astral.sh/uv/getting-started/installation/")
|
print(" https://docs.astral.sh/uv/getting-started/installation/")
|
||||||
failed = True
|
failed = True
|
||||||
|
|
@ -109,11 +126,11 @@ def main() -> int:
|
||||||
nginx_version_text = run_command(["nginx", "-v"])
|
nginx_version_text = run_command(["nginx", "-v"])
|
||||||
if nginx_version_text and "/" in nginx_version_text:
|
if nginx_version_text and "/" in nginx_version_text:
|
||||||
nginx_version = nginx_version_text.split("/", 1)[1]
|
nginx_version = nginx_version_text.split("/", 1)[1]
|
||||||
print(f" ✓ nginx {nginx_version}")
|
print(f" OK nginx {nginx_version}")
|
||||||
else:
|
else:
|
||||||
print(" ✓ nginx (version unknown)")
|
print(" INFO nginx (version unknown)")
|
||||||
else:
|
else:
|
||||||
print(" ✗ nginx not found")
|
print(" FAIL nginx not found")
|
||||||
print(" macOS: brew install nginx")
|
print(" macOS: brew install nginx")
|
||||||
print(" Ubuntu: sudo apt install nginx")
|
print(" Ubuntu: sudo apt install nginx")
|
||||||
print(" Windows: use WSL for local mode or use Docker mode")
|
print(" Windows: use WSL for local mode or use Docker mode")
|
||||||
|
|
@ -123,7 +140,7 @@ def main() -> int:
|
||||||
print()
|
print()
|
||||||
if not failed:
|
if not failed:
|
||||||
print("==========================================")
|
print("==========================================")
|
||||||
print(" ✓ All dependencies are installed!")
|
print(" OK All dependencies are installed!")
|
||||||
print("==========================================")
|
print("==========================================")
|
||||||
print()
|
print()
|
||||||
print("You can now run:")
|
print("You can now run:")
|
||||||
|
|
@ -134,7 +151,7 @@ def main() -> int:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
print("==========================================")
|
print("==========================================")
|
||||||
print(" ✗ Some dependencies are missing")
|
print(" FAIL Some dependencies are missing")
|
||||||
print("==========================================")
|
print("==========================================")
|
||||||
print()
|
print()
|
||||||
print("Please install the missing tools and run 'make check' again.")
|
print("Please install the missing tools and run 'make check' again.")
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,28 @@ fi
|
||||||
if [ -z "$CONFIG" ]; then
|
if [ -z "$CONFIG" ]; then
|
||||||
echo "No config.yaml found — creating from example..."
|
echo "No config.yaml found — creating from example..."
|
||||||
cp "$EXAMPLE" "$REPO_ROOT/config.yaml"
|
cp "$EXAMPLE" "$REPO_ROOT/config.yaml"
|
||||||
echo "✓ config.yaml created. Please review and set your API keys."
|
echo "OK config.yaml created. Please review and set your API keys."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use inline Python to do migrations + recursive merge with PyYAML
|
# Use inline Python to do migrations + recursive merge with PyYAML
|
||||||
cd "$REPO_ROOT/backend" && uv run python3 -c "
|
if command -v cygpath >/dev/null 2>&1; then
|
||||||
|
CONFIG_WIN="$(cygpath -w "$CONFIG")"
|
||||||
|
EXAMPLE_WIN="$(cygpath -w "$EXAMPLE")"
|
||||||
|
else
|
||||||
|
CONFIG_WIN="$CONFIG"
|
||||||
|
EXAMPLE_WIN="$EXAMPLE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$REPO_ROOT/backend" && CONFIG_WIN_PATH="$CONFIG_WIN" EXAMPLE_WIN_PATH="$EXAMPLE_WIN" uv run python -c "
|
||||||
|
import os
|
||||||
import sys, shutil, copy, re
|
import sys, shutil, copy, re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
config_path = Path('$CONFIG')
|
config_path = Path(os.environ['CONFIG_WIN_PATH'])
|
||||||
example_path = Path('$EXAMPLE')
|
example_path = Path(os.environ['EXAMPLE_WIN_PATH'])
|
||||||
|
|
||||||
with open(config_path, encoding='utf-8') as f:
|
with open(config_path, encoding='utf-8') as f:
|
||||||
raw_text = f.read()
|
raw_text = f.read()
|
||||||
|
|
@ -55,10 +64,10 @@ user_version = user.get('config_version', 0)
|
||||||
example_version = example.get('config_version', 0)
|
example_version = example.get('config_version', 0)
|
||||||
|
|
||||||
if user_version >= example_version:
|
if user_version >= example_version:
|
||||||
print(f'✓ config.yaml is already up to date (version {user_version}).')
|
print(f'OK config.yaml is already up to date (version {user_version}).')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
print(f'Upgrading config.yaml: version {user_version} → {example_version}')
|
print(f'Upgrading config.yaml: version {user_version} -> {example_version}')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
# ── Migrations ───────────────────────────────────────────────────────────
|
# ── Migrations ───────────────────────────────────────────────────────────
|
||||||
|
|
@ -93,7 +102,7 @@ for version in range(user_version + 1, example_version + 1):
|
||||||
for old, new in migration.get('replacements', []):
|
for old, new in migration.get('replacements', []):
|
||||||
if old in raw_text:
|
if old in raw_text:
|
||||||
raw_text = raw_text.replace(old, new)
|
raw_text = raw_text.replace(old, new)
|
||||||
migrated.append(f'{old} → {new}')
|
migrated.append(f'{old} -> {new}')
|
||||||
|
|
||||||
# Re-parse after text migrations
|
# Re-parse after text migrations
|
||||||
user = yaml.safe_load(raw_text) or {}
|
user = yaml.safe_load(raw_text) or {}
|
||||||
|
|
@ -141,6 +150,6 @@ if not migrated and not added:
|
||||||
print('No changes needed (version bumped only).')
|
print('No changes needed (version bumped only).')
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print(f'✓ config.yaml upgraded to version {example_version}.')
|
print(f'OK config.yaml upgraded to version {example_version}.')
|
||||||
print(' Please review the changes and set any new required values.')
|
print(' Please review the changes and set any new required values.')
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,15 @@ done
|
||||||
if $DEV_MODE; then
|
if $DEV_MODE; then
|
||||||
FRONTEND_CMD="pnpm run dev"
|
FRONTEND_CMD="pnpm run dev"
|
||||||
else
|
else
|
||||||
FRONTEND_CMD="env BETTER_AUTH_SECRET=$(python3 -c 'import secrets; print(secrets.token_hex(16))') pnpm run preview"
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
|
PYTHON_BIN="python3"
|
||||||
|
elif command -v python >/dev/null 2>&1; then
|
||||||
|
PYTHON_BIN="python"
|
||||||
|
else
|
||||||
|
echo "Python is required to generate BETTER_AUTH_SECRET, but neither python3 nor python was found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
FRONTEND_CMD="env BETTER_AUTH_SECRET=$($PYTHON_BIN -c 'import secrets; print(secrets.token_hex(16))') pnpm run preview"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Stop existing services ────────────────────────────────────────────────────
|
# ── Stop existing services ────────────────────────────────────────────────────
|
||||||
|
|
@ -121,6 +129,7 @@ trap cleanup INT TERM
|
||||||
# ── Start services ────────────────────────────────────────────────────────────
|
# ── Start services ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
mkdir -p logs
|
mkdir -p logs
|
||||||
|
mkdir -p temp/client_body_temp temp/proxy_temp temp/fastcgi_temp temp/uwsgi_temp temp/scgi_temp
|
||||||
|
|
||||||
if $DEV_MODE; then
|
if $DEV_MODE; then
|
||||||
LANGGRAPH_EXTRA_FLAGS="--no-reload"
|
LANGGRAPH_EXTRA_FLAGS="--no-reload"
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ trap cleanup_on_failure INT TERM
|
||||||
# ── Start services ────────────────────────────────────────────────────────────
|
# ── Start services ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
mkdir -p logs
|
mkdir -p logs
|
||||||
|
mkdir -p temp/client_body_temp temp/proxy_temp temp/fastcgi_temp temp/uwsgi_temp temp/scgi_temp
|
||||||
|
|
||||||
echo "Starting LangGraph server..."
|
echo "Starting LangGraph server..."
|
||||||
nohup sh -c 'cd backend && NO_COLOR=1 uv run langgraph dev --no-browser --allow-blocking --no-reload > ../logs/langgraph.log 2>&1' &
|
nohup sh -c 'cd backend && NO_COLOR=1 uv run langgraph dev --no-browser --allow-blocking --no-reload > ../logs/langgraph.log 2>&1' &
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue