Home | History | Annotate | Download | only in devtools
      1 """Updates the license text in source file.
      2 """
      3 
      4 # An existing license is found if the file starts with the string below,
      5 # and ends with the first blank line.
      6 LICENSE_BEGIN = "// Copyright "
      7 
      8 BRIEF_LICENSE = LICENSE_BEGIN + """2007-2010 Baptiste Lepilleur
      9 // Distributed under MIT license, or public domain if desired and
     10 // recognized in your jurisdiction.
     11 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
     12 
     13 """.replace('\r\n','\n')
     14 
     15 def update_license( path, dry_run, show_diff ):
     16     """Update the license statement in the specified file.
     17     Parameters:
     18       path: path of the C++ source file to update.
     19       dry_run: if True, just print the path of the file that would be updated,
     20                but don't change it.
     21       show_diff: if True, print the path of the file that would be modified,
     22                  as well as the change made to the file. 
     23     """
     24     with open( path, 'rt' ) as fin:
     25         original_text = fin.read().replace('\r\n','\n')
     26         newline = fin.newlines and fin.newlines[0] or '\n'
     27     if not original_text.startswith( LICENSE_BEGIN ):
     28         # No existing license found => prepend it
     29         new_text = BRIEF_LICENSE + original_text
     30     else:
     31         license_end_index = original_text.index( '\n\n' ) # search first blank line
     32         new_text = BRIEF_LICENSE + original_text[license_end_index+2:]
     33     if original_text != new_text:
     34         if not dry_run:
     35             with open( path, 'wb' ) as fout:
     36                 fout.write( new_text.replace('\n', newline ) )
     37         print 'Updated', path
     38         if show_diff:
     39             import difflib
     40             print '\n'.join( difflib.unified_diff( original_text.split('\n'),
     41                                                    new_text.split('\n') ) )
     42         return True
     43     return False
     44 
     45 def update_license_in_source_directories( source_dirs, dry_run, show_diff ):
     46     """Updates license text in C++ source files found in directory source_dirs.
     47     Parameters:
     48       source_dirs: list of directory to scan for C++ sources. Directories are
     49                    scanned recursively.
     50       dry_run: if True, just print the path of the file that would be updated,
     51                but don't change it.
     52       show_diff: if True, print the path of the file that would be modified,
     53                  as well as the change made to the file. 
     54     """
     55     from devtools import antglob
     56     prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist'
     57     for source_dir in source_dirs:
     58         cpp_sources = antglob.glob( source_dir,
     59             includes = '''**/*.h **/*.cpp **/*.inl''',
     60             prune_dirs = prune_dirs )
     61         for source in cpp_sources:
     62             update_license( source, dry_run, show_diff )
     63 
     64 def main():
     65     usage = """%prog DIR [DIR2...]
     66 Updates license text in sources of the project in source files found
     67 in the directory specified on the command-line.
     68 
     69 Example of call:
     70 python devtools\licenseupdater.py include src -n --diff
     71 => Show change that would be made to the sources.
     72 
     73 python devtools\licenseupdater.py include src
     74 => Update license statement on all sources in directories include/ and src/.
     75 """
     76     from optparse import OptionParser
     77     parser = OptionParser(usage=usage)
     78     parser.allow_interspersed_args = False
     79     parser.add_option('-n', '--dry-run', dest="dry_run", action='store_true', default=False,
     80         help="""Only show what files are updated, do not update the files""")
     81     parser.add_option('--diff', dest="show_diff", action='store_true', default=False,
     82         help="""On update, show change made to the file.""")
     83     parser.enable_interspersed_args()
     84     options, args = parser.parse_args()
     85     update_license_in_source_directories( args, options.dry_run, options.show_diff )
     86     print 'Done'
     87 
     88 if __name__ == '__main__':
     89     import sys
     90     import os.path
     91     sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
     92     main()
     93 
     94