Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/env python2
      2 # SPDX-License-Identifier: GPL-2.0+
      3 #
      4 # Author: Masahiro Yamada <yamada.m (at] jp.panasonic.com>
      5 #
      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()
    166