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