|
@@ -0,0 +1,313 @@
|
|
|
+#!/bin/bash
|
|
|
+
|
|
|
+# =============================================================================
|
|
|
+# UV Migration Script (Robust Version)
|
|
|
+# =============================================================================
|
|
|
+# Migrates from pip/venv to uv package manager
|
|
|
+# Enhanced error handling for production environments
|
|
|
+# =============================================================================
|
|
|
+
|
|
|
+# Don't exit on errors - handle them gracefully
|
|
|
+set +e
|
|
|
+
|
|
|
+# Colors for output
|
|
|
+RED='\033[0;31m'
|
|
|
+GREEN='\033[0;32m'
|
|
|
+YELLOW='\033[1;33m'
|
|
|
+BLUE='\033[0;34m'
|
|
|
+NC='\033[0m' # No Color
|
|
|
+
|
|
|
+# Script version
|
|
|
+VERSION="1.1.0-robust"
|
|
|
+
|
|
|
+# Print header
|
|
|
+echo -e "${BLUE}=================================${NC}"
|
|
|
+echo -e "${BLUE} UV Migration Script v${VERSION}${NC}"
|
|
|
+echo -e "${BLUE}=================================${NC}"
|
|
|
+echo ""
|
|
|
+
|
|
|
+# Function to print colored output
|
|
|
+print_success() {
|
|
|
+ echo -e "${GREEN}✅ $1${NC}"
|
|
|
+}
|
|
|
+
|
|
|
+print_warning() {
|
|
|
+ echo -e "${YELLOW}⚠️ $1${NC}"
|
|
|
+}
|
|
|
+
|
|
|
+print_error() {
|
|
|
+ echo -e "${RED}❌ $1${NC}"
|
|
|
+}
|
|
|
+
|
|
|
+print_info() {
|
|
|
+ echo -e "${BLUE}ℹ️ $1${NC}"
|
|
|
+}
|
|
|
+
|
|
|
+# Function to check if command exists
|
|
|
+command_exists() {
|
|
|
+ command -v "$1" >/dev/null 2>&1
|
|
|
+}
|
|
|
+
|
|
|
+# Function to get file size in human readable format
|
|
|
+get_size() {
|
|
|
+ if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
|
+ # macOS
|
|
|
+ du -h "$1" 2>/dev/null | cut -f1 || echo "0B"
|
|
|
+ else
|
|
|
+ # Linux
|
|
|
+ du -sh "$1" 2>/dev/null | cut -f1 || echo "0B"
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+# Check if we're in the project root
|
|
|
+if [[ ! -f "pyproject.toml" && ! -f "requirements.txt" ]]; then
|
|
|
+ print_error "Neither pyproject.toml nor requirements.txt found. Please run this script from the project root."
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+print_info "Starting migration process..."
|
|
|
+echo ""
|
|
|
+
|
|
|
+# =============================================================================
|
|
|
+# Step 1: Pre-migration Analysis
|
|
|
+# =============================================================================
|
|
|
+echo -e "${BLUE}📊 Pre-migration Analysis${NC}"
|
|
|
+echo "----------------------------"
|
|
|
+
|
|
|
+# Count cache files before cleanup (with timeout to prevent hanging)
|
|
|
+print_info "Analyzing project files (this may take a moment)..."
|
|
|
+PYCACHE_DIRS=$(timeout 30 find . -path "./.venv" -prune -o -path "./venv" -prune -o -name "__pycache__" -type d -print 2>/dev/null | wc -l | tr -d ' ')
|
|
|
+PYC_FILES=$(timeout 30 find . -path "./.venv" -prune -o -path "./venv" -prune -o -name "*.pyc" -type f -print 2>/dev/null | wc -l | tr -d ' ')
|
|
|
+
|
|
|
+echo "📁 Cache directories found: $PYCACHE_DIRS"
|
|
|
+echo "📄 .pyc files found: $PYC_FILES"
|
|
|
+
|
|
|
+# Check if pytest cache exists
|
|
|
+if [[ -d ".pytest_cache" ]]; then
|
|
|
+ PYTEST_SIZE=$(get_size ".pytest_cache")
|
|
|
+ echo "🧪 Pytest cache size: $PYTEST_SIZE"
|
|
|
+else
|
|
|
+ echo "🧪 No pytest cache found"
|
|
|
+fi
|
|
|
+
|
|
|
+# Check for old venv
|
|
|
+if [[ -d "venv" ]]; then
|
|
|
+ print_warning "Old 'venv' directory still exists!"
|
|
|
+ VENV_SIZE=$(get_size "venv")
|
|
|
+ echo "📦 Old venv size: $VENV_SIZE"
|
|
|
+else
|
|
|
+ print_success "No old 'venv' directory found"
|
|
|
+fi
|
|
|
+
|
|
|
+# Check for requirements.txt
|
|
|
+if [[ -f "requirements.txt" ]]; then
|
|
|
+ print_warning "requirements.txt still exists (should be removed after migration)"
|
|
|
+else
|
|
|
+ print_success "requirements.txt already removed"
|
|
|
+fi
|
|
|
+
|
|
|
+echo ""
|
|
|
+
|
|
|
+# =============================================================================
|
|
|
+# Step 2: UV Installation Check
|
|
|
+# =============================================================================
|
|
|
+echo -e "${BLUE}🔧 UV Installation Check${NC}"
|
|
|
+echo "----------------------------"
|
|
|
+
|
|
|
+# Add UV to PATH if it exists
|
|
|
+export PATH="$HOME/.local/bin:$PATH"
|
|
|
+
|
|
|
+if command_exists uv; then
|
|
|
+ UV_VERSION=$(uv --version 2>/dev/null | head -1)
|
|
|
+ print_success "UV installed: $UV_VERSION"
|
|
|
+else
|
|
|
+ print_error "UV not found! Installing UV..."
|
|
|
+ if command_exists curl; then
|
|
|
+ curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
|
+ # Add to PATH for this session
|
|
|
+ export PATH="$HOME/.local/bin:$PATH"
|
|
|
+ if command_exists uv; then
|
|
|
+ UV_VERSION=$(uv --version 2>/dev/null | head -1)
|
|
|
+ print_success "UV installed successfully: $UV_VERSION"
|
|
|
+ else
|
|
|
+ print_error "UV installation failed!"
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+ else
|
|
|
+ print_error "curl not found! Please install UV manually."
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+fi
|
|
|
+
|
|
|
+echo ""
|
|
|
+
|
|
|
+# =============================================================================
|
|
|
+# Step 3: Cache Cleanup (Robust Version)
|
|
|
+# =============================================================================
|
|
|
+echo -e "${BLUE}🧹 Cache Cleanup${NC}"
|
|
|
+echo "-------------------"
|
|
|
+
|
|
|
+# Ask for confirmation unless --force flag is provided
|
|
|
+if [[ "$1" != "--force" ]]; then
|
|
|
+ echo "This will delete:"
|
|
|
+ echo " - $PYCACHE_DIRS __pycache__ directories"
|
|
|
+ echo " - $PYC_FILES .pyc files"
|
|
|
+ echo " - .pytest_cache directory (if exists)"
|
|
|
+ echo ""
|
|
|
+ read -p "Continue with cleanup? (y/N): " -n 1 -r
|
|
|
+ echo
|
|
|
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
|
+ print_warning "Cleanup cancelled by user"
|
|
|
+ exit 0
|
|
|
+ fi
|
|
|
+fi
|
|
|
+
|
|
|
+print_info "Starting cleanup (using robust method for large file counts)..."
|
|
|
+
|
|
|
+# Method 1: Use xargs for better handling of large file lists
|
|
|
+DELETED_DIRS=0
|
|
|
+DELETED_FILES=0
|
|
|
+
|
|
|
+# Clean __pycache__ directories in batches
|
|
|
+print_info "Cleaning __pycache__ directories..."
|
|
|
+if find . -path "./.venv" -prune -o -path "./venv" -prune -o -name "__pycache__" -type d -print0 2>/dev/null | xargs -0 -r rm -rf; then
|
|
|
+ DELETED_DIRS=$(echo "$PYCACHE_DIRS")
|
|
|
+ print_success "Cleaned $DELETED_DIRS cache directories"
|
|
|
+else
|
|
|
+ print_warning "Some cache directories could not be deleted (may be permission issues)"
|
|
|
+fi
|
|
|
+
|
|
|
+# Clean .pyc files in batches
|
|
|
+print_info "Cleaning .pyc files..."
|
|
|
+if find . -path "./.venv" -prune -o -path "./venv" -prune -o -name "*.pyc" -type f -print0 2>/dev/null | xargs -0 -r rm -f; then
|
|
|
+ DELETED_FILES=$(echo "$PYC_FILES")
|
|
|
+ print_success "Cleaned $DELETED_FILES .pyc files"
|
|
|
+else
|
|
|
+ print_warning "Some .pyc files could not be deleted"
|
|
|
+fi
|
|
|
+
|
|
|
+# Clean .pyo files
|
|
|
+print_info "Cleaning .pyo files..."
|
|
|
+find . -path "./.venv" -prune -o -path "./venv" -prune -o -name "*.pyo" -type f -print0 2>/dev/null | xargs -0 -r rm -f
|
|
|
+
|
|
|
+# Remove pytest cache
|
|
|
+if [[ -d ".pytest_cache" ]]; then
|
|
|
+ if rm -rf ".pytest_cache" 2>/dev/null; then
|
|
|
+ print_success "Removed .pytest_cache directory"
|
|
|
+ else
|
|
|
+ print_warning "Could not remove .pytest_cache directory"
|
|
|
+ fi
|
|
|
+fi
|
|
|
+
|
|
|
+print_success "Cleanup phase completed!"
|
|
|
+
|
|
|
+echo ""
|
|
|
+
|
|
|
+# =============================================================================
|
|
|
+# Step 4: UV Environment Setup
|
|
|
+# =============================================================================
|
|
|
+echo -e "${BLUE}🔍 UV Environment Setup${NC}"
|
|
|
+echo "------------------------"
|
|
|
+
|
|
|
+# Check if pyproject.toml exists
|
|
|
+if [[ ! -f "pyproject.toml" ]]; then
|
|
|
+ print_warning "No pyproject.toml found. Creating basic one..."
|
|
|
+ cat > pyproject.toml << 'EOF'
|
|
|
+[project]
|
|
|
+name = "trading-bot"
|
|
|
+version = "1.0.0"
|
|
|
+requires-python = ">=3.8"
|
|
|
+dependencies = []
|
|
|
+
|
|
|
+[build-system]
|
|
|
+requires = ["hatchling"]
|
|
|
+build-backend = "hatchling.build"
|
|
|
+EOF
|
|
|
+ print_info "Created basic pyproject.toml - you may need to add your dependencies"
|
|
|
+fi
|
|
|
+
|
|
|
+# Create/sync UV environment
|
|
|
+print_info "Setting up UV environment..."
|
|
|
+if uv sync; then
|
|
|
+ print_success "UV environment ready"
|
|
|
+else
|
|
|
+ print_error "UV sync failed!"
|
|
|
+ print_info "Trying alternative setup..."
|
|
|
+ if uv venv && uv pip install -r requirements.txt 2>/dev/null; then
|
|
|
+ print_success "UV environment created with fallback method"
|
|
|
+ else
|
|
|
+ print_error "Could not create UV environment"
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+fi
|
|
|
+
|
|
|
+# Test imports
|
|
|
+print_info "Testing environment..."
|
|
|
+if uv run python -c "print('UV environment working!')" 2>/dev/null; then
|
|
|
+ print_success "UV environment functional"
|
|
|
+else
|
|
|
+ print_warning "UV environment may have issues"
|
|
|
+fi
|
|
|
+
|
|
|
+echo ""
|
|
|
+
|
|
|
+# =============================================================================
|
|
|
+# Step 5: Old Files Cleanup (Optional)
|
|
|
+# =============================================================================
|
|
|
+echo -e "${BLUE}🗑️ Old Files Cleanup${NC}"
|
|
|
+echo "-----------------------"
|
|
|
+
|
|
|
+# Check for old venv directory
|
|
|
+if [[ -d "venv" ]]; then
|
|
|
+ VENV_SIZE=$(get_size "venv")
|
|
|
+ print_warning "Old 'venv' directory found (${VENV_SIZE})"
|
|
|
+
|
|
|
+ if [[ "$1" != "--force" ]]; then
|
|
|
+ read -p "Delete old 'venv' directory? (y/N): " -n 1 -r
|
|
|
+ echo
|
|
|
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
|
+ if rm -rf "venv" 2>/dev/null; then
|
|
|
+ print_success "Removed old 'venv' directory"
|
|
|
+ else
|
|
|
+ print_warning "Could not remove old 'venv' directory (check permissions)"
|
|
|
+ fi
|
|
|
+ else
|
|
|
+ print_warning "Keeping old 'venv' directory"
|
|
|
+ fi
|
|
|
+ else
|
|
|
+ if rm -rf "venv" 2>/dev/null; then
|
|
|
+ print_success "Removed old 'venv' directory"
|
|
|
+ else
|
|
|
+ print_warning "Could not remove old 'venv' directory"
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+else
|
|
|
+ print_success "No old 'venv' directory found"
|
|
|
+fi
|
|
|
+
|
|
|
+echo ""
|
|
|
+
|
|
|
+# =============================================================================
|
|
|
+# Final Summary
|
|
|
+# =============================================================================
|
|
|
+echo -e "${GREEN}🎉 Migration Summary${NC}"
|
|
|
+echo "====================="
|
|
|
+echo ""
|
|
|
+print_success "UV migration completed!"
|
|
|
+echo ""
|
|
|
+echo "📋 What was done:"
|
|
|
+echo " ✅ Cleaned up cache files and directories"
|
|
|
+echo " ✅ Installed UV package manager"
|
|
|
+echo " ✅ Set up UV environment"
|
|
|
+echo ""
|
|
|
+echo "🚀 Next steps:"
|
|
|
+echo " • Test: uv run python --version"
|
|
|
+echo " • Run bot: uv run python trading_bot.py"
|
|
|
+echo " • Add packages: uv add package_name"
|
|
|
+echo ""
|
|
|
+echo "🔧 UV Quick Commands:"
|
|
|
+echo " uv sync # Sync dependencies"
|
|
|
+echo " uv add requests # Add package"
|
|
|
+echo " uv run python script.py # Run with UV"
|
|
|
+echo ""
|
|
|
+print_success "Migration complete! 🚀"
|