1#!/usr/bin/python 2## 3## Generates a summary of all branches in the repository. 4## Prints the branch creation date, the last update, 5## and whether the respective branch has been merged to 'master' or 'next' 6## Output is a standalone .html file. 7## 8## Usage: $> branches.py TYPE OUTPUT"; 9## TYPE ... Either 'all' or 'active'"; 10## OUTFILE ... The output file where the HTML code will be written to"; 11 12 13import os 14import sys 15import time 16import subprocess 17import datetime 18 19## Create a separate group in the summary for these: 20branchnames = ["balay", "barry", "hzhang", "jed", "karlrupp", "knepley", "mark", "prbrune", "sarich", "stefano_zampini", "tisaac"] 21 22 23 24## Worker function: 25 26def printtable(outfile, branches, anchor): 27 28 # Write table head: 29 outfile.write("<center><a name=\"" + anchor + "\"></a>") 30 outfile.write("<table>\n"); 31 outfile.write("<tr><th>Branchname</th><th>Created</th><th>Last Update</th><th>next </th><th>master</th><th> </th></tr>\n"); 32 outfile.write("<tr><td> </td><td>(days) </td><td>(days) </td><td> </td><td> </td><td> </td></tr>\n"); 33 34 tablebuffer = []; 35 36 # Write table body: 37 for branch in branches: 38 39 # Branch name 40 tablerow = "<tr><td>" + branch[7:] +"</td>"; 41 42 # Created: First get commit hash of merge base, then get date for commit 43 process = subprocess.Popen(["git", "merge-base", "remotes/" + branch, "master"], stdout=subprocess.PIPE) 44 commithash, err = process.communicate() 45 commithash = commithash.replace("\r", "").replace("\n", "") 46 process = subprocess.Popen(["git", "log", "--pretty=format:%at", commithash, "-n", "1"], stdout=subprocess.PIPE) 47 unixtime, err = process.communicate() 48 num_days = (int(time.time()) - int(unixtime)) / (60*60*24) 49 tablerow += "<td>" + str(int(num_days)) + "</td>"; 50 51 # Last Update: 52 process = subprocess.Popen(["git", "log", "--pretty=format:%at", "remotes/" + branch, "-n", "1"], stdout=subprocess.PIPE) 53 unixtime, err = process.communicate() 54 num_days = (int(time.time()) - int(unixtime)) / (60*60*24) 55 tablerow += "<td>" + str(int(num_days)) + "</td>"; 56 57 # Merged next: 58 process = subprocess.Popen(["git", "log", "--pretty=oneline", "remotes/origin/next..remotes/" + branch, "-n", "1"], stdout=subprocess.PIPE) 59 stdoutstring, err = process.communicate() 60 if (len(stdoutstring) > 2): 61 tablerow += "<td class=\"yellow\">no</td>"; 62 else: 63 tablerow += "<td class=\"green\">yes</td>"; 64 65 # Merged master: 66 process = subprocess.Popen(["git", "log", "--pretty=oneline", "remotes/origin/master..remotes/" + branch, "-n", "1"], stdout=subprocess.PIPE) 67 stdoutstring, err = process.communicate() 68 if (len(stdoutstring) > 2): 69 tablerow += "<td class=\"red\">no</td>"; 70 else: 71 tablerow += "<td class=\"green\">yes</td>"; 72 73 # Delete button 74 #outfile.write("<td>Delete</td>") 75 76 77 # End of row 78 tablerow += "</tr>"; 79 tablebuffer.append([unixtime, tablerow]); 80 81 # dump table: 82 tablebuffer.sort(reverse=True); 83 84 for row in tablebuffer: 85 outfile.write(row[1]); 86 87 outfile.write("</table></center>\n"); 88 89 90 91 92##################################################### 93#### Start of main execution 94##################################################### 95 96 97## Early checks: 98 99if len(sys.argv) < 3: 100 print("Usage: $> branches.py TYPE OUTPUT"); 101 print(" TYPE ... Either 'all' or 'active'"); 102 print(" OUTFILE ... The output file where the HTML code will be written to"); 103 print("Aborting...") 104 sys.exit(1) 105 106if (sys.argv[1] != "all" and sys.argv[1] != "active"): 107 print("Unknown type: " + sys.argv[1]); 108 print("Usage: $> branches.py TYPE OUTPUT"); 109 print(" TYPE ... Either 'all' or 'active'"); 110 print(" OUTFILE ... The output file where the HTML code will be written to"); 111 print("Aborting...") 112 sys.exit(1) 113 114 115###### Main execution body ########## 116 117 118outfile = open(sys.argv[2], "w") 119 120# Static HTML header: 121outfile.write(""" 122<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 123<html> 124<head><title>PETSc Branch Summary</title> 125<style type="text/css"> 126div.main { 127 max-width: 1300px; 128 background: white; 129 margin-left: auto; 130 margin-right: auto; 131 padding: 20px; 132 padding-top: 0; 133 border: 5px solid #CCCCCC; 134 border-radius: 10px; 135 background: #FBFBFB; 136} 137table { 138 /*border: 1px solid black; 139 border-radius: 10px;*/ 140 padding: 3px; 141 margin-top: 0; 142} 143td a:link, td a:visited, td a:focus, td a:active { 144 font-weight: bold; 145 text-decoration: underline; 146 color: black; 147} 148td a:hover { 149 font-weight: bold; 150 text-decoration: underline; 151 color: black; 152} 153th { 154 padding: 10px; 155 padding-top: 5px; 156 padding-bottom: 5px; 157 font-size: 1.1em; 158 font-weight: bold; 159 text-align: center; 160} 161td.desc { 162 max-width: 650px; 163 padding: 2px; 164 font-size: 0.9em; 165} 166td.green { 167 text-align: center; 168 vertical-align: middle; 169 padding: 2px; 170 background: #01DF01; 171 min-width: 50px; 172} 173td.yellow { 174 text-align: center; 175 vertical-align: middle; 176 padding: 2px; 177 background: #F4FA58; 178 min-width: 50px; 179} 180td.red { 181 text-align: center; 182 vertical-align: middle; 183 padding: 2px; 184 background: #FE2E2E; 185 min-width: 50px; 186} 187</style> 188</head> 189<body><div class="main"> """) 190 191 192outfile.write("<center><span style=\"font-size:1.3em; font-weight: bold;\">") 193if (sys.argv[1] == "all"): 194 outfile.write("Summary of ALL PETSc Branches") 195else: 196 outfile.write("Summary of ACTIVE PETSc Branches") 197outfile.write("</span><br />Last update: " + time.strftime("%c") + "</center>\n") 198 199 200# Build quicklink bar: 201outfile.write("<br /><center>") 202for branchprefix in branchnames: 203 outfile.write("<a href=\"#" + branchprefix + "\">[" + branchprefix + "]</a> ") 204outfile.write("<a href=\"#other\">[other]</a>") 205outfile.write("</center><br />") 206 207 208# Get all remote branches 209process = subprocess.Popen(["git", "branch", "-r"], stdout=subprocess.PIPE) 210allbranches, err = process.communicate() 211 212# Print branches for each of the branchnames defined above: 213for branchprefix in branchnames: 214 print("Working on " + branchprefix) 215 branchprefix2 = "origin/" + branchprefix 216 217 userbranches = [] 218 for line in allbranches.splitlines(): 219 if branchprefix2 in line: 220 userbranches.append(line.strip()) 221 222 printtable(outfile, userbranches, branchprefix) 223 224# Print all other branches by testing against the 'standard' branchnames: 225print("Working on remaining branches") 226otherbranches = [] 227for line in allbranches.splitlines(): 228 229 if "origin" not in line or "origin/HEAD" in line: 230 continue 231 232 is_other_branch = 1 233 for branchprefix in branchnames: 234 branchprefix2 = "origin/" + branchprefix 235 236 if branchprefix2 in line: 237 is_other_branch = 0 238 239 if (is_other_branch == 1): 240 otherbranches.append(line.strip()) 241 242printtable(outfile, otherbranches, "other") 243 244 245# write footer: 246outfile.write("</div></body></html>") 247outfile.close() 248 249 250