75 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Python
		
	
	
	
| import os
 | |
| import subprocess
 | |
| from collections import Counter
 | |
| 
 | |
| CONFIG_FILE_EXTENSIONS = (".json", ".yml", ".yaml", ".ini", ".conf", ".toml")
 | |
| 
 | |
| 
 | |
| def is_text_file(filepath):
 | |
|     # Check for binary file by scanning for null bytes.
 | |
|     try:
 | |
|         with open(filepath, "rb") as f:
 | |
|             chunk = f.read(4096)
 | |
|         if b"\0" in chunk:
 | |
|             return False
 | |
|         return True
 | |
|     except Exception:
 | |
|         return False
 | |
| 
 | |
| 
 | |
| def should_skip_file(path):
 | |
|     base = os.path.basename(path)
 | |
|     # Skip dotfiles and dotdirs
 | |
|     if base.startswith("."):
 | |
|         return True
 | |
|     # Skip config files by extension
 | |
|     if base.lower().endswith(CONFIG_FILE_EXTENSIONS):
 | |
|         return True
 | |
|     return False
 | |
| 
 | |
| 
 | |
| def get_tracked_files():
 | |
|     try:
 | |
|         output = subprocess.check_output(["git", "ls-files"], text=True)
 | |
|         files = output.strip().split("\n")
 | |
|         files = [f for f in files if f and os.path.isfile(f)]
 | |
|         return files
 | |
|     except subprocess.CalledProcessError:
 | |
|         print("Error: Are you in a git repository?")
 | |
|         return []
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     files = get_tracked_files()
 | |
|     email_counter = Counter()
 | |
|     total_lines = 0
 | |
| 
 | |
|     for file in files:
 | |
|         if should_skip_file(file):
 | |
|             continue
 | |
|         if not is_text_file(file):
 | |
|             continue
 | |
|         try:
 | |
|             blame = subprocess.check_output(
 | |
|                 ["git", "blame", "-e", file], text=True, errors="replace"
 | |
|             )
 | |
|             for line in blame.splitlines():
 | |
|                 # The email always inside <>
 | |
|                 if "<" in line and ">" in line:
 | |
|                     try:
 | |
|                         email = line.split("<")[1].split(">")[0].strip()
 | |
|                     except Exception:
 | |
|                         continue
 | |
|                     email_counter[email] += 1
 | |
|                     total_lines += 1
 | |
|         except subprocess.CalledProcessError:
 | |
|             continue
 | |
| 
 | |
|     for email, lines in email_counter.most_common():
 | |
|         percent = (lines / total_lines * 100) if total_lines else 0
 | |
|         print(f"{email}: {lines}/{total_lines} {percent:.2f}%")
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |