#!/usr/bin/env python3 """ Packages the client-side scripts and their dependencies into a distributable .tar.gz archive. This script should be run from the root of the project repository. """ import argparse import os import shutil import sys import tarfile from pathlib import Path try: # Assumes yt_ops_services/version.py exists and is importable from yt_ops_services.version import get_version as get_api_version except ImportError: print("Error: Could not import get_version from yt_ops_services.version.", file=sys.stderr) print("Please ensure yt_ops_services/version.py exists and run this script from the project root.", file=sys.stderr) sys.exit(1) def get_client_version(): """Reads the client version from the VERSION.client file.""" try: return Path('VERSION.client').read_text(encoding='utf-8').strip() except FileNotFoundError: print("Error: VERSION.client file not found in the project root.", file=sys.stderr) sys.exit(1) # --- Configuration --- # Defines the content of the package. # Keys are source paths relative to the project root. # Values are destination paths inside the archive. PACKAGE_CONTENT = { 'get_info_json_client.py': 'get_info_json_client.py', 'list_formats.py': 'list_formats.py', 'format_download.py': 'format_download.py', 'stress_test_formats.py': 'stress_test_formats.py', 'cli.config': 'cli.config', 'README.client.md': 'README.md', # Rename for convention 'formats.md': 'formats.md', 'VERSION.client': 'VERSION.client', 'yt_ops_services': 'yt_ops_services', 'thrift_model/gen_py': 'thrift_model/gen_py', } # Client-side Python requirements CLIENT_REQUIREMENTS = [ 'thrift==0.16.0', ] def main(): """Main entry point""" parser = argparse.ArgumentParser(description="Package the yt-ops-services client tools.") parser.add_argument('--output-dir', default='dist', help='Directory to save the package file (default: dist).') args = parser.parse_args() api_version = get_api_version() client_version = get_client_version() package_name = f"yt-ops-services-client-{api_version}-{client_version}" archive_filename = f"{package_name}.tar.gz" os.makedirs(args.output_dir, exist_ok=True) archive_path = os.path.join(args.output_dir, archive_filename) staging_dir = Path(args.output_dir) / f"{package_name}-staging" print(f"Creating client package: {archive_filename}") if staging_dir.exists(): shutil.rmtree(staging_dir) staging_dir.mkdir(parents=True) package_root = staging_dir / package_name package_root.mkdir() try: print("Staging files...") for src, dest in PACKAGE_CONTENT.items(): src_path = Path(src) dest_path = package_root / dest if not src_path.exists(): print(f"Warning: Source not found, skipping: {src_path}", file=sys.stderr) continue dest_path.parent.mkdir(parents=True, exist_ok=True) if src_path.is_dir(): shutil.copytree(src_path, dest_path) else: shutil.copy2(src_path, dest_path) # Create __init__.py to ensure thrift_model is a package (package_root / 'thrift_model/__init__.py').touch() print("Creating requirements.txt...") (package_root / 'requirements.txt').write_text('\n'.join(CLIENT_REQUIREMENTS) + '\n', encoding='utf-8') print(f"Creating archive at {archive_path}...") with tarfile.open(archive_path, "w:gz") as tar: tar.add(package_root, arcname=package_name) print("\nPackage created successfully!") print(f" -> {archive_path}") finally: if staging_dir.exists(): print("Cleaning up staging directory...") shutil.rmtree(staging_dir) if __name__ == "__main__": main()