Skip to content

Commit 39ea15f

Browse files
authored
Add local dev commands for linking to rtc-sdk (#4258)
1 parent 264728a commit 39ea15f

1 file changed

Lines changed: 265 additions & 3 deletions

File tree

makefile

Lines changed: 265 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
.PHONY: help install format format-check lint check type-check test test-unit test-docker clean build
1+
.PHONY: help install format format-check lint lint-fix check type-check test test-unit test-docker clean build \
2+
link-rtc link-rtc-local link-rtc-version unlink-rtc status doctor
23

34
# Colors for output
45
CYAN := \033[36m
@@ -8,12 +9,31 @@ RED := \033[31m
89
RESET := \033[0m
910
BOLD := \033[1m
1011

12+
# Paths (computed as absolute paths)
13+
MAKEFILE_DIR := $(shell pwd)
14+
AGENTS_PROJECT := $(MAKEFILE_DIR)/livekit-agents
15+
PYTHON_RTC := $(MAKEFILE_DIR)/../python-sdks/livekit-rtc
16+
RUST_SUBMODULE := $(MAKEFILE_DIR)/../python-sdks/livekit-rtc/rust-sdks
17+
PACKAGE_NAME := livekit
18+
19+
# Platform and architecture auto-detection
20+
ARCH := $(shell uname -m)
21+
OS := $(shell uname -s | tr A-Z a-z)
22+
1123
# Default target
1224
.DEFAULT_GOAL := help
1325

1426
help: ## Show this help message
1527
@echo "$(BOLD)$(CYAN)Available targets:$(RESET)"
16-
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
28+
@echo ""
29+
@echo "$(BOLD)Development Workflows:$(RESET)"
30+
@grep -E '^(link-rtc|link-rtc-local|link-rtc-version|unlink-rtc|status|doctor):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
31+
@echo ""
32+
@echo "$(BOLD)Code Quality:$(RESET)"
33+
@grep -E '^(format|format-check|lint|lint-fix|type-check|check):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
34+
@echo ""
35+
@echo "$(BOLD)Other:$(RESET)"
36+
@grep -E '^(install|clean|build):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
1737

1838
install: ## Install all dependencies with dev extras
1939
@echo "$(BOLD)$(CYAN)Installing dependencies...$(RESET)"
@@ -97,4 +117,246 @@ type-check: ## Run mypy type checker
97117
fi
98118

99119
check: format-check lint type-check ## Run all checks (format, lint, type-check)
100-
@echo "$(BOLD)$(GREEN)✓ All checks passed!$(RESET)"
120+
@echo "$(BOLD)$(GREEN)✓ All checks passed!$(RESET)"
121+
122+
# ============================================
123+
# Development Workflows
124+
# ============================================
125+
126+
link-rtc: ## Link to local python-rtc (default FFI version)
127+
@echo "$(BOLD)$(CYAN)🐍 Linking local python-rtc with default FFI version...$(RESET)"
128+
@set -e; \
129+
DETECTED_ARCH="$(ARCH)"; \
130+
DETECTED_OS="$(OS)"; \
131+
if [ "$$DETECTED_ARCH" = "aarch64" ]; then \
132+
PLATFORM_ARCH="arm64"; \
133+
else \
134+
PLATFORM_ARCH="$$DETECTED_ARCH"; \
135+
fi; \
136+
if [ "$$DETECTED_OS" = "darwin" ]; then \
137+
PLATFORM_OS="macos"; \
138+
else \
139+
PLATFORM_OS="$$DETECTED_OS"; \
140+
fi; \
141+
echo "$(CYAN)📦 Downloading FFI artifacts for $$PLATFORM_OS-$$PLATFORM_ARCH...$(RESET)"; \
142+
cd $(PYTHON_RTC) && python rust-sdks/download_ffi.py --platform "$$PLATFORM_OS" --arch "$$PLATFORM_ARCH" --output livekit/rtc/resources; \
143+
echo "$(CYAN)🔗 Adding local python-rtc to agents...$(RESET)"; \
144+
cd $(AGENTS_PROJECT) && uv add --editable "../../python-sdks/livekit-rtc" && uv sync; \
145+
rm -f $(AGENTS_PROJECT)/.env; \
146+
echo "$(BOLD)$(GREEN)✅ Linked to local python-rtc (with default FFI version)$(RESET)"
147+
148+
link-rtc-local: ## Build and link local rust SDK from source
149+
@echo "$(BOLD)$(CYAN)🦀 Building and linking local rust SDK...$(RESET)"
150+
@set -e; \
151+
echo "$(CYAN)🦀 Building livekit-ffi...$(RESET)"; \
152+
cd $(RUST_SUBMODULE) && cargo build --release -p livekit-ffi; \
153+
echo "$(CYAN)📝 Generating protobuf FFI protocol...$(RESET)"; \
154+
cd $(PYTHON_RTC) && ./generate_proto.sh; \
155+
RUST_LIB_DIR="$$(cd $(RUST_SUBMODULE) && pwd)/target/release"; \
156+
if [ "$(OS)" = "darwin" ]; then \
157+
RUST_LIB_PATH="$$RUST_LIB_DIR/liblivekit_ffi.dylib"; \
158+
elif [ "$(OS)" = "linux" ]; then \
159+
RUST_LIB_PATH="$$RUST_LIB_DIR/liblivekit_ffi.so"; \
160+
else \
161+
RUST_LIB_PATH="$$RUST_LIB_DIR/livekit_ffi.dll"; \
162+
fi; \
163+
echo "$(CYAN) LIVEKIT_LIB_PATH=$$RUST_LIB_PATH$(RESET)"; \
164+
echo "$(CYAN)🔗 Adding local python-rtc to agents...$(RESET)"; \
165+
cd $(AGENTS_PROJECT) && uv add --editable "../../python-sdks/livekit-rtc" && uv sync; \
166+
echo "LIVEKIT_LIB_PATH=$$RUST_LIB_PATH" > $(AGENTS_PROJECT)/.env; \
167+
echo "$(BOLD)$(GREEN)✅ Linked to local rust-sdk + python-rtc$(RESET)"; \
168+
echo ""; \
169+
echo "$(BOLD)$(YELLOW)📋 To use the local rust lib in your terminal, run:$(RESET)"; \
170+
echo "$(BOLD) export LIVEKIT_LIB_PATH=$$RUST_LIB_PATH$(RESET)"
171+
172+
link-rtc-version: ## Install specific livekit version from PyPI (e.g., make link-rtc-version VERSION=0.18.0)
173+
ifndef VERSION
174+
@echo "$(BOLD)$(RED)Error: VERSION not specified. Use: make link-rtc-version VERSION=0.18.0$(RESET)"
175+
@exit 1
176+
endif
177+
@echo "$(BOLD)$(CYAN)📦 Installing livekit version $(VERSION)...$(RESET)"
178+
@set -e; \
179+
if grep -q "^livekit = { path = " pyproject.toml 2>/dev/null; then \
180+
echo "$(CYAN) Removing workspace root livekit source override...$(RESET)"; \
181+
sed -i.bak '/^livekit = { path = /d' pyproject.toml && rm -f pyproject.toml.bak; \
182+
fi; \
183+
cd $(AGENTS_PROJECT); \
184+
if grep -q "\[tool.uv.sources\]" pyproject.toml && grep -q "^livekit = " pyproject.toml; then \
185+
echo "$(CYAN) Removing [tool.uv.sources] override...$(RESET)"; \
186+
sed -i.bak '/^livekit = /d' pyproject.toml && rm -f pyproject.toml.bak; \
187+
fi; \
188+
uv remove $(PACKAGE_NAME) 2>/dev/null || true; \
189+
uv add "$(PACKAGE_NAME)==$(VERSION)" && uv sync; \
190+
rm -f .env; \
191+
echo "$(BOLD)$(GREEN)✅ Linked to livekit $(VERSION)$(RESET)"
192+
193+
unlink-rtc: ## Unlink local and restore PyPI version
194+
@echo "$(BOLD)$(CYAN)🔓 Unlinking local python-rtc...$(RESET)"
195+
@set -e; \
196+
if grep -q "^livekit = { path = " pyproject.toml 2>/dev/null; then \
197+
echo "$(CYAN) Removing workspace root livekit source override...$(RESET)"; \
198+
sed -i.bak '/^livekit = { path = /d' pyproject.toml && rm -f pyproject.toml.bak; \
199+
fi; \
200+
cd $(AGENTS_PROJECT); \
201+
if grep -q "\[tool.uv.sources\]" pyproject.toml; then \
202+
echo "$(CYAN) Removing [tool.uv.sources] override...$(RESET)"; \
203+
sed -i.bak '/\[tool.uv.sources\]/,/^livekit = /d' pyproject.toml && rm -f pyproject.toml.bak; \
204+
fi; \
205+
uv remove --dev $(PACKAGE_NAME) 2>/dev/null || true; \
206+
uv add --upgrade-package $(PACKAGE_NAME) $(PACKAGE_NAME) && uv sync; \
207+
rm -f .env; \
208+
echo "$(BOLD)$(GREEN)✅ Restored PyPI version$(RESET)"
209+
210+
status: ## Show current linking status
211+
@echo "$(BOLD)$(CYAN)📍 Current status:$(RESET)"
212+
@echo ""
213+
@set -e; \
214+
RUST_SUBMODULE_DIR="$$(cd $(RUST_SUBMODULE) 2>/dev/null && pwd || echo "")"; \
215+
cd $(AGENTS_PROJECT); \
216+
SHOW_OUTPUT=$$(uv pip show livekit 2>/dev/null || echo ""); \
217+
IS_LOCAL_EDITABLE=false; \
218+
if [ -z "$$SHOW_OUTPUT" ]; then \
219+
echo " livekit: NOT INSTALLED"; \
220+
elif echo "$$SHOW_OUTPUT" | grep -q "Editable project location:"; then \
221+
IS_LOCAL_EDITABLE=true; \
222+
VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}'); \
223+
LOCATION=$$(echo "$$SHOW_OUTPUT" | grep "Editable project location:" | cut -d' ' -f4-); \
224+
echo " livekit: LOCAL (editable) v$$VERSION"; \
225+
echo " path: $$LOCATION"; \
226+
else \
227+
VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}'); \
228+
echo " livekit: PyPI (v$$VERSION)"; \
229+
fi; \
230+
echo ""; \
231+
if [ -f .env ] && grep -q "LIVEKIT_LIB_PATH" .env; then \
232+
SUBMODULE_COMMIT=$$([ -n "$$RUST_SUBMODULE_DIR" ] && cd "$$RUST_SUBMODULE_DIR" 2>/dev/null && git rev-parse --short HEAD || echo 'unknown'); \
233+
echo " FFI: LOCAL BUILD (rust-sdks @ $$SUBMODULE_COMMIT)"; \
234+
elif [ "$$IS_LOCAL_EDITABLE" = "true" ]; then \
235+
FFI_PATH="$$(cd $(PYTHON_RTC) 2>/dev/null && pwd || echo "")/livekit/rtc/resources"; \
236+
if [ -d "$$FFI_PATH" ] && { [ -f "$$FFI_PATH/liblivekit_ffi.dylib" ] || [ -f "$$FFI_PATH/liblivekit_ffi.so" ] || [ -f "$$FFI_PATH/livekit_ffi.dll" ]; }; then \
237+
CARGO_TOML_PATH="$$RUST_SUBMODULE_DIR/livekit-ffi/Cargo.toml"; \
238+
if [ -f "$$CARGO_TOML_PATH" ]; then \
239+
FFI_VERSION=$$(grep '^version = ' "$$CARGO_TOML_PATH" | head -1 | sed 's/.*"\(.*\)".*/\1/'); \
240+
echo " FFI: PRE-BUILT ARTIFACTS (v$$FFI_VERSION)"; \
241+
else \
242+
echo " FFI: PRE-BUILT ARTIFACTS"; \
243+
fi; \
244+
else \
245+
echo " FFI: NOT AVAILABLE"; \
246+
fi; \
247+
else \
248+
echo " FFI: BUNDLED (PyPI package)"; \
249+
fi
250+
251+
doctor: ## Check development environment health
252+
@echo "$(BOLD)$(CYAN)🏥 Running diagnostics...$(RESET)"
253+
@echo ""
254+
@ISSUES=0; \
255+
echo "$(BOLD)📦 Required Tools:$(RESET)"; \
256+
if command -v uv &> /dev/null; then \
257+
UV_VERSION=$$(uv --version 2>&1 | head -1); \
258+
echo " ✓ uv: $$UV_VERSION"; \
259+
else \
260+
echo " ✗ uv: NOT FOUND"; \
261+
ISSUES=$$((ISSUES + 1)); \
262+
fi; \
263+
if command -v python &> /dev/null; then \
264+
PYTHON_VERSION=$$(python --version 2>&1); \
265+
echo " ✓ python: $$PYTHON_VERSION"; \
266+
else \
267+
echo " ✗ python: NOT FOUND"; \
268+
ISSUES=$$((ISSUES + 1)); \
269+
fi; \
270+
if command -v cargo &> /dev/null; then \
271+
CARGO_VERSION=$$(cargo --version 2>&1); \
272+
echo " ✓ cargo: $$CARGO_VERSION"; \
273+
else \
274+
echo " ⚠ cargo: NOT FOUND (required for 'make link-rtc-local')"; \
275+
fi; \
276+
if command -v git &> /dev/null; then \
277+
GIT_VERSION=$$(git --version 2>&1); \
278+
echo " ✓ git: $$GIT_VERSION"; \
279+
else \
280+
echo " ✗ git: NOT FOUND"; \
281+
ISSUES=$$((ISSUES + 1)); \
282+
fi; \
283+
echo ""; \
284+
echo "$(BOLD)📂 Repository Structure:$(RESET)"; \
285+
if [ -d "$(PYTHON_RTC)" ]; then \
286+
echo " ✓ python-rtc: $$(cd $(PYTHON_RTC) && pwd)"; \
287+
PYTHON_RTC_BRANCH=$$(cd $(PYTHON_RTC) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo ""); \
288+
if [ -n "$$PYTHON_RTC_BRANCH" ]; then \
289+
PYTHON_RTC_COMMIT=$$(cd $(PYTHON_RTC) && git rev-parse --short HEAD 2>/dev/null || echo "unknown"); \
290+
echo " Branch: $$PYTHON_RTC_BRANCH @ $$PYTHON_RTC_COMMIT"; \
291+
fi; \
292+
else \
293+
echo " ✗ python-rtc: NOT FOUND at $(PYTHON_RTC)"; \
294+
ISSUES=$$((ISSUES + 1)); \
295+
fi; \
296+
if [ -d "$(RUST_SUBMODULE)" ]; then \
297+
echo " ✓ rust-submodule: $$(cd $(RUST_SUBMODULE) && pwd)"; \
298+
if [ -e "$(RUST_SUBMODULE)/.git" ]; then \
299+
RUST_BRANCH=$$(cd $(RUST_SUBMODULE) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"); \
300+
RUST_COMMIT=$$(cd $(RUST_SUBMODULE) && git rev-parse --short HEAD 2>/dev/null || echo "unknown"); \
301+
RUST_TAG=$$(cd $(RUST_SUBMODULE) && git describe --exact-match --tags 2>/dev/null || echo ""); \
302+
if [ -n "$$RUST_TAG" ]; then \
303+
echo " Branch: $$RUST_BRANCH @ $$RUST_COMMIT (tag: $$RUST_TAG)"; \
304+
else \
305+
echo " Branch: $$RUST_BRANCH @ $$RUST_COMMIT"; \
306+
fi; \
307+
else \
308+
echo " ⚠ Not a git repository"; \
309+
fi; \
310+
else \
311+
echo " ✗ rust-submodule: NOT FOUND at $(RUST_SUBMODULE)"; \
312+
ISSUES=$$((ISSUES + 1)); \
313+
fi; \
314+
if [ -d "$(AGENTS_PROJECT)" ]; then \
315+
AGENTS_ABS_PATH=$$(cd $(AGENTS_PROJECT) && pwd); \
316+
echo " ✓ agents-project: $$AGENTS_ABS_PATH"; \
317+
AGENTS_REPO_ROOT=$$(cd $(MAKEFILE_DIR) && git rev-parse --show-toplevel 2>/dev/null || echo ""); \
318+
if [ -n "$$AGENTS_REPO_ROOT" ]; then \
319+
AGENTS_BRANCH=$$(cd $(MAKEFILE_DIR) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"); \
320+
AGENTS_COMMIT=$$(cd $(MAKEFILE_DIR) && git rev-parse --short HEAD 2>/dev/null || echo "unknown"); \
321+
echo " Branch: $$AGENTS_BRANCH @ $$AGENTS_COMMIT"; \
322+
fi; \
323+
else \
324+
echo " ✗ agents-project: NOT FOUND at $(AGENTS_PROJECT)"; \
325+
ISSUES=$$((ISSUES + 1)); \
326+
fi; \
327+
echo ""; \
328+
echo "$(BOLD)🔍 Current Configuration:$(RESET)"; \
329+
if [ -d ".venv" ]; then \
330+
echo " ✓ Virtual environment: .venv exists"; \
331+
else \
332+
echo " ⚠ Virtual environment: .venv not found (run 'make install')"; \
333+
fi; \
334+
cd $(AGENTS_PROJECT); \
335+
SHOW_OUTPUT=$$(uv pip show livekit 2>/dev/null || echo ""); \
336+
if [ -z "$$SHOW_OUTPUT" ]; then \
337+
echo " ✗ livekit: NOT INSTALLED"; \
338+
echo " Run 'make link-rtc' to set up"; \
339+
ISSUES=$$((ISSUES + 1)); \
340+
elif echo "$$SHOW_OUTPUT" | grep -q "Editable project location:"; then \
341+
VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}'); \
342+
echo " ✓ livekit: LOCAL (editable) v$$VERSION"; \
343+
else \
344+
VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}'); \
345+
echo " ✓ livekit: PyPI v$$VERSION"; \
346+
fi; \
347+
if [ -f .env ] && grep -q "LIVEKIT_LIB_PATH" .env; then \
348+
LIVEKIT_LIB_PATH=$$(grep "LIVEKIT_LIB_PATH" .env | cut -d'=' -f2); \
349+
if [ -d "$$LIVEKIT_LIB_PATH" ]; then \
350+
echo " ✓ FFI: Local build at $$LIVEKIT_LIB_PATH"; \
351+
else \
352+
echo " ✗ FFI: Local build path not found: $$LIVEKIT_LIB_PATH"; \
353+
ISSUES=$$((ISSUES + 1)); \
354+
fi; \
355+
fi; \
356+
echo ""; \
357+
if [ $$ISSUES -eq 0 ]; then \
358+
echo "$(BOLD)$(GREEN)✅ All checks passed! Environment is healthy.$(RESET)"; \
359+
else \
360+
echo "$(BOLD)$(RED)⚠️ Found $$ISSUES issue(s). Please fix the errors above.$(RESET)"; \
361+
exit 1; \
362+
fi

0 commit comments

Comments
 (0)