Skip to content

Commit 90f88c8

Browse files
committed
feat: add script to convert the project files to any other one that we support
1 parent 5a7c9c7 commit 90f88c8

File tree

4 files changed

+471
-0
lines changed

4 files changed

+471
-0
lines changed

Makefile

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Package Manager Conversion Tool for Python LiveKit Agent
2+
# This Makefile helps convert between different Python package managers
3+
4+
.PHONY: help convert-to-pip convert-to-poetry convert-to-pipenv convert-to-pdm convert-to-hatch convert-to-uv rollback list-backups clean-backups
5+
6+
# Default target shows help
7+
help:
8+
@echo "Package Manager Conversion Tool - Python"
9+
@echo "========================================="
10+
@echo ""
11+
@echo "⚠️ WARNING: Converting will reset Dockerfiles to LiveKit templates"
12+
@echo " Any custom Dockerfile modifications will be lost!"
13+
@echo ""
14+
@echo "Available conversion targets:"
15+
@echo " make convert-to-pip - Convert to pip (requirements.txt)"
16+
@echo " make convert-to-poetry - Convert to Poetry"
17+
@echo " make convert-to-pipenv - Convert to Pipenv"
18+
@echo " make convert-to-pdm - Convert to PDM"
19+
@echo " make convert-to-hatch - Convert to Hatch"
20+
@echo " make convert-to-uv - Convert to UV"
21+
@echo ""
22+
@echo "Backup management:"
23+
@echo " make rollback - Restore from backup (interactive if multiple)"
24+
@echo " make list-backups - Show available backups"
25+
@echo " make clean-backups - Remove all backup directories"
26+
@echo ""
27+
@echo "Notes:"
28+
@echo " • Backups are saved as .backup.{package-manager}"
29+
@echo " • Multiple conversions create multiple backups"
30+
@echo " • Rollback is interactive when multiple backups exist"
31+
@echo " • Lock files are NOT generated automatically - see instructions after conversion"
32+
33+
convert-to-pip:
34+
@bash scripts/convert-package-manager.sh pip
35+
36+
convert-to-poetry:
37+
@bash scripts/convert-package-manager.sh poetry
38+
39+
convert-to-pipenv:
40+
@bash scripts/convert-package-manager.sh pipenv
41+
42+
convert-to-pdm:
43+
@bash scripts/convert-package-manager.sh pdm
44+
45+
convert-to-hatch:
46+
@bash scripts/convert-package-manager.sh hatch
47+
48+
convert-to-uv:
49+
@bash scripts/convert-package-manager.sh uv
50+
51+
rollback:
52+
@bash scripts/rollback.sh
53+
54+
list-backups:
55+
@echo "Available backups:"
56+
@for dir in .backup.*; do \
57+
if [ -d "$$dir" ]; then \
58+
echo " $$dir"; \
59+
fi; \
60+
done 2>/dev/null || echo " No backups found"
61+
62+
clean-backups:
63+
@echo "Removing all backup directories..."
64+
@rm -rf .backup.* 2>/dev/null || true
65+
@echo "✔ All backups removed"

scripts/convert-package-manager.sh

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Configuration
6+
# GITHUB_BASE_URL="https://raw.githubusercontent.com/livekit/livekit-cli/refs/heads/main/pkg/agentfs/examples/"
7+
# Temporary until this is merged: https://github.com/livekit/livekit-cli/pull/644
8+
GITHUB_BASE_URL="https://raw.githubusercontent.com/livekit/livekit-cli/05790019cc1977abcc6452890811bda07f2e74b1/pkg/agentfs/examples"
9+
PROGRAM_MAIN="src/agent.py"
10+
11+
# Color codes for output
12+
RED='\033[0;31m'
13+
GREEN='\033[0;32m'
14+
YELLOW='\033[1;33m'
15+
NC='\033[0m' # No Color
16+
17+
# Get the target package manager from command line
18+
TARGET_PM="$1"
19+
20+
if [ -z "$TARGET_PM" ]; then
21+
echo -e "${RED}Error: No package manager specified${NC}"
22+
echo "Usage: $0 {pip|poetry|pipenv|pdm|hatch|uv}"
23+
exit 1
24+
fi
25+
26+
# Source the detection script
27+
source "$(dirname "$0")/detect-package-manager.sh"
28+
29+
# Detect current package manager
30+
CURRENT_PM=$(detect_current_pm)
31+
32+
echo -e "${GREEN}${NC} Detected current package manager: ${YELLOW}$CURRENT_PM${NC}"
33+
34+
# Create backup directory
35+
BACKUP_DIR=".backup.$CURRENT_PM"
36+
if [ "$CURRENT_PM" = "unknown" ]; then
37+
BACKUP_DIR=".backup.original"
38+
fi
39+
40+
echo " Creating backup: $BACKUP_DIR/"
41+
42+
# Create backup
43+
mkdir -p "$BACKUP_DIR"
44+
45+
# Backup existing files
46+
[ -f "Dockerfile" ] && cp "Dockerfile" "$BACKUP_DIR/"
47+
[ -f ".dockerignore" ] && cp ".dockerignore" "$BACKUP_DIR/"
48+
[ -f "pyproject.toml" ] && cp "pyproject.toml" "$BACKUP_DIR/"
49+
[ -f "requirements.txt" ] && cp "requirements.txt" "$BACKUP_DIR/"
50+
[ -f "Pipfile" ] && cp "Pipfile" "$BACKUP_DIR/"
51+
[ -f "Pipfile.lock" ] && cp "Pipfile.lock" "$BACKUP_DIR/"
52+
[ -f "poetry.lock" ] && cp "poetry.lock" "$BACKUP_DIR/"
53+
[ -f "pdm.lock" ] && cp "pdm.lock" "$BACKUP_DIR/"
54+
[ -f "uv.lock" ] && cp "uv.lock" "$BACKUP_DIR/"
55+
56+
echo ""
57+
echo -e "${GREEN}${NC} Fetching $TARGET_PM templates from GitHub"
58+
59+
# Download Dockerfile and dockerignore
60+
DOCKERFILE_URL="$GITHUB_BASE_URL/python.$TARGET_PM.Dockerfile"
61+
DOCKERIGNORE_URL="$GITHUB_BASE_URL/python.$TARGET_PM.dockerignore"
62+
63+
curl -sL "$DOCKERFILE_URL" -o Dockerfile.tmp
64+
if [ $? -ne 0 ]; then
65+
echo -e "${RED}Error: Failed to download Dockerfile${NC}"
66+
exit 1
67+
fi
68+
69+
curl -sL "$DOCKERIGNORE_URL" -o .dockerignore
70+
if [ $? -ne 0 ]; then
71+
echo -e "${RED}Error: Failed to download .dockerignore${NC}"
72+
exit 1
73+
fi
74+
75+
# Replace template variable in Dockerfile
76+
sed "s|{{\.ProgramMain}}|$PROGRAM_MAIN|g" Dockerfile.tmp > Dockerfile
77+
rm Dockerfile.tmp
78+
79+
echo " Downloaded: Dockerfile (from LiveKit template)"
80+
echo " Downloaded: .dockerignore (from LiveKit template)"
81+
echo ""
82+
echo -e "${YELLOW}⚠️ Note: Dockerfile has been reset to LiveKit template version${NC}"
83+
echo " Any custom modifications have been backed up"
84+
85+
# Generate package manager specific files
86+
echo ""
87+
echo -e "${GREEN}${NC} Generating $TARGET_PM configuration"
88+
89+
case "$TARGET_PM" in
90+
pip)
91+
# Generate requirements.txt from pyproject.toml
92+
if [ -f "pyproject.toml" ]; then
93+
python3 -c "
94+
import sys
95+
try:
96+
import tomllib
97+
except ImportError:
98+
try:
99+
import tomli as tomllib
100+
except ImportError:
101+
# Fallback to basic parsing
102+
import re
103+
with open('pyproject.toml', 'r') as f:
104+
content = f.read()
105+
# Extract dependencies with regex
106+
deps_match = re.search(r'dependencies = \[(.*?)\]', content, re.DOTALL)
107+
if deps_match:
108+
deps_str = deps_match.group(1)
109+
deps = re.findall(r'\"([^\"]+)\"', deps_str)
110+
for dep in deps:
111+
print(dep)
112+
sys.exit(0)
113+
114+
with open('pyproject.toml', 'rb') as f:
115+
data = tomllib.load(f)
116+
117+
deps = data.get('project', {}).get('dependencies', [])
118+
for dep in deps:
119+
print(dep)
120+
121+
# Also include dev dependencies as comments
122+
dev_groups = data.get('dependency-groups', {})
123+
if dev_groups:
124+
print('\n# Development dependencies:')
125+
for group, deps in dev_groups.items():
126+
print(f'# [{group}]')
127+
for dep in deps:
128+
print(f'# {dep}')
129+
" > requirements.txt
130+
echo " Generated: requirements.txt"
131+
else
132+
echo -e "${YELLOW}Warning: No pyproject.toml found to convert${NC}"
133+
fi
134+
;;
135+
136+
poetry)
137+
# Poetry can work with existing pyproject.toml
138+
if [ -f "pyproject.toml" ]; then
139+
echo " Note: Poetry will use existing pyproject.toml"
140+
echo " You may need to run 'poetry init' to add Poetry-specific metadata"
141+
else
142+
echo -e "${YELLOW}Warning: No pyproject.toml found${NC}"
143+
fi
144+
echo " Using: pyproject.toml"
145+
;;
146+
147+
pipenv)
148+
# Generate Pipfile from pyproject.toml
149+
if [ -f "pyproject.toml" ]; then
150+
# Create a basic Pipfile
151+
cat > Pipfile << 'EOF'
152+
[[source]]
153+
url = "https://pypi.org/simple"
154+
verify_ssl = true
155+
name = "pypi"
156+
157+
[packages]
158+
livekit-agents = {extras = ["openai", "turn-detector", "silero", "cartesia", "deepgram"], version = "~=1.2"}
159+
livekit-plugins-noise-cancellation = "~=0.2"
160+
python-dotenv = "*"
161+
162+
[dev-packages]
163+
pytest = "*"
164+
pytest-asyncio = "*"
165+
ruff = "*"
166+
167+
[requires]
168+
python_version = "3.9"
169+
EOF
170+
echo " Generated: Pipfile"
171+
else
172+
echo -e "${YELLOW}Warning: Creating basic Pipfile${NC}"
173+
cat > Pipfile << 'EOF'
174+
[[source]]
175+
url = "https://pypi.org/simple"
176+
verify_ssl = true
177+
name = "pypi"
178+
179+
[packages]
180+
181+
[dev-packages]
182+
183+
[requires]
184+
python_version = "3.9"
185+
EOF
186+
echo " Generated: Pipfile (basic template)"
187+
fi
188+
;;
189+
190+
pdm|hatch|uv)
191+
# These use pyproject.toml, just ensure it exists
192+
if [ ! -f "pyproject.toml" ]; then
193+
echo -e "${YELLOW}Warning: No pyproject.toml found${NC}"
194+
else
195+
echo " Using existing: pyproject.toml"
196+
fi
197+
;;
198+
esac
199+
200+
echo " Entry point: $PROGRAM_MAIN"
201+
202+
# Display instructions based on package manager
203+
echo ""
204+
echo "Next steps:"
205+
echo " › Install $TARGET_PM:"
206+
207+
case "$TARGET_PM" in
208+
pip)
209+
echo " # pip is usually pre-installed with Python"
210+
echo ""
211+
echo " › Install dependencies:"
212+
echo " pip install -r requirements.txt"
213+
echo ""
214+
echo " › For reproducible builds, generate lock file:"
215+
echo " pip freeze > requirements.lock"
216+
;;
217+
poetry)
218+
echo " curl -sSL https://install.python-poetry.org | python3 -"
219+
echo ""
220+
echo " › Generate lock file:"
221+
echo " poetry lock"
222+
echo ""
223+
echo " › Install dependencies:"
224+
echo " poetry install"
225+
;;
226+
pipenv)
227+
echo " pip install pipenv"
228+
echo ""
229+
echo " › Generate lock file:"
230+
echo " pipenv lock"
231+
echo ""
232+
echo " › Install dependencies:"
233+
echo " pipenv install"
234+
;;
235+
pdm)
236+
echo " pip install pdm"
237+
echo ""
238+
echo " › Generate lock file:"
239+
echo " pdm lock"
240+
echo ""
241+
echo " › Install dependencies:"
242+
echo " pdm install"
243+
;;
244+
hatch)
245+
echo " pip install hatch"
246+
echo ""
247+
echo " › Create environment:"
248+
echo " hatch env create"
249+
echo ""
250+
echo " › Install dependencies:"
251+
echo " hatch env run pip install -e ."
252+
;;
253+
uv)
254+
echo " curl -LsSf https://astral.sh/uv/install.sh | sh"
255+
echo ""
256+
echo " › Generate lock file:"
257+
echo " uv lock"
258+
echo ""
259+
echo " › Install dependencies:"
260+
echo " uv sync"
261+
;;
262+
esac
263+
264+
echo ""
265+
echo " › Test locally:"
266+
echo " python $PROGRAM_MAIN dev"
267+
echo ""
268+
echo " › Build Docker image:"
269+
echo " docker build -t my-agent ."
270+
echo ""
271+
echo "To rollback: make rollback"
272+
273+
# List existing backups
274+
BACKUP_COUNT=$(ls -d .backup.* 2>/dev/null | wc -l)
275+
if [ $BACKUP_COUNT -gt 0 ]; then
276+
echo "Existing backups: $(ls -d .backup.* | tr '\n' ' ')"
277+
fi

0 commit comments

Comments
 (0)