]>
Commit | Line | Data |
---|---|---|
478d9372 | 1 | #!/usr/bin/env python2 |
83d290c5 | 2 | # SPDX-License-Identifier: GPL-2.0+ |
478d9372 MY |
3 | # |
4 | # Author: Masahiro Yamada <[email protected]> | |
5 | # | |
478d9372 MY |
6 | |
7 | """ | |
8 | Fill the "Commit" and "Removed" fields of doc/README.scrapyard | |
9 | ||
10 | The file doc/README.scrapyard is used to keep track of removed boards. | |
11 | ||
12 | When we remove support for boards, we are supposed to add entries to | |
13 | doc/README.scrapyard leaving "Commit" and "Removed" fields blank. | |
14 | ||
15 | The "Commit" field is the commit hash in which the board was removed | |
16 | and the "Removed" is the date at which the board was removed. Those | |
17 | two are known only after the board removal patch was applied, thus they | |
18 | need to be filled in later. | |
19 | ||
20 | This effectively means that the person who removes other boards is | |
21 | supposed to fill in the blank fields before adding new entries to | |
22 | doc/README.scrapyard. | |
23 | ||
24 | That is a really tedious task that should be automated. | |
25 | This script fills the blank fields of doc/README.scrapyard for you! | |
26 | ||
27 | Usage: | |
28 | ||
29 | The "Commit" and "Removed" fields must be "-". The other fields should | |
30 | have already been filled in by a former commit. | |
31 | ||
32 | Run | |
33 | scripts/fill_scrapyard.py | |
34 | """ | |
35 | ||
36 | import os | |
37 | import subprocess | |
38 | import sys | |
39 | import tempfile | |
40 | ||
41 | DOC='doc/README.scrapyard' | |
42 | ||
43 | def 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 | ||
72 | def 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 | ||
87 | def 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 | ||
105 | class 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 | ||
131 | def 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 | ||
164 | if __name__ == '__main__': | |
165 | main() |