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