Spaces:
Running
Running
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 <repo_path_or_url> [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 | |