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