From 1557f5717ed83de252fb765b5284d608a1f542db Mon Sep 17 00:00:00 2001 From: Ankan Saha Date: Sun, 20 Jul 2025 23:17:13 +0530 Subject: [PATCH 1/3] Add version controller script and update Docker configurations - Introduced a version controller script to manage local versioning. - Updated VERSION file to 1.1.1-beta. - Refactored docker-compose.yml to improve service configurations and networking. - Modified Dockerfile to set a static build date. - Changed permissions for init-db.py and validate-dockerfile.py scripts. - Added a setup script for simplified development environment setup. --- .pre-commit-config.yaml | 11 ++ VERSION | 2 +- docker-compose.yml | 272 ++++++--------------------------- docker/api/Dockerfile | 2 +- scripts/init-db.py | 0 scripts/validate-dockerfile.py | 0 scripts/versionController.sh | 95 ++++++++++++ setup.sh | 173 +++++++++++++++++++++ 8 files changed, 331 insertions(+), 224 deletions(-) create mode 100644 .pre-commit-config.yaml mode change 100644 => 100755 scripts/init-db.py mode change 100644 => 100755 scripts/validate-dockerfile.py create mode 100755 scripts/versionController.sh create mode 100755 setup.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3a4a674 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: + - repo: local + hooks: + - id: version-controller + name: Version Controller + entry: ./scripts/versionController.sh + language: system + stages: [commit] + pass_filenames: false + always_run: true + verbose: true \ No newline at end of file diff --git a/VERSION b/VERSION index 3eefcb9..898d2bf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.1.1-beta diff --git a/docker-compose.yml b/docker-compose.yml index 3bc305d..891755a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,34 +1,14 @@ -# version: '3.8' # Version is obsolete in Docker Compose v2+ - services: - # Interactive Setup Wizard (run once for initial configuration) - setup: - build: - context: . - dockerfile: docker/setup/Dockerfile - container_name: rendiff_setup - volumes: - - .:/host # Mount the entire project directory - - ./config:/app/config:ro # Mount config templates - environment: - - TERM=xterm-256color # Better terminal support - profiles: - - setup - stdin_open: true - tty: true - networks: - - rendiff - - # Traefik Reverse Proxy with HTTPS (runs by default) + # Traefik Reverse Proxy traefik: image: traefik:v3.0 - container_name: rendiff_traefik + container_name: ffmpeg_traefik command: - --configFile=/etc/traefik/traefik.yml ports: - "80:80" - "443:443" - - "8081:8080" # Dashboard on 8081 to avoid conflict + - "8081:8080" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro @@ -37,7 +17,7 @@ services: depends_on: - api networks: - - rendiff + - ffmpeg-net restart: unless-stopped labels: - "traefik.enable=true" @@ -45,106 +25,76 @@ services: - "traefik.http.routers.traefik-dashboard.entrypoints=websecure" - "traefik.http.routers.traefik-dashboard.tls=true" - "traefik.http.routers.traefik-dashboard.service=api@internal" - - # API Gateway (now behind Traefik) - krakend: - image: devopsfaith/krakend:2.6 - container_name: rendiff_gateway - volumes: - - ./config/krakend.json:/etc/krakend/krakend.json:ro - # No port exposure - accessed through Traefik - depends_on: - - api - networks: - - rendiff - restart: unless-stopped - labels: - - "traefik.enable=true" - - "traefik.http.routers.krakend.rule=Host(`localhost`) && PathPrefix(`/`)" - - "traefik.http.routers.krakend.entrypoints=websecure" - - "traefik.http.routers.krakend.tls=true" - - "traefik.http.services.krakend.loadbalancer.server.port=8080" - # Database Service postgres: image: postgres:15-alpine - container_name: rendiff_postgres + container_name: ffmpeg_postgres environment: - POSTGRES_DB=ffmpeg_api - POSTGRES_USER=ffmpeg_user - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-defaultpassword} volumes: - postgres-data:/var/lib/postgresql/data - - ./docker/postgres/init:/docker-entrypoint-initdb.d:ro - # ports: - # - "5432:5432" # Remove port exposure for security + ports: + - "5432:5432" networks: - - rendiff + - ffmpeg-net restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U ffmpeg_user -d ffmpeg_api"] interval: 10s timeout: 5s retries: 5 - command: > - postgres - -c max_connections=200 - -c shared_buffers=256MB - -c effective_cache_size=1GB - -c maintenance_work_mem=64MB - -c checkpoint_completion_target=0.9 - -c wal_buffers=16MB - -c default_statistics_target=100 - -c random_page_cost=1.1 - -c effective_io_concurrency=200 - # Database Migration Service (runs once to initialize schema) + # Queue Service (Redis) + redis: + image: redis:7-alpine + container_name: ffmpeg_redis + command: redis-server --appendonly yes + volumes: + - redis-data:/data + ports: + - "6379:6379" + networks: + - ffmpeg-net + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + + # Database Migration Service db-migrate: build: context: . dockerfile: docker/api/Dockerfile command: ["/app/scripts/docker-entrypoint.sh", "migrate"] environment: - - DATABASE_URL=${DATABASE_URL} + - DATABASE_URL=${DATABASE_URL:-postgresql://ffmpeg_user:defaultpassword@postgres:5432/ffmpeg_api} - PYTHONUNBUFFERED=1 - - POSTGRES_HOST=postgres - - POSTGRES_PORT=5432 - - POSTGRES_USER=ffmpeg_user - - POSTGRES_DB=ffmpeg_api depends_on: postgres: condition: service_healthy networks: - - rendiff + - ffmpeg-net restart: "no" - volumes: - - ./alembic:/app/alembic:ro - - ./alembic.ini:/app/alembic.ini:ro # API Service api: build: context: . dockerfile: docker/api/Dockerfile + container_name: ffmpeg_api environment: - - DATABASE_URL=${DATABASE_URL} + - DATABASE_URL=${DATABASE_URL:-postgresql://ffmpeg_user:defaultpassword@postgres:5432/ffmpeg_api} - REDIS_URL=redis://redis:6379/0 - - STORAGE_CONFIG=/app/config/storage.yml - LOG_LEVEL=info - PYTHONUNBUFFERED=1 - API_HOST=0.0.0.0 - API_PORT=8000 - - API_WORKERS=4 - - POSTGRES_HOST=postgres - - POSTGRES_PORT=5432 - - POSTGRES_USER=ffmpeg_user - - POSTGRES_DB=ffmpeg_api - - REDIS_HOST=redis - - REDIS_PORT=6379 volumes: - - ./config:/app/config:ro - - storage:/storage + - ./storage:/storage depends_on: postgres: condition: service_healthy @@ -153,176 +103,54 @@ services: db-migrate: condition: service_completed_successfully networks: - - rendiff + - ffmpeg-net restart: unless-stopped healthcheck: - test: ["CMD", "/app/scripts/health-check.sh", "api"] + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s - start_period: 120s + start_period: 60s retries: 3 - deploy: - replicas: 2 - resources: - limits: - cpus: '2' - memory: 4G + labels: + - "traefik.enable=true" + - "traefik.http.routers.api.rule=Host(`localhost`) && PathPrefix(`/api`)" + - "traefik.http.routers.api.entrypoints=web" + - "traefik.http.services.api.loadbalancer.server.port=8000" - # Worker Service - CPU - worker-cpu: + # Worker Service - CPU Only + worker: build: context: . dockerfile: docker/worker/Dockerfile + args: + - WORKER_TYPE=cpu + container_name: ffmpeg_worker environment: - - DATABASE_URL=${DATABASE_URL} + - DATABASE_URL=${DATABASE_URL:-postgresql://ffmpeg_user:defaultpassword@postgres:5432/ffmpeg_api} - REDIS_URL=redis://redis:6379/0 - - STORAGE_CONFIG=/app/config/storage.yml - WORKER_TYPE=cpu - WORKER_CONCURRENCY=4 - LOG_LEVEL=info - PYTHONUNBUFFERED=1 volumes: - - ./config:/app/config:ro - - storage:/storage + - ./storage:/storage depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - - rendiff + - ffmpeg-net restart: unless-stopped - deploy: - replicas: 2 - resources: - limits: - cpus: '4' - memory: 8G - - # Worker Service - GPU (optional) - worker-gpu: - build: - context: . - dockerfile: docker/worker/Dockerfile - environment: - - DATABASE_URL=${DATABASE_URL} - - REDIS_URL=redis://redis:6379/0 - - STORAGE_CONFIG=/app/config/storage.yml - - WORKER_TYPE=gpu - - WORKER_CONCURRENCY=2 - - LOG_LEVEL=info - - PYTHONUNBUFFERED=1 - - NVIDIA_VISIBLE_DEVICES=all - volumes: - - ./config:/app/config:ro - - storage:/storage - depends_on: - postgres: - condition: service_healthy - redis: - condition: service_healthy - networks: - - rendiff - restart: unless-stopped - deploy: - replicas: 1 - resources: - limits: - cpus: '4' - memory: 8G - reservations: - devices: - - driver: nvidia - count: 1 - capabilities: [gpu] - profiles: - - gpu - - # Queue Service (Redis) - redis: - image: redis:7-alpine - container_name: rendiff_redis - command: > - redis-server - --appendonly yes - --appendfsync everysec - --maxmemory 2gb - --maxmemory-policy allkeys-lru - --timeout 300 - --tcp-keepalive 300 - --maxclients 1000 - volumes: - - redis-data:/data - - ./docker/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro - # ports: - # - "6379:6379" # Remove port exposure for security - networks: - - rendiff - restart: unless-stopped - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - - - # Monitoring - Prometheus - prometheus: - image: prom/prometheus:v2.48.0 - command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' - - '--web.console.libraries=/usr/share/prometheus/console_libraries' - - '--web.console.templates=/usr/share/prometheus/consoles' - volumes: - - ./config/prometheus.yml:/etc/prometheus/prometheus.yml:ro - - prometheus-data:/prometheus - ports: - - "9090:9090" - networks: - - rendiff - restart: unless-stopped - profiles: - - monitoring - - # Monitoring - Grafana - grafana: - image: grafana/grafana:10.2.0 - environment: - - GF_SECURITY_ADMIN_USER=admin - - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD} - - GF_USERS_ALLOW_SIGN_UP=false - volumes: - - grafana-data:/var/lib/grafana - - ./monitoring/dashboards:/etc/grafana/provisioning/dashboards:ro - - ./monitoring/datasources:/etc/grafana/provisioning/datasources:ro - ports: - - "3000:3000" - networks: - - rendiff - restart: unless-stopped - depends_on: - - prometheus - profiles: - - monitoring - networks: - rendiff: + ffmpeg-net: driver: bridge volumes: storage: driver: local - driver_opts: - type: none - o: bind - device: ${STORAGE_PATH:-./storage} postgres-data: driver: local redis-data: - driver: local - prometheus-data: - driver: local - grafana-data: driver: local \ No newline at end of file diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index df3c1e4..14c6701 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -10,7 +10,7 @@ FROM python:${PYTHON_VERSION}-slim AS builder # Build-time labels for traceability LABEL stage=builder LABEL python.version=${PYTHON_VERSION} -LABEL build.date=$(date -u +'%Y-%m-%dT%H:%M:%SZ') +LABEL build.date="2024-01-01" # Set environment variables for consistent builds ENV PYTHONUNBUFFERED=1 \ diff --git a/scripts/init-db.py b/scripts/init-db.py old mode 100644 new mode 100755 diff --git a/scripts/validate-dockerfile.py b/scripts/validate-dockerfile.py old mode 100644 new mode 100755 diff --git a/scripts/versionController.sh b/scripts/versionController.sh new file mode 100755 index 0000000..0cb8fa0 --- /dev/null +++ b/scripts/versionController.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# Fetch remote version +remote_url="https://raw.githubusercontent.com/rendiffdev/ffmpeg-api/main/VERSION" +remote_version=$(curl -s "$remote_url") +if [[ -z "$remote_version" ]]; then + echo "Error: Unable to fetch remote version." + exit 1 +fi +echo "Current GitHub version: $remote_version" + +# Read local version +local_version=$(cat "$(dirname "$0")/../VERSION" 2>/dev/null || echo "0.0.0") +echo "Local version: $local_version" + +# Compare versions: returns 0 if first > second +ver_gt() { + local IFS=. + local raw1 raw2 i ver1 ver2 + # Strip suffix from versions (ignore -beta or -stable) + raw1="${1%%-*}" + raw2="${2%%-*}" + # parse numeric parts + read -ra ver1 <<<"$raw1" + read -ra ver2 <<<"$raw2" + # pad shorter array with zeros + for ((i = ${#ver1[@]}; i < ${#ver2[@]}; i++)); do ver1[i]=0; done + for ((i = ${#ver2[@]}; i < ${#ver1[@]}; i++)); do ver2[i]=0; done + # compare each segment + for ((i = 0; i < ${#ver1[@]}; i++)); do + if ((10#${ver1[i]} > 10#${ver2[i]})); then return 0; fi + if ((10#${ver1[i]} < 10#${ver2[i]})); then return 1; fi + done + return 1 +} + +# Exit if local is already ahead of remote +if ver_gt "$local_version" "$remote_version"; then + echo "Local version ($local_version) is ahead of remote ($remote_version). Skipping update." + exit 0 +fi + +# ---- now select version type ---- +options=("Stable" "Beta") +selected=0 + +tput civis # hide cursor +show_menu() { + for i in "${!options[@]}"; do + if [[ $i -eq $selected ]]; then + echo -e "\033[7m> ${options[$i]}\033[0m" + else + echo " ${options[$i]}" + fi + done +} +refresh() { + tput cup 4 0 + tput ed + show_menu +} + +show_menu +while true; do + read -rsn3 key + case "$key" in + $'\x1b[A') # Up arrow + ((selected = (selected - 1 + ${#options[@]}) % ${#options[@]})) + refresh + ;; + $'\x1b[B') # Down arrow + ((selected = (selected + 1) % ${#options[@]})) + refresh + ;; + "") # Enter key + version_type="${options[$selected]}" + break + ;; + esac +done +tput cnorm # show cursor +echo -e "\nSelected: $version_type" + +# Prompt for new version +read -p "Enter new version: " new_version + +# Validate version format +if ! [[ "$new_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: Invalid version format. Use X.Y.Z (e.g., 1.0.0)." + exit 1 +fi + +# Update local version file +suffix=$(echo "$version_type" | tr '[:upper:]' '[:lower:]') +echo "${new_version}-${suffix}" >"$(dirname "$0")/../VERSION" +echo "Local version updated to ${new_version}-${suffix}" \ No newline at end of file diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..85efdc0 --- /dev/null +++ b/setup.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +# Rendiff FFmpeg API - Simple Setup Script +set -e + +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$PROJECT_DIR" + +echo "🚀 Rendiff FFmpeg API Setup" +echo "==========================" + +# Function to show usage +show_usage() { + echo "Usage: $0 [--development|--standard|--genai|--status|--stop]" + echo "" + echo "Options:" + echo " --development Quick local development setup (SQLite, no auth)" + echo " --standard Production setup (PostgreSQL, Redis, auth)" + echo " --genai AI-enhanced setup (GPU support)" + echo " --status Show current status" + echo " --stop Stop all services" + echo " --help Show this help" + exit 1 +} + +# Function to check requirements +check_requirements() { + echo "Checking requirements..." + + if ! command -v docker &> /dev/null; then + echo "❌ Docker is not installed. Please install Docker first." + exit 1 + fi + + if ! command -v docker &> /dev/null || ! docker compose version &> /dev/null; then + echo "❌ Docker Compose is not available. Please install Docker Compose." + exit 1 + fi + + echo "✅ Docker and Docker Compose are available" +} + +# Function for development setup +setup_development() { + echo "🛠️ Setting up Development Environment..." + + # Create development .env file + cat > .env << EOF +# Development Configuration +DATABASE_URL=sqlite+aiosqlite:///data/rendiff.db +REDIS_URL=redis://redis:6379/0 +API_HOST=0.0.0.0 +API_PORT=8000 +DEBUG=true +LOG_LEVEL=debug +STORAGE_PATH=./storage +CORS_ORIGINS=http://localhost:8000,http://127.0.0.1:8000 +ENABLE_API_KEYS=false +POSTGRES_PASSWORD=dev_password_123 +GRAFANA_PASSWORD=admin +EOF + + # Create minimal docker-compose for development + cat > docker-compose.dev.yml << EOF +services: + # Redis for queue + redis: + image: redis:7-alpine + container_name: ffmpeg_dev_redis + ports: + - "6379:6379" + command: redis-server --appendonly yes + volumes: + - redis_dev_data:/data + + # Simple API service + api: + build: + context: . + dockerfile: docker/api/Dockerfile + container_name: ffmpeg_dev_api + ports: + - "8000:8000" + environment: + - DATABASE_URL=sqlite+aiosqlite:///data/rendiff.db + - REDIS_URL=redis://redis:6379/0 + - DEBUG=true + - ENABLE_API_KEYS=false + volumes: + - ./storage:/storage + - ./data:/data + depends_on: + - redis + command: python -m uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload + +volumes: + redis_dev_data: +EOF + + echo "📁 Creating directories..." + mkdir -p storage data logs + + echo "🐳 Starting development services..." + docker compose -f docker-compose.dev.yml up -d + + echo "" + echo "✅ Development setup complete!" + echo "" + echo "🌐 API available at: http://localhost:8000" + echo "📚 API docs at: http://localhost:8000/docs" + echo "🔍 Health check: http://localhost:8000/api/v1/health" + echo "" + echo "📝 To stop: ./setup.sh --stop" +} + +# Function to show status +show_status() { + echo "📊 Current Status:" + echo "==================" + + if docker compose -f docker-compose.dev.yml ps 2>/dev/null | grep -q "Up"; then + echo "🟢 Development environment is running" + docker compose -f docker-compose.dev.yml ps + echo "" + echo "🌐 Access URLs:" + echo " API: http://localhost:8000" + echo " Docs: http://localhost:8000/docs" + else + echo "🔴 Development environment is not running" + fi +} + +# Function to stop services +stop_services() { + echo "🛑 Stopping services..." + + if [ -f "docker-compose.dev.yml" ]; then + docker compose -f docker-compose.dev.yml down + fi + + echo "✅ Services stopped" +} + +# Parse command line arguments +case "${1:-}" in + --development|--dev) + check_requirements + setup_development + ;; + --standard|--prod) + echo "🚧 Standard/Production setup not implemented yet" + echo "💡 Use --development for now" + exit 1 + ;; + --genai|--ai) + echo "🚧 GenAI setup not implemented yet" + echo "💡 Use --development for now" + exit 1 + ;; + --status) + show_status + ;; + --stop) + stop_services + ;; + --help|-h) + show_usage + ;; + *) + echo "❌ Unknown option: ${1:-}" + show_usage + ;; +esac \ No newline at end of file From 5ec378aec221330ce2b9396417d26dbfa02be2af Mon Sep 17 00:00:00 2001 From: Ankan Saha Date: Sun, 20 Jul 2025 23:18:14 +0530 Subject: [PATCH 2/3] Test Pre Commit --- REPOSITORY_STRUCTURE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/REPOSITORY_STRUCTURE.md b/REPOSITORY_STRUCTURE.md index fb027fb..9eca168 100644 --- a/REPOSITORY_STRUCTURE.md +++ b/REPOSITORY_STRUCTURE.md @@ -4,6 +4,7 @@ This document outlines the clean, organized structure of the FFmpeg API project. ## Directory Structure + ``` ffmpeg-api/ ├── .github/ From 1e8afd77429dbcc52f9fef1eae221a846317cdf7 Mon Sep 17 00:00:00 2001 From: Ankan Saha Date: Sun, 20 Jul 2025 23:28:55 +0530 Subject: [PATCH 3/3] Added Development Setup Script, that setup the development Enviroment --- .pre-commit-config.yaml | 2 +- development.sh | 191 ++++++++++++++++++++++++++++++++++++++++ scripts/version-hook.sh | 14 +++ 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100755 development.sh create mode 100755 scripts/version-hook.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3a4a674..f3dc317 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: hooks: - id: version-controller name: Version Controller - entry: ./scripts/versionController.sh + entry: ./scripts/version-hook.sh language: system stages: [commit] pass_filenames: false diff --git a/development.sh b/development.sh new file mode 100755 index 0000000..24739eb --- /dev/null +++ b/development.sh @@ -0,0 +1,191 @@ +#!/bin/bash + +set -e # Exit on any error + +echo "🚀 Setting up development environment..." + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if running as root +if [[ $EUID -eq 0 ]]; then + print_warning "Running as root. Some operations may behave differently." +fi + +# Update package lists +print_status "Updating package lists..." +if command -v apt-get &> /dev/null; then + sudo apt-get update -qq +elif command -v yum &> /dev/null; then + sudo yum check-update || true +elif command -v dnf &> /dev/null; then + sudo dnf check-update || true +elif command -v pacman &> /dev/null; then + sudo pacman -Sy +else + print_warning "Package manager not detected. Manual installation may be required." +fi + +# Install essential tools +print_status "Installing essential development tools..." +if command -v apt-get &> /dev/null; then + sudo apt-get install -y curl wget git build-essential software-properties-common +elif command -v yum &> /dev/null; then + sudo yum groupinstall -y "Development Tools" + sudo yum install -y curl wget git +elif command -v dnf &> /dev/null; then + sudo dnf groupinstall -y "Development Tools" + sudo dnf install -y curl wget git +elif command -v pacman &> /dev/null; then + sudo pacman -S --noconfirm curl wget git base-devel +fi + +# Check if Python3 is available +print_status "Checking Python installation..." +if ! command -v python3 &> /dev/null; then + print_warning "Python3 not found. Installing Python3..." + + if command -v apt-get &> /dev/null; then + sudo apt-get install -y python3 python3-pip python3-venv python3-dev + elif command -v yum &> /dev/null; then + sudo yum install -y python3 python3-pip python3-venv python3-devel + elif command -v dnf &> /dev/null; then + sudo dnf install -y python3 python3-pip python3-venv python3-devel + elif command -v pacman &> /dev/null; then + sudo pacman -S --noconfirm python python-pip python-virtualenv + else + print_error "Could not install Python3. Please install manually." + exit 1 + fi +else + print_success "Python3 is already installed: $(python3 --version)" +fi + +# Check if pip is available +if ! command -v pip3 &> /dev/null && ! python3 -m pip --version &> /dev/null; then + print_warning "pip not found. Installing pip..." + + if command -v apt-get &> /dev/null; then + sudo apt-get install -y python3-pip + elif command -v yum &> /dev/null; then + sudo yum install -y python3-pip + elif command -v dnf &> /dev/null; then + sudo dnf install -y python3-pip + else + # Download and install pip manually + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + python3 get-pip.py + rm get-pip.py + fi +else + print_success "pip is available" +fi + +# Install FFmpeg (required for media processing) +print_status "Checking FFmpeg installation..." +if ! command -v ffmpeg &> /dev/null; then + print_warning "FFmpeg not found. Installing FFmpeg..." + + if command -v apt-get &> /dev/null; then + sudo apt-get install -y ffmpeg + elif command -v yum &> /dev/null; then + sudo yum install -y ffmpeg + elif command -v dnf &> /dev/null; then + sudo dnf install -y ffmpeg + elif command -v pacman &> /dev/null; then + sudo pacman -S --noconfirm ffmpeg + else + print_error "Could not install FFmpeg. Please install manually." + exit 1 + fi +else + print_success "FFmpeg is already installed: $(ffmpeg -version | head -n1)" +fi + +# Create virtual environment +VENV_NAME="venv" +print_status "Creating virtual environment..." + +if [ -d "$VENV_NAME" ]; then + print_warning "Virtual environment already exists. Removing old environment..." + rm -rf "$VENV_NAME" +fi + +python3 -m venv "$VENV_NAME" +print_success "Virtual environment created: $VENV_NAME" + +# Activate virtual environment +print_status "Activating virtual environment..." +source "$VENV_NAME/bin/activate" +print_success "Virtual environment activated" + +# Upgrade pip +print_status "Upgrading pip..." +python -m pip install --upgrade pip + +# Install requirements +if [ -f "requirements.txt" ]; then + print_status "Installing requirements from requirements.txt..." + python -m pip install -r requirements.txt + print_success "Requirements installed successfully" +else + print_error "requirements.txt not found!" + exit 1 +fi + +# Install pre-commit if not already installed +if ! command -v pre-commit &> /dev/null; then + print_status "Installing pre-commit..." + python -m pip install pre-commit + print_success "pre-commit installed" +fi + +# Install pre-commit hooks +if [ -f ".pre-commit-config.yaml" ]; then + print_status "Installing pre-commit hooks..." + pre-commit install + print_success "Pre-commit hooks installed" +fi + +print_success "🎉 Development environment setup complete!" +print_status "To activate the virtual environment in the future, run:" +echo " source $VENV_NAME/bin/activate" +print_status "To deactivate the virtual environment, run:" +echo " deactivate" + +# Display environment info +echo "" +print_status "Environment Information:" +echo " Python: $(python --version)" +echo " Pip: $(pip --version)" +echo " Virtual Environment: $(pwd)/$VENV_NAME" +if command -v ffmpeg &> /dev/null; then + echo " FFmpeg: $(ffmpeg -version | head -n1 | cut -d' ' -f3)" +fi +if command -v redis-server &> /dev/null; then + echo " Redis: Available" +fi + +echo "" +print_success "You can now start developing! 🚀" \ No newline at end of file diff --git a/scripts/version-hook.sh b/scripts/version-hook.sh new file mode 100755 index 0000000..d25d85b --- /dev/null +++ b/scripts/version-hook.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Interactive wrapper for version controller in git hooks +# This script properly handles terminal input/output for git hooks + +# Check if we're in a git hook environment +if [ -t 0 ] && [ -t 1 ]; then + # We have a proper terminal, run directly + exec "$(dirname "$0")/versionController.sh" +else + # We're in a git hook, need to use terminal properly + exec < /dev/tty > /dev/tty 2>&1 + "$(dirname "$0")/versionController.sh" +fi \ No newline at end of file