Skip to content

Instantly share code, notes, and snippets.

@kylemcdonald
Created August 6, 2025 01:47
Show Gist options
  • Select an option

  • Save kylemcdonald/43724f3054ab1912fb7bd334c1e48525 to your computer and use it in GitHub Desktop.

Select an option

Save kylemcdonald/43724f3054ab1912fb7bd334c1e48525 to your computer and use it in GitHub Desktop.
Python script for copying many files of interest from old hard drives.
#!/usr/bin/env python3
import os
import shutil
import argparse
from pathlib import Path
def copy_source_files(source_dir, dest_dir, extensions=('.h', '.cpp', '.pde')):
"""
Recursively find files with specified extensions and copy them to destination
while preserving folder hierarchy.
Args:
source_dir (str): Source directory to search
dest_dir (str): Destination directory to copy files to
extensions (tuple): File extensions to search for
"""
source_path = Path(source_dir)
dest_path = Path(dest_dir)
# Create destination directory if it doesn't exist
dest_path.mkdir(parents=True, exist_ok=True)
copied_count = 0
# Walk through source directory recursively
for root, dirs, files in os.walk(source_path):
# Filter out build artifacts and non-source directories
excluded_dirs = {
'.xcodeproj', 'libs', 'applet', 'web-export'
}
excluded_patterns = [
lambda d: d.endswith('.app'),
lambda d: d.endswith('.macosx'),
lambda d: d.startswith('application.')
]
dirs[:] = [
d for d in dirs
if d not in excluded_dirs
and not any(pattern(d) for pattern in excluded_patterns)
]
root_path = Path(root)
# Get relative path from source directory
relative_path = root_path.relative_to(source_path)
# Check each file in current directory
for file in files:
if file.lower().endswith(extensions):
# Create corresponding directory in destination only when we have a file to copy
dest_subdir = dest_path / relative_path
dest_subdir.mkdir(parents=True, exist_ok=True)
source_file = root_path / file
dest_file = dest_subdir / file
try:
shutil.copy2(source_file, dest_file)
print(f"Copied: {source_file} -> {dest_file}")
copied_count += 1
except Exception as e:
print(f"Error copying {source_file}: {e}")
print(f"\nTotal files copied: {copied_count}")
def main():
parser = argparse.ArgumentParser(
description="Copy source files (.h, .cpp, .pde) to a new directory while preserving folder structure"
)
parser.add_argument(
"source_dir",
help="Source directory to search for files"
)
parser.add_argument(
"dest_dir",
help="Destination directory to copy files to"
)
parser.add_argument(
"--extensions",
nargs="+",
default=['.h', '.c', '.hpp', '.cpp', '.pde'],
help="File extensions to search for (default: .h .cpp .pde)"
)
args = parser.parse_args()
# Validate source directory exists
if not os.path.exists(args.source_dir):
print(f"Error: Source directory '{args.source_dir}' does not exist.")
return
# Convert extensions to tuple and ensure they start with dot
extensions = tuple(ext if ext.startswith('.') else f'.{ext}' for ext in args.extensions)
print(f"Searching for files with extensions: {extensions}")
print(f"Source directory: {args.source_dir}")
print(f"Destination directory: {args.dest_dir}")
print("-" * 50)
copy_source_files(args.source_dir, args.dest_dir, extensions)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment