import os import glob import fnmatch def clean_files_oswalk(): """os.walk를 사용한 기존 방식 - 더 세밀한 컨트롤 가능""" # 1. 삭제할 확장자 정의 target_extensions = ('.c', '.pyd') # 2. 제외할 폴더 이름 (어디에 있든 이름이 일치하면 제외) # 대소문자를 정확히 입력해주세요. 필요시 '.git', '__pycache__' 등 추가 exclude_folder_names = { 'scripts', 'build', 'Lib', '.git', '__pycache__', 'venv', 'env', '.env', '.venv', 'virtualenv', '.virtualenv', 'conda', 'miniconda', 'anaconda', 'miniforge', 'node_modules', 'dist', 'build', 'target', '.vscode', '.idea', '__pycache__', '.pytest_cache', '.mypy_cache', '.tox', '.coverage', '.DS_Store' } # 3. 제외할 특정 경로 (현재 위치 기준 상대 경로) # 예: 'src/browsers'는 ./src/browsers 폴더 하위를 모두 제외함 exclude_specific_paths = {'src/browsers'} # 경로 구분자 통일 (Windows '\', Mac/Linux '/' 호환성 확보) exclude_specific_paths = {os.path.normpath(p) for p in exclude_specific_paths} current_dir = os.getcwd() # 현재 실행 위치 print(f"작업 시작 위치: {current_dir}") print("-" * 30) for root, dirs, files in os.walk(current_dir): # [중요] dirs 리스트를 제자리에서 수정(slice assignment)하여 # os.walk가 제외된 폴더로 진입하지 않도록 막습니다. # 1차 필터링: 폴더 이름으로 제외 (예: build, Lib) dirs[:] = [d for d in dirs if d not in exclude_folder_names] # 2차 필터링: 특정 경로로 제외 (예: src/browsers) allowed_dirs = [] for d in dirs: # 현재 탐색 중인 폴더(root) + 하위 폴더(d)의 전체 경로 생성 full_path = os.path.join(root, d) # 실행 위치 기준 상대 경로 계산 rel_path = os.path.relpath(full_path, current_dir) # 제외할 경로 리스트에 포함되어 있는지 확인 if rel_path not in exclude_specific_paths: allowed_dirs.append(d) else: print(f"[제외됨] 경로: {rel_path}") dirs[:] = allowed_dirs # 파일 삭제 로직 for file in files: if file.endswith(target_extensions): file_path = os.path.join(root, file) try: os.remove(file_path) print(f"삭제됨: {file_path}") except Exception as e: print(f"오류 발생 ({file}): {e}") def clean_files_glob(): """glob을 사용한 방식 - 더 간단하지만 덜 세밀한 컨트롤""" current_dir = os.getcwd() print(f"작업 시작 위치: {current_dir}") print("-" * 30) # 제외할 폴더 패턴들 exclude_patterns = [ '**/venv/**', '**/env/**', '**/.env/**', '**/.venv/**', '**/virtualenv/**', '**/.virtualenv/**', '**/conda/**', '**/miniconda/**', '**/anaconda/**', '**/miniforge/**', '**/node_modules/**', '**/dist/**', '**/build/**', '**/target/**', '**/.git/**', '**/__pycache__/**', '**/.vscode/**', '**/.idea/**', '**/.pytest_cache/**', '**/.mypy_cache/**', '**/.tox/**', '**/.coverage/**' ] deleted_count = 0 total_size = 0 # .c 파일들 찾기 for c_file in glob.glob("**/*.c", recursive=True): if not _is_excluded_by_patterns(c_file, exclude_patterns): try: size = os.path.getsize(c_file) os.remove(c_file) print(f"삭제됨: {c_file} ({size} bytes)") deleted_count += 1 total_size += size except Exception as e: print(f"오류 발생 ({c_file}): {e}") # .pyd 파일들 찾기 for pyd_file in glob.glob("**/*.pyd", recursive=True): if not _is_excluded_by_patterns(pyd_file, exclude_patterns): try: size = os.path.getsize(pyd_file) os.remove(pyd_file) print(f"삭제됨: {pyd_file} ({size} bytes)") deleted_count += 1 total_size += size except Exception as e: print(f"오류 발생 ({pyd_file}): {e}") print(f"\n총 {deleted_count}개 파일 삭제, {total_size} bytes 정리됨") def _is_excluded_by_patterns(file_path, exclude_patterns): """파일 경로가 제외 패턴에 매칭되는지 확인""" for pattern in exclude_patterns: # glob 패턴을 fnmatch 스타일로 변환 if fnmatch.fnmatch(file_path, pattern): return True return False def clean_files(): """메인 정리 함수 - 기본적으로 oswalk 방식을 사용 (더 안전하고 세밀한 컨트롤)""" print("=== Cython 빌드 파일 정리기 ===") print("두 가지 정리 방식이 있습니다:") print("1: os.walk 방식 (세밀한 컨트롤, 폴더별 제외, 추천)") print("2: glob 방식 (간단하지만 덜 정밀)") try: choice = input("방식을 선택하세요 (1 또는 2, 기본값: 1): ").strip() if choice == "2": print("glob 방식을 선택했습니다.") clean_files_glob() else: print("os.walk 방식을 선택했습니다.") clean_files_oswalk() except KeyboardInterrupt: print("\n\n작업이 취소되었습니다.") return if __name__ == "__main__": # 실수로 실행하는 것을 방지하기 위해 사용자 확인을 추가할 수 있습니다. confirm = input("현재 폴더 내의 모든 .c, .pyd 파일을 삭제하시겠습니까? (y/n): ") if confirm.lower() == 'y': clean_files() print("\n작업 완료.") else: print("취소되었습니다.")