migrate_to_uv_robust.sh 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #!/bin/bash
  2. # =============================================================================
  3. # UV Migration Script (Robust Version)
  4. # =============================================================================
  5. # Migrates from pip/venv to uv package manager
  6. # Enhanced error handling for production environments
  7. # =============================================================================
  8. # Don't exit on errors - handle them gracefully
  9. set +e
  10. # Colors for output
  11. RED='\033[0;31m'
  12. GREEN='\033[0;32m'
  13. YELLOW='\033[1;33m'
  14. BLUE='\033[0;34m'
  15. NC='\033[0m' # No Color
  16. # Script version
  17. VERSION="1.1.0-robust"
  18. # Print header
  19. echo -e "${BLUE}=================================${NC}"
  20. echo -e "${BLUE} UV Migration Script v${VERSION}${NC}"
  21. echo -e "${BLUE}=================================${NC}"
  22. echo ""
  23. # Function to print colored output
  24. print_success() {
  25. echo -e "${GREEN}✅ $1${NC}"
  26. }
  27. print_warning() {
  28. echo -e "${YELLOW}⚠️ $1${NC}"
  29. }
  30. print_error() {
  31. echo -e "${RED}❌ $1${NC}"
  32. }
  33. print_info() {
  34. echo -e "${BLUE}ℹ️ $1${NC}"
  35. }
  36. # Function to check if command exists
  37. command_exists() {
  38. command -v "$1" >/dev/null 2>&1
  39. }
  40. # Function to get file size in human readable format
  41. get_size() {
  42. if [[ "$OSTYPE" == "darwin"* ]]; then
  43. # macOS
  44. du -h "$1" 2>/dev/null | cut -f1 || echo "0B"
  45. else
  46. # Linux
  47. du -sh "$1" 2>/dev/null | cut -f1 || echo "0B"
  48. fi
  49. }
  50. # Check if we're in the project root
  51. if [[ ! -f "pyproject.toml" && ! -f "requirements.txt" ]]; then
  52. print_error "Neither pyproject.toml nor requirements.txt found. Please run this script from the project root."
  53. exit 1
  54. fi
  55. print_info "Starting migration process..."
  56. echo ""
  57. # =============================================================================
  58. # Step 1: Pre-migration Analysis
  59. # =============================================================================
  60. echo -e "${BLUE}📊 Pre-migration Analysis${NC}"
  61. echo "----------------------------"
  62. # Count cache files before cleanup (with timeout to prevent hanging)
  63. print_info "Analyzing project files (this may take a moment)..."
  64. 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 ' ')
  65. 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 ' ')
  66. echo "📁 Cache directories found: $PYCACHE_DIRS"
  67. echo "📄 .pyc files found: $PYC_FILES"
  68. # Check if pytest cache exists
  69. if [[ -d ".pytest_cache" ]]; then
  70. PYTEST_SIZE=$(get_size ".pytest_cache")
  71. echo "🧪 Pytest cache size: $PYTEST_SIZE"
  72. else
  73. echo "🧪 No pytest cache found"
  74. fi
  75. # Check for old venv
  76. if [[ -d "venv" ]]; then
  77. print_warning "Old 'venv' directory still exists!"
  78. VENV_SIZE=$(get_size "venv")
  79. echo "📦 Old venv size: $VENV_SIZE"
  80. else
  81. print_success "No old 'venv' directory found"
  82. fi
  83. # Check for requirements.txt
  84. if [[ -f "requirements.txt" ]]; then
  85. print_warning "requirements.txt still exists (should be removed after migration)"
  86. else
  87. print_success "requirements.txt already removed"
  88. fi
  89. echo ""
  90. # =============================================================================
  91. # Step 2: UV Installation Check
  92. # =============================================================================
  93. echo -e "${BLUE}🔧 UV Installation Check${NC}"
  94. echo "----------------------------"
  95. # Add UV to PATH if it exists
  96. export PATH="$HOME/.local/bin:$PATH"
  97. if command_exists uv; then
  98. UV_VERSION=$(uv --version 2>/dev/null | head -1)
  99. print_success "UV installed: $UV_VERSION"
  100. else
  101. print_error "UV not found! Installing UV..."
  102. if command_exists curl; then
  103. curl -LsSf https://astral.sh/uv/install.sh | sh
  104. # Add to PATH for this session
  105. export PATH="$HOME/.local/bin:$PATH"
  106. if command_exists uv; then
  107. UV_VERSION=$(uv --version 2>/dev/null | head -1)
  108. print_success "UV installed successfully: $UV_VERSION"
  109. else
  110. print_error "UV installation failed!"
  111. exit 1
  112. fi
  113. else
  114. print_error "curl not found! Please install UV manually."
  115. exit 1
  116. fi
  117. fi
  118. echo ""
  119. # =============================================================================
  120. # Step 3: Cache Cleanup (Robust Version)
  121. # =============================================================================
  122. echo -e "${BLUE}🧹 Cache Cleanup${NC}"
  123. echo "-------------------"
  124. # Ask for confirmation unless --force flag is provided
  125. if [[ "$1" != "--force" ]]; then
  126. echo "This will delete:"
  127. echo " - $PYCACHE_DIRS __pycache__ directories"
  128. echo " - $PYC_FILES .pyc files"
  129. echo " - .pytest_cache directory (if exists)"
  130. echo ""
  131. read -p "Continue with cleanup? (y/N): " -n 1 -r
  132. echo
  133. if [[ ! $REPLY =~ ^[Yy]$ ]]; then
  134. print_warning "Cleanup cancelled by user"
  135. exit 0
  136. fi
  137. fi
  138. print_info "Starting cleanup (using robust method for large file counts)..."
  139. # Method 1: Use xargs for better handling of large file lists
  140. DELETED_DIRS=0
  141. DELETED_FILES=0
  142. # Clean __pycache__ directories in batches
  143. print_info "Cleaning __pycache__ directories..."
  144. if find . -path "./.venv" -prune -o -path "./venv" -prune -o -name "__pycache__" -type d -print0 2>/dev/null | xargs -0 -r rm -rf; then
  145. DELETED_DIRS=$(echo "$PYCACHE_DIRS")
  146. print_success "Cleaned $DELETED_DIRS cache directories"
  147. else
  148. print_warning "Some cache directories could not be deleted (may be permission issues)"
  149. fi
  150. # Clean .pyc files in batches
  151. print_info "Cleaning .pyc files..."
  152. if find . -path "./.venv" -prune -o -path "./venv" -prune -o -name "*.pyc" -type f -print0 2>/dev/null | xargs -0 -r rm -f; then
  153. DELETED_FILES=$(echo "$PYC_FILES")
  154. print_success "Cleaned $DELETED_FILES .pyc files"
  155. else
  156. print_warning "Some .pyc files could not be deleted"
  157. fi
  158. # Clean .pyo files
  159. print_info "Cleaning .pyo files..."
  160. find . -path "./.venv" -prune -o -path "./venv" -prune -o -name "*.pyo" -type f -print0 2>/dev/null | xargs -0 -r rm -f
  161. # Remove pytest cache
  162. if [[ -d ".pytest_cache" ]]; then
  163. if rm -rf ".pytest_cache" 2>/dev/null; then
  164. print_success "Removed .pytest_cache directory"
  165. else
  166. print_warning "Could not remove .pytest_cache directory"
  167. fi
  168. fi
  169. print_success "Cleanup phase completed!"
  170. echo ""
  171. # =============================================================================
  172. # Step 4: UV Environment Setup
  173. # =============================================================================
  174. echo -e "${BLUE}🔍 UV Environment Setup${NC}"
  175. echo "------------------------"
  176. # Check if pyproject.toml exists
  177. if [[ ! -f "pyproject.toml" ]]; then
  178. print_warning "No pyproject.toml found. Creating basic one..."
  179. cat > pyproject.toml << 'EOF'
  180. [project]
  181. name = "trading-bot"
  182. version = "1.0.0"
  183. requires-python = ">=3.8"
  184. dependencies = []
  185. [build-system]
  186. requires = ["hatchling"]
  187. build-backend = "hatchling.build"
  188. EOF
  189. print_info "Created basic pyproject.toml - you may need to add your dependencies"
  190. fi
  191. # Create/sync UV environment
  192. print_info "Setting up UV environment..."
  193. if uv sync; then
  194. print_success "UV environment ready"
  195. else
  196. print_error "UV sync failed!"
  197. print_info "Trying alternative setup..."
  198. if uv venv && uv pip install -r requirements.txt 2>/dev/null; then
  199. print_success "UV environment created with fallback method"
  200. else
  201. print_error "Could not create UV environment"
  202. exit 1
  203. fi
  204. fi
  205. # Test imports
  206. print_info "Testing environment..."
  207. if uv run python -c "print('UV environment working!')" 2>/dev/null; then
  208. print_success "UV environment functional"
  209. else
  210. print_warning "UV environment may have issues"
  211. fi
  212. echo ""
  213. # =============================================================================
  214. # Step 5: Old Files Cleanup (Optional)
  215. # =============================================================================
  216. echo -e "${BLUE}🗑️ Old Files Cleanup${NC}"
  217. echo "-----------------------"
  218. # Check for old venv directory
  219. if [[ -d "venv" ]]; then
  220. VENV_SIZE=$(get_size "venv")
  221. print_warning "Old 'venv' directory found (${VENV_SIZE})"
  222. if [[ "$1" != "--force" ]]; then
  223. read -p "Delete old 'venv' directory? (y/N): " -n 1 -r
  224. echo
  225. if [[ $REPLY =~ ^[Yy]$ ]]; then
  226. if rm -rf "venv" 2>/dev/null; then
  227. print_success "Removed old 'venv' directory"
  228. else
  229. print_warning "Could not remove old 'venv' directory (check permissions)"
  230. fi
  231. else
  232. print_warning "Keeping old 'venv' directory"
  233. fi
  234. else
  235. if rm -rf "venv" 2>/dev/null; then
  236. print_success "Removed old 'venv' directory"
  237. else
  238. print_warning "Could not remove old 'venv' directory"
  239. fi
  240. fi
  241. else
  242. print_success "No old 'venv' directory found"
  243. fi
  244. echo ""
  245. # =============================================================================
  246. # Final Summary
  247. # =============================================================================
  248. echo -e "${GREEN}🎉 Migration Summary${NC}"
  249. echo "====================="
  250. echo ""
  251. print_success "UV migration completed!"
  252. echo ""
  253. echo "📋 What was done:"
  254. echo " ✅ Cleaned up cache files and directories"
  255. echo " ✅ Installed UV package manager"
  256. echo " ✅ Set up UV environment"
  257. echo ""
  258. echo "🚀 Next steps:"
  259. echo " • Test: uv run python --version"
  260. echo " • Run bot: uv run python trading_bot.py"
  261. echo " • Add packages: uv add package_name"
  262. echo ""
  263. echo "🔧 UV Quick Commands:"
  264. echo " uv sync # Sync dependencies"
  265. echo " uv add requests # Add package"
  266. echo " uv run python script.py # Run with UV"
  267. echo ""
  268. print_success "Migration complete! 🚀"