# AI Lecture 프로젝트 Makefile # 자주 사용하는 명령어들을 단순화하여 제공합니다. .PHONY: help format test clean setup install lint coverage docs progress # 기본 타겟: 도움말 표시 help: @echo "AI Lecture 프로젝트 Makefile" @echo "================================" @echo "" @echo "사용 가능한 명령어:" @echo " make help - 이 도움말을 표시합니다" @echo " make format - 코드 포맷팅을 수행합니다 (black, isort)" @echo " make test - 모든 테스트를 실행합니다" @echo " make lint - 코드 품질 검사를 수행합니다 (flake8, black --check)" @echo " make coverage - 테스트 커버리지를 측정합니다" @echo " make clean - 캐시 파일들을 정리합니다" @echo " make setup - 개발 환경을 설정합니다" @echo " make install - 의존성을 설치합니다" @echo " make docs - 문서를 빌드합니다" @echo " make progress - 학습 진도를 확인합니다" @echo "" @echo "진도 관리 명령어:" @echo " make progress-show [PART=part_2] - 특정 파트 진도 확인" @echo " make progress-complete PART=part_2 ITEM=0 - 항목 완료 표시" @echo " make progress-export [FILE=report.md] - 진도 리포트 생성" @echo "" @echo "예시:" @echo " make format test - 포맷팅 후 테스트 실행" @echo " make test coverage - 테스트와 커버리지 실행" @echo " make progress-show PART=part_2 - Part 2 진도 확인" # 코드 포맷팅 format: @echo "🎨 코드 포맷팅을 시작합니다..." @echo "==========================================" @if command -v isort > /dev/null; then \ echo "✓ import 문을 정렬합니다..."; \ find source_code -name "*.py" -exec isort {} \; 2>/dev/null || true; \ find . -maxdepth 1 -name "*.py" -exec isort {} \; 2>/dev/null || true; \ echo "✓ import 문 정렬 완료"; \ else \ echo "⚠ isort가 설치되어 있지 않습니다. pip install isort로 설치하세요."; \ fi @if command -v black > /dev/null; then \ echo "✓ 코드를 포맷팅합니다..."; \ black source_code/ --line-length=88 2>/dev/null || true; \ black *.py --line-length=88 2>/dev/null || true; \ echo "✓ 코드 포맷팅 완료"; \ else \ echo "⚠ black이 설치되어 있지 않습니다. pip install black으로 설치하세요."; \ fi @echo "🎉 코드 포맷팅이 완료되었습니다!" # 테스트 실행 test: @echo "🧪 테스트를 시작합니다..." @echo "==========================================" @if [ ! -d "source_code" ]; then \ echo "❌ source_code 디렉토리가 없습니다. 프로젝트 루트에서 실행해주세요."; \ exit 1; \ fi @if ! python3 -c "import pytest" 2>/dev/null; then \ echo "⚠ pytest가 설치되어 있지 않습니다. pip install pytest pytest-cov로 설치하세요."; \ exit 1; \ fi @echo "✓ 테스트 환경 확인 완료" @echo "" @for test_dir in source_code/*/tests source_code/*/*/tests; do \ if [ -d "$$test_dir" ] && [ -n "$$(find $$test_dir -name 'test_*.py' -type f)" ]; then \ echo "📦 $$(basename $$(dirname $$test_dir)) 테스트를 실행합니다..."; \ python3 -m pytest "$$test_dir" -v --tb=short || echo "⚠ 일부 테스트가 실패했습니다."; \ echo ""; \ fi; \ done @echo "🎉 테스트 실행이 완료되었습니다!" # 코드 품질 검사 lint: @echo "🔍 코드 품질을 검사합니다..." @echo "==========================================" @if command -v flake8 > /dev/null; then \ echo "✓ flake8으로 코드 스타일을 검사합니다..."; \ flake8 source_code/ --max-line-length=88 --extend-ignore=E203,W503 || echo "⚠ 코드 스타일 개선이 필요합니다"; \ else \ echo "⚠ flake8이 설치되어 있지 않습니다. pip install flake8으로 설치하세요."; \ fi @if command -v black > /dev/null; then \ echo "✓ black으로 코드 포맷팅을 검사합니다..."; \ black --check source_code/ 2>/dev/null || echo "⚠ 코드 포맷팅 개선이 필요합니다"; \ else \ echo "⚠ black이 설치되어 있지 않습니다. pip install black으로 설치하세요."; \ fi @echo "🎉 코드 품질 검사가 완료되었습니다!" # 테스트 커버리지 coverage: @echo "📊 테스트 커버리지를 측정합니다..." @echo "==========================================" @if ! python3 -c "import pytest" 2>/dev/null; then \ echo "❌ pytest가 설치되어 있지 않습니다."; \ exit 1; \ fi @python3 -m pytest source_code/ --cov=source_code --cov-report=term-missing --cov-report=html 2>/dev/null || true @if [ -d "htmlcov" ]; then \ echo "✓ 커버리지 리포트가 htmlcov/ 폴더에 생성되었습니다"; \ fi @echo "🎉 커버리지 측정이 완료되었습니다!" # 캐시 파일 정리 clean: @echo "🧹 캐시 파일들을 정리합니다..." @echo "==========================================" @find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true @find . -type f -name "*.pyc" -delete 2>/dev/null || true @find . -type f -name "*.pyo" -delete 2>/dev/null || true @find . -type f -name "*.pyd" -delete 2>/dev/null || true @find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true @find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true @find . -type d -name "htmlcov" -exec rm -rf {} + 2>/dev/null || true @find . -type f -name ".coverage" -delete 2>/dev/null || true @echo "✓ 캐시 파일 정리 완료" # 개발 환경 설정 setup: @echo "🔧 개발 환경을 설정합니다..." @echo "==========================================" @if [ -f "pyproject.toml" ]; then \ echo "✓ Poetry를 사용하여 의존성을 설치합니다..."; \ poetry install || echo "⚠ Poetry 설치에 실패했습니다. pip install poetry로 Poetry를 설치하세요."; \ elif [ -f "requirements.txt" ]; then \ echo "✓ pip를 사용하여 의존성을 설치합니다..."; \ pip install -r requirements.txt || echo "⚠ pip 설치에 실패했습니다."; \ else \ echo "⚠ 의존성 파일을 찾을 수 없습니다."; \ fi @echo "✓ 개발 환경 설정 완료" # 의존성 설치 install: @echo "📦 의존성을 설치합니다..." @echo "==========================================" @if [ -f "pyproject.toml" ]; then \ echo "✓ Poetry를 사용하여 의존성을 설치합니다..."; \ poetry install; \ elif [ -f "requirements.txt" ]; then \ echo "✓ pip를 사용하여 의존성을 설치합니다..."; \ pip install -r requirements.txt; \ else \ echo "⚠ 의존성 파일을 찾을 수 없습니다."; \ exit 1; \ fi @echo "✓ 의존성 설치 완료" # 문서 빌드 (선택적) docs: @echo "📚 문서를 빌드합니다..." @echo "==========================================" @echo "⚠ 문서 빌드 기능은 아직 구현되지 않았습니다." @echo "현재는 Markdown 파일들이 직접 사용됩니다." # 포맷팅 + 테스트 (자주 사용하는 조합) check: format test # 전체 검사 (포맷팅 + 린트 + 테스트 + 커버리지) all: format lint test coverage # Docker 관련 명령어들 docker-build: @echo "🐳 Docker 이미지를 빌드합니다..." docker build -f Dockerfile.dev -t ai-lecture:dev . docker-run: @echo "🐳 Docker 컨테이너를 실행합니다..." docker run -it --rm -p 8000:8000 ai-lecture:dev docker-compose-up: @echo "🐳 Docker Compose로 서비스를 시작합니다..." docker-compose -f docker-compose.dev.yml up -d docker-compose-down: @echo "🐳 Docker Compose 서비스를 중지합니다..." docker-compose -f docker-compose.dev.yml down # 진도 관리 명령어들 progress: @echo "📊 학습 진도를 확인합니다..." @echo "==========================================" @if [ -f "scripts/progress_checker.py" ]; then \ python3 scripts/progress_checker.py show; \ else \ echo "❌ progress_checker.py 파일을 찾을 수 없습니다."; \ echo "scripts/ 디렉토리에 파일이 있는지 확인해주세요."; \ fi progress-show: @echo "📚 특정 파트 진도를 확인합니다..." @echo "==========================================" @if [ -f "scripts/progress_checker.py" ]; then \ if [ -n "$(PART)" ]; then \ python3 scripts/progress_checker.py show $(PART); \ else \ echo "❌ PART 변수를 지정해주세요. (예: make progress-show PART=part_2)"; \ fi; \ else \ echo "❌ progress_checker.py 파일을 찾을 수 없습니다."; \ fi progress-complete: @echo "✅ 학습 항목을 완료로 표시합니다..." @echo "==========================================" @if [ -f "scripts/progress_checker.py" ]; then \ if [ -n "$(PART)" ] && [ -n "$(ITEM)" ]; then \ python3 scripts/progress_checker.py complete $(PART) $(ITEM); \ else \ echo "❌ PART와 ITEM 변수를 모두 지정해주세요."; \ echo "예: make progress-complete PART=part_2 ITEM=0"; \ fi; \ else \ echo "❌ progress_checker.py 파일을 찾을 수 없습니다."; \ fi progress-incomplete: @echo "❌ 학습 항목을 미완료로 표시합니다..." @echo "==========================================" @if [ -f "scripts/progress_checker.py" ]; then \ if [ -n "$(PART)" ] && [ -n "$(ITEM)" ]; then \ python3 scripts/progress_checker.py incomplete $(PART) $(ITEM); \ else \ echo "❌ PART와 ITEM 변수를 모두 지정해주세요."; \ echo "예: make progress-incomplete PART=part_2 ITEM=0"; \ fi; \ else \ echo "❌ progress_checker.py 파일을 찾을 수 없습니다."; \ fi progress-reset: @echo "🔄 학습 진도를 초기화합니다..." @echo "==========================================" @if [ -f "scripts/progress_checker.py" ]; then \ if [ -n "$(PART)" ]; then \ python3 scripts/progress_checker.py reset $(PART); \ else \ echo "⚠️ 모든 진도를 초기화합니다. 계속하시겠습니까? (y/N)"; \ read -r response; \ if [ "$$response" = "y" ] || [ "$$response" = "Y" ]; then \ python3 scripts/progress_checker.py reset; \ else \ echo "진도 초기화가 취소되었습니다."; \ fi; \ fi; \ else \ echo "❌ progress_checker.py 파일을 찾을 수 없습니다."; \ fi progress-export: @echo "📄 학습 진도 리포트를 생성합니다..." @echo "==========================================" @if [ -f "scripts/progress_checker.py" ]; then \ if [ -n "$(FILE)" ]; then \ python3 scripts/progress_checker.py export $(FILE); \ else \ python3 scripts/progress_checker.py export progress_report.md; \ fi; \ else \ echo "❌ progress_checker.py 파일을 찾을 수 없습니다."; \ fi