1*478d9372SMasahiro Yamada#!/usr/bin/env python2 2*478d9372SMasahiro Yamada# 3*478d9372SMasahiro Yamada# Author: Masahiro Yamada <yamada.m@jp.panasonic.com> 4*478d9372SMasahiro Yamada# 5*478d9372SMasahiro Yamada# SPDX-License-Identifier: GPL-2.0+ 6*478d9372SMasahiro Yamada# 7*478d9372SMasahiro Yamada 8*478d9372SMasahiro Yamada""" 9*478d9372SMasahiro YamadaFill the "Commit" and "Removed" fields of doc/README.scrapyard 10*478d9372SMasahiro Yamada 11*478d9372SMasahiro YamadaThe file doc/README.scrapyard is used to keep track of removed boards. 12*478d9372SMasahiro Yamada 13*478d9372SMasahiro YamadaWhen we remove support for boards, we are supposed to add entries to 14*478d9372SMasahiro Yamadadoc/README.scrapyard leaving "Commit" and "Removed" fields blank. 15*478d9372SMasahiro Yamada 16*478d9372SMasahiro YamadaThe "Commit" field is the commit hash in which the board was removed 17*478d9372SMasahiro Yamadaand the "Removed" is the date at which the board was removed. Those 18*478d9372SMasahiro Yamadatwo are known only after the board removal patch was applied, thus they 19*478d9372SMasahiro Yamadaneed to be filled in later. 20*478d9372SMasahiro Yamada 21*478d9372SMasahiro YamadaThis effectively means that the person who removes other boards is 22*478d9372SMasahiro Yamadasupposed to fill in the blank fields before adding new entries to 23*478d9372SMasahiro Yamadadoc/README.scrapyard. 24*478d9372SMasahiro Yamada 25*478d9372SMasahiro YamadaThat is a really tedious task that should be automated. 26*478d9372SMasahiro YamadaThis script fills the blank fields of doc/README.scrapyard for you! 27*478d9372SMasahiro Yamada 28*478d9372SMasahiro YamadaUsage: 29*478d9372SMasahiro Yamada 30*478d9372SMasahiro YamadaThe "Commit" and "Removed" fields must be "-". The other fields should 31*478d9372SMasahiro Yamadahave already been filled in by a former commit. 32*478d9372SMasahiro Yamada 33*478d9372SMasahiro YamadaRun 34*478d9372SMasahiro Yamada scripts/fill_scrapyard.py 35*478d9372SMasahiro Yamada""" 36*478d9372SMasahiro Yamada 37*478d9372SMasahiro Yamadaimport os 38*478d9372SMasahiro Yamadaimport subprocess 39*478d9372SMasahiro Yamadaimport sys 40*478d9372SMasahiro Yamadaimport tempfile 41*478d9372SMasahiro Yamada 42*478d9372SMasahiro YamadaDOC='doc/README.scrapyard' 43*478d9372SMasahiro Yamada 44*478d9372SMasahiro Yamadadef get_last_modify_commit(file, line_num): 45*478d9372SMasahiro Yamada """Get the commit that last modified the given line. 46*478d9372SMasahiro Yamada 47*478d9372SMasahiro Yamada This function runs "git blame" against the given line of the given 48*478d9372SMasahiro Yamada file and returns the commit hash that last modified it. 49*478d9372SMasahiro Yamada 50*478d9372SMasahiro Yamada Arguments: 51*478d9372SMasahiro Yamada file: the file to be git-blame'd. 52*478d9372SMasahiro Yamada line_num: the line number to be git-blame'd. This line number 53*478d9372SMasahiro Yamada starts from 1, not 0. 54*478d9372SMasahiro Yamada 55*478d9372SMasahiro Yamada Returns: 56*478d9372SMasahiro Yamada Commit hash that last modified the line. The number of digits is 57*478d9372SMasahiro Yamada long enough to form a unique commit. 58*478d9372SMasahiro Yamada """ 59*478d9372SMasahiro Yamada result = subprocess.check_output(['git', 'blame', '-L', 60*478d9372SMasahiro Yamada '%d,%d' % (line_num, line_num), file]) 61*478d9372SMasahiro Yamada commit = result.split()[0] 62*478d9372SMasahiro Yamada 63*478d9372SMasahiro Yamada if commit[0] == '^': 64*478d9372SMasahiro Yamada sys.exit('%s: line %d: ' % (file, line_num) + 65*478d9372SMasahiro Yamada 'this line was modified before the beginning of git history') 66*478d9372SMasahiro Yamada 67*478d9372SMasahiro Yamada if commit == '0' * len(commit): 68*478d9372SMasahiro Yamada sys.exit('%s: line %d: locally modified\n' % (file, line_num) + 69*478d9372SMasahiro Yamada 'Please run this script in a clean repository.') 70*478d9372SMasahiro Yamada 71*478d9372SMasahiro Yamada return commit 72*478d9372SMasahiro Yamada 73*478d9372SMasahiro Yamadadef get_committer_date(commit): 74*478d9372SMasahiro Yamada """Get the committer date of the given commit. 75*478d9372SMasahiro Yamada 76*478d9372SMasahiro Yamada This function returns the date when the given commit was applied. 77*478d9372SMasahiro Yamada 78*478d9372SMasahiro Yamada Arguments: 79*478d9372SMasahiro Yamada commit: commit-ish object. 80*478d9372SMasahiro Yamada 81*478d9372SMasahiro Yamada Returns: 82*478d9372SMasahiro Yamada The committer date of the given commit in the form YY-MM-DD. 83*478d9372SMasahiro Yamada """ 84*478d9372SMasahiro Yamada committer_date = subprocess.check_output(['git', 'show', '-s', 85*478d9372SMasahiro Yamada '--format=%ci', commit]) 86*478d9372SMasahiro Yamada return committer_date.split()[0] 87*478d9372SMasahiro Yamada 88*478d9372SMasahiro Yamadadef move_to_topdir(): 89*478d9372SMasahiro Yamada """Change directory to the top of the git repository. 90*478d9372SMasahiro Yamada 91*478d9372SMasahiro Yamada Or, exit with an error message if called out of a git repository. 92*478d9372SMasahiro Yamada """ 93*478d9372SMasahiro Yamada try: 94*478d9372SMasahiro Yamada toplevel = subprocess.check_output(['git', 'rev-parse', 95*478d9372SMasahiro Yamada '--show-toplevel']) 96*478d9372SMasahiro Yamada except subprocess.CalledProcessError: 97*478d9372SMasahiro Yamada sys.exit('Please run in a git repository.') 98*478d9372SMasahiro Yamada 99*478d9372SMasahiro Yamada # strip '\n' 100*478d9372SMasahiro Yamada toplevel = toplevel.rstrip() 101*478d9372SMasahiro Yamada 102*478d9372SMasahiro Yamada # Change the current working directory to the toplevel of the respository 103*478d9372SMasahiro Yamada # for our easier life. 104*478d9372SMasahiro Yamada os.chdir(toplevel) 105*478d9372SMasahiro Yamada 106*478d9372SMasahiro Yamadaclass TmpFile: 107*478d9372SMasahiro Yamada 108*478d9372SMasahiro Yamada """Useful class to handle a temporary file. 109*478d9372SMasahiro Yamada 110*478d9372SMasahiro Yamada tempfile.mkstemp() is often used to create a unique temporary file, 111*478d9372SMasahiro Yamada but what is inconvenient is that the caller is responsible for 112*478d9372SMasahiro Yamada deleting the file when done with it. 113*478d9372SMasahiro Yamada 114*478d9372SMasahiro Yamada Even when the caller errors out on the way, the temporary file must 115*478d9372SMasahiro Yamada be deleted somehow. The idea here is that we delete the file in 116*478d9372SMasahiro Yamada the destructor of this class because the destructor is always 117*478d9372SMasahiro Yamada invoked when the instance of the class is freed. 118*478d9372SMasahiro Yamada """ 119*478d9372SMasahiro Yamada 120*478d9372SMasahiro Yamada def __init__(self): 121*478d9372SMasahiro Yamada """Constructor - create a temporary file""" 122*478d9372SMasahiro Yamada fd, self.filename = tempfile.mkstemp() 123*478d9372SMasahiro Yamada self.file = os.fdopen(fd, 'w') 124*478d9372SMasahiro Yamada 125*478d9372SMasahiro Yamada def __del__(self): 126*478d9372SMasahiro Yamada """Destructor - delete the temporary file""" 127*478d9372SMasahiro Yamada try: 128*478d9372SMasahiro Yamada os.remove(self.filename) 129*478d9372SMasahiro Yamada except: 130*478d9372SMasahiro Yamada pass 131*478d9372SMasahiro Yamada 132*478d9372SMasahiro Yamadadef main(): 133*478d9372SMasahiro Yamada move_to_topdir() 134*478d9372SMasahiro Yamada 135*478d9372SMasahiro Yamada line_num = 1 136*478d9372SMasahiro Yamada 137*478d9372SMasahiro Yamada tmpfile = TmpFile() 138*478d9372SMasahiro Yamada for line in open(DOC): 139*478d9372SMasahiro Yamada tmp = line.split(None, 5) 140*478d9372SMasahiro Yamada modified = False 141*478d9372SMasahiro Yamada 142*478d9372SMasahiro Yamada if len(tmp) >= 5: 143*478d9372SMasahiro Yamada # fill "Commit" field 144*478d9372SMasahiro Yamada if tmp[3] == '-': 145*478d9372SMasahiro Yamada tmp[3] = get_last_modify_commit(DOC, line_num) 146*478d9372SMasahiro Yamada modified = True 147*478d9372SMasahiro Yamada # fill "Removed" field 148*478d9372SMasahiro Yamada if tmp[4] == '-': 149*478d9372SMasahiro Yamada tmp[4] = get_committer_date(tmp[3]) 150*478d9372SMasahiro Yamada if modified: 151*478d9372SMasahiro Yamada line = tmp[0].ljust(17) 152*478d9372SMasahiro Yamada line += tmp[1].ljust(12) 153*478d9372SMasahiro Yamada line += tmp[2].ljust(15) 154*478d9372SMasahiro Yamada line += tmp[3].ljust(12) 155*478d9372SMasahiro Yamada line += tmp[4].ljust(12) 156*478d9372SMasahiro Yamada if len(tmp) >= 6: 157*478d9372SMasahiro Yamada line += tmp[5] 158*478d9372SMasahiro Yamada line = line.rstrip() + '\n' 159*478d9372SMasahiro Yamada 160*478d9372SMasahiro Yamada tmpfile.file.write(line) 161*478d9372SMasahiro Yamada line_num += 1 162*478d9372SMasahiro Yamada 163*478d9372SMasahiro Yamada os.rename(tmpfile.filename, DOC) 164*478d9372SMasahiro Yamada 165*478d9372SMasahiro Yamadaif __name__ == '__main__': 166*478d9372SMasahiro Yamada main() 167