import subprocess import tempfile import shutil import os from typing import Optional, Union, Dict, List, Tuple def get_repo_readme(repo_source: str, commit_depth: int = 1) -> Union[Tuple[str, str], str]: """ Returns the README content of a git repository at a specific commit. Args: repo_source: Path to the git repository or URL to a remote repository. Function automatically detects if it's a local path or remote URL. commit_depth: How many commits back to check (default=1 for the latest commit). For example, 2 would return the README from the second-to-last commit. Returns: A tuple containing (readme_filename, readme_content) if README is found, or an error string if something fails or no README is found """ temp_dir = None try: # Determine if repo_source is a remote URL or local path is_remote = repo_source.startswith(('http://', 'https://', 'git://', 'ssh://')) or repo_source.endswith('.git') # If it's a remote repository, clone it to a temporary directory if is_remote: temp_dir = tempfile.mkdtemp() print(f"Cloning remote repository: {repo_source}") clone_cmd = ["git", "clone", repo_source, temp_dir] subprocess.check_output(clone_cmd) repo_path = temp_dir else: repo_path = repo_source # Validate commit_depth parameter if commit_depth < 1: return "Error: commit_depth must be a positive integer" # Get the commit hash for the specified depth if commit_depth == 1: # For the latest commit commit_ref = "HEAD" else: # For earlier commits: HEAD~1, HEAD~2, etc. (0-indexed in git, so we subtract 1) commit_ref = f"HEAD~{commit_depth-1}" # Get the commit hash commit_cmd = ["git", "-C", repo_path, "rev-parse", commit_ref] try: commit_hash = subprocess.check_output(commit_cmd).decode('utf-8').strip() except subprocess.CalledProcessError: return f"Error: Could not find commit at depth {commit_depth}" # Common README file patterns to check readme_patterns = [ "README.md", "README.txt", "README", "readme.md", "Readme.md", "ReadMe.md", "readme.txt", "README.markdown", "readme.markdown" ] # Check for the existence of README files ls_files_cmd = ["git", "-C", repo_path, "ls-tree", "--name-only", commit_hash] files = subprocess.check_output(ls_files_cmd).decode('utf-8').strip().split('\n') readme_file = None for pattern in readme_patterns: if pattern in files: readme_file = pattern break # Also check in the root directory if not readme_file: for pattern in readme_patterns: if any(f == pattern or f.endswith(f"/{pattern}") for f in files): readme_file = next((f for f in files if f == pattern or f.endswith(f"/{pattern}")), None) break if not readme_file: return "No README file found in the repository" # Get the content of the README file at the specified commit show_cmd = ["git", "-C", repo_path, "show", f"{commit_hash}:{readme_file}"] try: readme_content = subprocess.check_output(show_cmd).decode('utf-8') return (readme_file, readme_content) except subprocess.CalledProcessError: return f"Error: Could not read {readme_file} at commit {commit_hash}" except subprocess.CalledProcessError as e: return f"Error executing git command: {str(e)}" except Exception as e: return f"Unexpected error: {str(e)}" finally: # Clean up temporary directory if it was created if temp_dir and os.path.exists(temp_dir): shutil.rmtree(temp_dir) # Example usage if __name__ == "__main__": import sys if len(sys.argv) < 2: print("Usage: python git_readme_utils.py [commit_depth]") print(" repo_path_or_url: Path to local repository or URL to remote repository") print(" commit_depth: Optional - How many commits back to check (default=1 for latest commit)") sys.exit(1) repo_source = sys.argv[1] commit_depth = 1 # Default to latest commit # Check if commit_depth was provided if len(sys.argv) > 2: try: commit_depth = int(sys.argv[2]) if commit_depth < 1: print("Error: commit_depth must be a positive integer") sys.exit(1) except ValueError: print("Error: commit_depth must be an integer") sys.exit(1) print(f"Getting README for repository: {repo_source} (commit depth: {commit_depth})") result = get_repo_readme(repo_source, commit_depth) if isinstance(result, tuple): readme_file, readme_content = result print(f"\nFound README file: {readme_file}\n") print("=" * 80) print(readme_content) print("=" * 80) else: print(result) # Error message