16f56a586Spaul_hoad#!/usr/bin/env python 26f56a586Spaul_hoad# A tool to parse creates a document outlining how clang formatted the 36f56a586Spaul_hoad# LLVM project is. 46f56a586Spaul_hoad 56f56a586Spaul_hoadimport sys 66f56a586Spaul_hoadimport os 76f56a586Spaul_hoadimport subprocess 86f56a586Spaul_hoadfrom datetime import datetime 96f56a586Spaul_hoad 106f56a586Spaul_hoad 116f56a586Spaul_hoaddef get_git_revision_short_hash(): 125aca8bb9Smydeveloperday """Get the get SHA in short hash form.""" 13dd3c26a0STobias Hieta return ( 14dd3c26a0STobias Hieta subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]) 15dd3c26a0STobias Hieta .decode(sys.stdout.encoding) 16dd3c26a0STobias Hieta .strip() 17dd3c26a0STobias Hieta ) 186f56a586Spaul_hoad 196f56a586Spaul_hoad 206f56a586Spaul_hoaddef get_style(count, passed): 215aca8bb9Smydeveloperday """Determine if this directory is good based on the number of clean 225aca8bb9Smydeveloperday files vs the number of files in total.""" 236f56a586Spaul_hoad if passed == count: 246f56a586Spaul_hoad return ":good:" 255aca8bb9Smydeveloperday if passed != 0: 266f56a586Spaul_hoad return ":part:" 276f56a586Spaul_hoad return ":none:" 286f56a586Spaul_hoad 296f56a586Spaul_hoad 30dd3c26a0STobias HietaTOP_DIR = os.path.join(os.path.dirname(__file__), "../../..") 31dd3c26a0STobias HietaCLANG_DIR = os.path.join(os.path.dirname(__file__), "../..") 32dd3c26a0STobias HietaDOC_FILE = os.path.join(CLANG_DIR, "docs/ClangFormattedStatus.rst") 33dd3c26a0STobias HietaCLEAN_FILE = os.path.join(CLANG_DIR, "docs/tools/clang-formatted-files.txt") 346f56a586Spaul_hoad 356f56a586Spaul_hoadrootdir = TOP_DIR 366f56a586Spaul_hoad 376f56a586Spaul_hoadskipped_dirs = [".git", "test"] 386f56a586Spaul_hoadsuffixes = (".cpp", ".h") 396f56a586Spaul_hoad 405aca8bb9SmydeveloperdayRST_PREFIX = """\ 416f56a586Spaul_hoad.. raw:: html 426f56a586Spaul_hoad 436f56a586Spaul_hoad <style type="text/css"> 446f56a586Spaul_hoad .total {{ font-weight: bold; }} 453019898eSmydeveloperday .none {{ background-color: #FFFF99; height: 20px; display: inline-block; width: 120px; text-align: center; border-radius: 5px; color: #000000; font-family="Verdana,Geneva,DejaVu Sans,sans-serif" }} 463019898eSmydeveloperday .part {{ background-color: #FFCC99; height: 20px; display: inline-block; width: 120px; text-align: center; border-radius: 5px; color: #000000; font-family="Verdana,Geneva,DejaVu Sans,sans-serif" }} 473019898eSmydeveloperday .good {{ background-color: #2CCCFF; height: 20px; display: inline-block; width: 120px; text-align: center; border-radius: 5px; color: #000000; font-family="Verdana,Geneva,DejaVu Sans,sans-serif" }} 486f56a586Spaul_hoad </style> 496f56a586Spaul_hoad 506f56a586Spaul_hoad.. role:: none 516f56a586Spaul_hoad.. role:: part 526f56a586Spaul_hoad.. role:: good 536f56a586Spaul_hoad.. role:: total 546f56a586Spaul_hoad 556f56a586Spaul_hoad====================== 566f56a586Spaul_hoadClang Formatted Status 576f56a586Spaul_hoad====================== 586f56a586Spaul_hoad 596f56a586Spaul_hoad:doc:`ClangFormattedStatus` describes the state of LLVM source 606f56a586Spaul_hoadtree in terms of conformance to :doc:`ClangFormat` as of: {today} (`{sha} <https://github.com/llvm/llvm-project/commit/{sha}>`_). 616f56a586Spaul_hoad 626f56a586Spaul_hoad 636f56a586Spaul_hoad.. list-table:: LLVM Clang-Format Status 646f56a586Spaul_hoad :widths: 50 25 25 25 25 656f56a586Spaul_hoad :header-rows: 1\n 666f56a586Spaul_hoad * - Directory 676f56a586Spaul_hoad - Total Files 686f56a586Spaul_hoad - Formatted Files 696f56a586Spaul_hoad - Unformatted Files 706f56a586Spaul_hoad - % Complete 716f56a586Spaul_hoad""" 726f56a586Spaul_hoad 735aca8bb9SmydeveloperdayTABLE_ROW = """\ 746f56a586Spaul_hoad * - {path} 756f56a586Spaul_hoad - {style}`{count}` 766f56a586Spaul_hoad - {style}`{passes}` 776f56a586Spaul_hoad - {style}`{fails}` 786f56a586Spaul_hoad - {style2}`{percent}%` 796f56a586Spaul_hoad""" 806f56a586Spaul_hoad 815aca8bb9Smydeveloperday 82dd3c26a0STobias Hietawith open(DOC_FILE, "wb") as output: 835aca8bb9Smydeveloperday cleanfiles = open(CLEAN_FILE, "wb") 846f56a586Spaul_hoad sha = get_git_revision_short_hash() 856f56a586Spaul_hoad today = datetime.now().strftime("%B %d, %Y %H:%M:%S") 86dd3c26a0STobias Hieta output.write(bytes(RST_PREFIX.format(today=today, sha=sha).encode("utf-8"))) 876f56a586Spaul_hoad 886f56a586Spaul_hoad total_files_count = 0 896f56a586Spaul_hoad total_files_pass = 0 906f56a586Spaul_hoad total_files_fail = 0 916f56a586Spaul_hoad for root, subdirs, files in os.walk(rootdir): 926f56a586Spaul_hoad for subdir in subdirs: 936f56a586Spaul_hoad if any(sd == subdir for sd in skipped_dirs): 946f56a586Spaul_hoad subdirs.remove(subdir) 95abafb655SNathan James else: 96abafb655SNathan James act_sub_dir = os.path.join(root, subdir) 97abafb655SNathan James # Check the git index to see if the directory contains tracked 98abafb655SNathan James # files. Reditect the output to a null descriptor as we aren't 99abafb655SNathan James # interested in it, just the return code. 100abafb655SNathan James git_check = subprocess.Popen( 101abafb655SNathan James ["git", "ls-files", "--error-unmatch", act_sub_dir], 102*c49770c6SNicolas van Kempen stdout=subprocess.DEVNULL, 103*c49770c6SNicolas van Kempen stderr=subprocess.DEVNULL, 104dd3c26a0STobias Hieta ) 105abafb655SNathan James if git_check.wait() != 0: 106abafb655SNathan James print("Skipping directory: ", act_sub_dir) 107abafb655SNathan James subdirs.remove(subdir) 1086f56a586Spaul_hoad 1096f56a586Spaul_hoad path = os.path.relpath(root, TOP_DIR) 110dd3c26a0STobias Hieta path = path.replace("\\", "/") 1116f56a586Spaul_hoad 1126f56a586Spaul_hoad file_count = 0 1136f56a586Spaul_hoad file_pass = 0 1146f56a586Spaul_hoad file_fail = 0 1156f56a586Spaul_hoad for filename in files: 1166f56a586Spaul_hoad file_path = os.path.join(root, filename) 1176f56a586Spaul_hoad ext = os.path.splitext(file_path)[-1].lower() 1186f56a586Spaul_hoad if not ext.endswith(suffixes): 1196f56a586Spaul_hoad continue 1206f56a586Spaul_hoad 1216f56a586Spaul_hoad file_count += 1 1226f56a586Spaul_hoad 1236f56a586Spaul_hoad args = ["clang-format", "-n", file_path] 1246f56a586Spaul_hoad cmd = subprocess.Popen(args, stderr=subprocess.PIPE) 1256f56a586Spaul_hoad stdout, err = cmd.communicate() 1266f56a586Spaul_hoad 1276f56a586Spaul_hoad relpath = os.path.relpath(file_path, TOP_DIR) 128dd3c26a0STobias Hieta relpath = relpath.replace("\\", "/") 129dd3c26a0STobias Hieta if err.decode(sys.stdout.encoding).find(": warning:") > 0: 1306f56a586Spaul_hoad print(relpath, ":", "FAIL") 1316f56a586Spaul_hoad file_fail += 1 1326f56a586Spaul_hoad else: 1336f56a586Spaul_hoad print(relpath, ":", "PASS") 1346f56a586Spaul_hoad file_pass += 1 1355aca8bb9Smydeveloperday cleanfiles.write(bytes(relpath + "\n")) 1365aca8bb9Smydeveloperday cleanfiles.flush() 1376f56a586Spaul_hoad 1386f56a586Spaul_hoad total_files_count += file_count 1396f56a586Spaul_hoad total_files_pass += file_pass 1406f56a586Spaul_hoad total_files_fail += file_fail 1416f56a586Spaul_hoad 1426f56a586Spaul_hoad if file_count > 0: 143dd3c26a0STobias Hieta percent = int(100.0 * (float(file_pass) / float(file_count))) 1446f56a586Spaul_hoad style = get_style(file_count, file_pass) 145dd3c26a0STobias Hieta output.write( 146dd3c26a0STobias Hieta bytes( 147dd3c26a0STobias Hieta TABLE_ROW.format( 148dd3c26a0STobias Hieta path=path, 1496f56a586Spaul_hoad count=file_count, 1506f56a586Spaul_hoad passes=file_pass, 1516f56a586Spaul_hoad fails=file_fail, 152dd3c26a0STobias Hieta percent=str(percent), 153dd3c26a0STobias Hieta style="", 154dd3c26a0STobias Hieta style2=style, 155dd3c26a0STobias Hieta ).encode("utf-8") 156dd3c26a0STobias Hieta ) 157dd3c26a0STobias Hieta ) 1586f56a586Spaul_hoad output.flush() 1596f56a586Spaul_hoad 1606f56a586Spaul_hoad print("----\n") 1616f56a586Spaul_hoad print(path, file_count, file_pass, file_fail, percent) 1626f56a586Spaul_hoad print("----\n") 1636f56a586Spaul_hoad 164dd3c26a0STobias Hieta total_percent = float(total_files_pass) / float(total_files_count) 1656f56a586Spaul_hoad percent_str = str(int(100.0 * total_percent)) 166dd3c26a0STobias Hieta output.write( 167dd3c26a0STobias Hieta bytes( 168dd3c26a0STobias Hieta TABLE_ROW.format( 169dd3c26a0STobias Hieta path="Total", 1706f56a586Spaul_hoad count=total_files_count, 1716f56a586Spaul_hoad passes=total_files_pass, 1726f56a586Spaul_hoad fails=total_files_fail, 173dd3c26a0STobias Hieta percent=percent_str, 174dd3c26a0STobias Hieta style=":total:", 175dd3c26a0STobias Hieta style2=":total:", 176dd3c26a0STobias Hieta ).encode("utf-8") 177dd3c26a0STobias Hieta ) 178dd3c26a0STobias Hieta ) 179