-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathstats_cli.py
191 lines (146 loc) · 6.94 KB
/
stats_cli.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import sys
import tempfile
import yaml
from colorama import Fore, Style, init
from io import StringIO
from pathlib import Path
from .shgit import Sh
from .stats import main as stats
# Initialize colorama for Windows compatibility (does nothing on Linux/macOS)
init(autoreset=True)
class Capturing(list):
def __enter__(self):
self._stdout = sys.stdout
sys.stdout = self._stringio = StringIO()
return self
def __exit__(self, *_args):
self.extend(self._stringio.getvalue().splitlines())
del self._stringio # free up some memory
sys.stdout = self._stdout
# Define the ages you're interested in
AGES = ["now", "1 month ago", "2 months ago", "3 months ago", "4 months ago", "5 months ago", "6 months ago"]
# Path to the Git repository
REPO_PATH = "/Users/fprior/Development/GitFarm/workplace/fprior/update-mirror-3/update-mirror/src/AWSDocsSdkExamplesPublic"
# Path to the YAML file you want to extract from each commit
FILE_PATH = "tools/update_mirror/config.yaml"
def get_commit_hash_for_age(git, age):
"""
Get the commit hash for a specific age in the repository's history.
Args:
repo_dir (str): The path to the Git repository.
age (str): The age to search for (e.g., '1 month ago').
Returns:
str: The commit hash corresponding to the specified age, or None if not found.
"""
str(git('rev-list', '-1', f"--before={age}", 'HEAD', capture_output=True).stdout)
def run_commands_in_repo(git, commit_hash, age):
"""
Run Git log and a Python command in a specific commit of a repository.
Args:
git (Sh(git)): an shgit with the repo loaded as its CWD
commit_hash (str): The commit hash to run the commands in.
age (str): The age of the commit being processed.
"""
# Checkout repo at the specific commit
git.checkout("--force", commit_hash)
# Retrieve commit details
log_output = str(git('log', '-n', '1', commit_hash, pretty='format:"%H|%an|%aI"', capture_output=True).stdout)
if log_output:
hash, name, date = log_output.split('|')
print(f"{Fore.MAGENTA}Commit for {age}: {hash}, Author: {name}, Date: {date}")
# Run the Python command on the repository
print(f"{Fore.CYAN}Running stats command for repository: {git.cwd}")
with Capturing() as output:
stats([git.cwd])
if output:
print(output)
print("###########################")
else:
print(f"{Fore.RED}No commit found for {age} in {git.cwd}")
def get_file_from_commits_and_clone(git: Sh, file_path: str, ages):
"""
Extract file contents from specific commits and clone repositories for each mirror.
Args:
repo_path (str): Path to the main repository.
file_path (str): Path to the YAML file within the repository.
ages (list): List of age ranges to retrieve commit hashes for.
Returns:
dict: A dictionary mapping each age to the mirrors section of the YAML file.
"""
age_content_dict = {}
cloned_repos: dict[str, Path] = {} # To track cloned repositories and their directories
# Create a tmp directory for the clones
with tempfile.TemporaryDirectory() as tmp:
tmp_dir = Path(tmp)
# Fetch the config file from the main repository for each age
for age in ages:
print(f"{Style.BRIGHT}{Fore.BLUE}" + "#" * 61)
print(f"{Style.BRIGHT}{Fore.BLUE}" + f" {age.upper()} ".center(61, "#"))
print(f"{Style.BRIGHT}{Fore.BLUE}" + "#" * 61)
# Get the commit hash for the main repository
main_commit_hash = get_commit_hash_for_age(git, age)
if not main_commit_hash:
print(f"{Fore.RED}Skipping {age} because commit hash could not be retrieved for the main repository.")
continue
# Get the YAML configuration from that commit
file_content = str(git.show(f"{main_commit_hash}:{file_path}").stdout)
if file_content:
try:
# Parse the YAML content
yaml_content = yaml.safe_load(file_content)
# Extract the mirrors section
mirrors = yaml_content.get('mirrors', {})
age_content_dict[age] = mirrors
# Clone or reuse repos for each mirror
for mirror_name, mirror_info in mirrors.items():
process_mirror(cloned_repos, tmp_dir, age, mirror_name, mirror_info)
except yaml.YAMLError as exc:
print(f"{Fore.RED}Error parsing YAML file for {age}: {exc}")
else:
print(f"{Fore.RED}No file content found for commit {main_commit_hash} at {age}")
return age_content_dict
def process_mirror(cloned_repos, tmp_dir: Path, age, mirror_name, mirror_info):
repo_url = mirror_info.get('git_mirror')
branch = mirror_info.get('branch')
dir_name = mirror_info.get('dir')
# Check if repo has already been cloned
if repo_url not in cloned_repos:
# If not, clone the repository to a subfolder in the temp directory
clone_dir = tmp_dir/dir_name
git = Sh('git', cwd=clone_dir)
git.clone(repo_url, str(clone_dir))
git.checkout(branch)
# Mark this repo as cloned
cloned_repos[repo_url] = clone_dir
else:
print(f"{Fore.YELLOW}Reusing cloned repository {repo_url} for mirror {mirror_name}.")
git = Sh('git', cwd=cloned_repos[repo_url])
# Get the specific commit hash for this repo at this age
repo_commit_hash = get_commit_hash_for_age(git, age)
if repo_commit_hash:
# Run commands in the cloned repository for the specific commit hash
run_commands_in_repo(git, repo_commit_hash, age)
else:
print(f"{Fore.YELLOW}Skipping {mirror_name} in {age} due to failure in retrieving commit hash.")
def display_age_content_dict(age_content_dict):
"""
Display the mirrors section extracted from the YAML files, grouped by age.
Args:
age_content_dict (dict): A dictionary with age as keys and mirrors data as values.
"""
print(f"{Style.BRIGHT}{Fore.GREEN}File contents grouped by age range:")
for age, mirrors in age_content_dict.items():
print(f"{Fore.YELLOW}Age: {age}")
print(f"{Fore.CYAN}Mirrors:")
for mirror_name, mirror_info in mirrors.items():
print(f"{Fore.MAGENTA} - {mirror_name}:")
print(f" {Fore.CYAN}git_mirror: {mirror_info.get('git_mirror')}")
print(f" {Fore.CYAN}branch: {mirror_info.get('branch')}")
print(f" {Fore.CYAN}dir: {mirror_info.get('dir')}")
print("-----------------")
if __name__ == "__main__":
# Get the contents from the commits and clone the repos.
git = Sh('git', cwd=REPO_PATH)
age_content_dict = get_file_from_commits_and_clone(git, FILE_PATH, AGES)
# Display the contents in the dictionary format.
display_age_content_dict(age_content_dict)