at main 2.9 kB view raw
1#!/usr/bin/env -S uv run --script --quiet 2"""Copy R2 bucket data from old buckets to new buckets.""" 3 4from pathlib import Path 5 6import boto3 7from pydantic import Field 8from pydantic_settings import BaseSettings, SettingsConfigDict 9 10BASE_DIR = Path(__file__).resolve().parents[1] 11 12 13class R2Settings(BaseSettings): 14 """R2 credentials from environment.""" 15 16 model_config = SettingsConfigDict( 17 env_file=str(BASE_DIR / ".env"), 18 env_file_encoding="utf-8", 19 extra="ignore", 20 case_sensitive=False, 21 ) 22 23 aws_access_key_id: str = Field(validation_alias="AWS_ACCESS_KEY_ID") 24 aws_secret_access_key: str = Field(validation_alias="AWS_SECRET_ACCESS_KEY") 25 r2_endpoint_url: str = Field(validation_alias="R2_ENDPOINT_URL") 26 27 28def get_s3_client(): 29 """Create S3 client for R2.""" 30 settings = R2Settings() 31 return boto3.client( 32 "s3", 33 endpoint_url=settings.r2_endpoint_url, 34 aws_access_key_id=settings.aws_access_key_id, 35 aws_secret_access_key=settings.aws_secret_access_key, 36 region_name="auto", 37 ) 38 39 40def copy_bucket(s3_client, source_bucket: str, dest_bucket: str): 41 """Copy all objects from source bucket to destination bucket.""" 42 print(f"\n{'=' * 60}") 43 print(f"Copying from '{source_bucket}' to '{dest_bucket}'") 44 print(f"{'=' * 60}\n") 45 46 # List all objects in source bucket 47 paginator = s3_client.get_paginator("list_objects_v2") 48 pages = paginator.paginate(Bucket=source_bucket) 49 50 total_objects = 0 51 copied_objects = 0 52 53 for page in pages: 54 if "Contents" not in page: 55 print(f"No objects found in {source_bucket}") 56 return 57 58 for obj in page["Contents"]: 59 key = obj["Key"] 60 total_objects += 1 61 62 try: 63 # Copy object 64 copy_source = {"Bucket": source_bucket, "Key": key} 65 s3_client.copy_object( 66 CopySource=copy_source, Bucket=dest_bucket, Key=key 67 ) 68 copied_objects += 1 69 print(f"✓ Copied: {key} ({obj['Size']} bytes)") 70 except Exception as e: 71 print(f"✗ Failed to copy {key}: {e}") 72 73 print(f"\n{'=' * 60}") 74 print(f"Summary: {copied_objects}/{total_objects} objects copied successfully") 75 print(f"{'=' * 60}\n") 76 77 78def main(): 79 """Copy data from old buckets to new buckets.""" 80 s3_client = get_s3_client() 81 82 # Define bucket mappings 83 bucket_mappings = [ 84 ("relay", "audio-prod"), 85 ("relay-stg", "audio-staging"), 86 ] 87 88 print("\n🚀 Starting R2 bucket copy operation\n") 89 90 for source, dest in bucket_mappings: 91 try: 92 copy_bucket(s3_client, source, dest) 93 except Exception as e: 94 print(f"✗ Error copying {source} -> {dest}: {e}") 95 continue 96 97 print("✅ All copy operations completed!\n") 98 99 100if __name__ == "__main__": 101 main()