| #!/usr/bin/env python |
| # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Module that sanitizes source files with specified modifiers.""" |
| |
| |
| import commands |
| import os |
| import sys |
| |
| |
| _FILE_EXTENSIONS_TO_SANITIZE = ['cpp', 'h', 'c'] |
| |
| _SUBDIRS_TO_IGNORE = ['.git', '.svn', 'third_party'] |
| |
| |
| def SanitizeFilesWithModifiers(directory, file_modifiers, line_modifiers): |
| """Sanitizes source files with the specified file and line modifiers. |
| |
| Args: |
| directory: string - The directory which will be recursively traversed to |
| find source files to apply modifiers to. |
| file_modifiers: list - file-modification methods which should be applied to |
| the complete file content (Eg: EOFOneAndOnlyOneNewlineAdder). |
| line_modifiers: list - line-modification methods which should be applied to |
| lines in a file (Eg: TabReplacer). |
| """ |
| for item in os.listdir(directory): |
| |
| full_item_path = os.path.join(directory, item) |
| |
| if os.path.isfile(full_item_path): # Item is a file. |
| |
| # Only sanitize files with extensions we care about. |
| if (len(full_item_path.split('.')) > 1 and |
| full_item_path.split('.')[-1] in _FILE_EXTENSIONS_TO_SANITIZE): |
| f = file(full_item_path) |
| try: |
| lines = f.readlines() |
| finally: |
| f.close() |
| |
| new_lines = [] # Collect changed lines here. |
| line_number = 0 # Keeps track of line numbers in the source file. |
| write_to_file = False # File is written to only if this flag is set. |
| |
| # Run the line modifiers for each line in this file. |
| for line in lines: |
| original_line = line |
| line_number += 1 |
| |
| for modifier in line_modifiers: |
| line = modifier(line, full_item_path, line_number) |
| if original_line != line: |
| write_to_file = True |
| new_lines.append(line) |
| |
| # Run the file modifiers. |
| old_content = ''.join(lines) |
| new_content = ''.join(new_lines) |
| for modifier in file_modifiers: |
| new_content = modifier(new_content, full_item_path) |
| if new_content != old_content: |
| write_to_file = True |
| |
| # Write modifications to the file. |
| if write_to_file: |
| f = file(full_item_path, 'w') |
| try: |
| f.write(new_content) |
| finally: |
| f.close() |
| print 'Made changes to %s' % full_item_path |
| |
| elif item not in _SUBDIRS_TO_IGNORE: |
| # Item is a directory recursively call the method. |
| SanitizeFilesWithModifiers(full_item_path, file_modifiers, line_modifiers) |
| |
| |
| ############## Line Modification methods ############## |
| |
| |
| def TrailingWhitespaceRemover(line, file_path, line_number): |
| """Strips out trailing whitespaces from the specified line.""" |
| stripped_line = line.rstrip() + '\n' |
| if line != stripped_line: |
| print 'Removing trailing whitespace in %s:%s' % (file_path, line_number) |
| return stripped_line |
| |
| |
| def CrlfReplacer(line, file_path, line_number): |
| """Replaces CRLF with LF.""" |
| if '\r\n' in line: |
| print 'Replacing CRLF with LF in %s:%s' % (file_path, line_number) |
| return line.replace('\r\n', '\n') |
| |
| |
| def TabReplacer(line, file_path, line_number): |
| """Replaces Tabs with 4 whitespaces.""" |
| if '\t' in line: |
| print 'Replacing Tab with whitespace in %s:%s' % (file_path, line_number) |
| return line.replace('\t', ' ') |
| |
| |
| ############## File Modification methods ############## |
| |
| |
| def CopywriteChecker(file_content, unused_file_path): |
| """Ensures that the copywrite information is correct.""" |
| # TODO(rmistry): Figure out the legal implications of changing old copyright |
| # headers. |
| return file_content |
| |
| |
| def EOFOneAndOnlyOneNewlineAdder(file_content, file_path): |
| """Adds one and only one LF at the end of the file.""" |
| if file_content and (file_content[-1] != '\n' or file_content[-2:-1] == '\n'): |
| file_content = file_content.rstrip() |
| file_content += '\n' |
| print 'Added exactly one newline to %s' % file_path |
| return file_content |
| |
| |
| def SvnEOLChecker(file_content, file_path): |
| """Sets svn:eol-style property to LF.""" |
| output = commands.getoutput( |
| 'svn propget svn:eol-style %s' % file_path) |
| if output != 'LF': |
| print 'Setting svn:eol-style property to LF in %s' % file_path |
| os.system('svn ps svn:eol-style LF %s' % file_path) |
| return file_content |
| |
| |
| ####################################################### |
| |
| |
| if '__main__' == __name__: |
| sys.exit(SanitizeFilesWithModifiers( |
| os.getcwd(), |
| file_modifiers=[ |
| CopywriteChecker, |
| EOFOneAndOnlyOneNewlineAdder, |
| SvnEOLChecker, |
| ], |
| line_modifiers=[ |
| CrlfReplacer, |
| TabReplacer, |
| TrailingWhitespaceRemover, |
| ], |
| )) |