blob: d6e3ec62ae136db22a1aae83fcc07bcec4ce3602 [file] [log] [blame]
rmistry@google.comb1faddf2012-08-22 18:10:37 +00001#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Module that sanitizes source files with specified modifiers."""
7
8
9import commands
10import os
11import sys
12
13
14_FILE_EXTENSIONS_TO_SANITIZE = ['cpp', 'h', 'c', 'gyp', 'gypi']
15
16_SUBDIRS_TO_IGNORE = ['.svn', 'third_party']
17
18
19def SanitizeFilesWithModifiers(directory, file_modifiers, line_modifiers):
20 """Sanitizes source files with the specified file and line modifiers.
21
22 Args:
23 directory: string - The directory which will be recursively traversed to
24 find source files to apply modifiers to.
25 file_modifiers: list - file-modification methods which should be applied to
26 the complete file content (Eg: EOFNewlineAdder).
27 line_modifiers: list - line-modification methods which should be applied to
28 lines in a file (Eg: TabReplacer).
29 """
30 for item in os.listdir(directory):
31
32 full_item_path = os.path.join(directory, item)
33
34 if os.path.isfile(full_item_path): # Item is a file.
35
36 # Only sanitize files with extensions we care about.
37 if (len(full_item_path.split('.')) > 1 and
38 full_item_path.split('.')[-1] in _FILE_EXTENSIONS_TO_SANITIZE):
39 f = file(full_item_path)
40 try:
41 lines = f.readlines()
42 finally:
43 f.close()
44
45 new_lines = [] # Collect changed lines here.
46 line_number = 0 # Keeps track of line numbers in the source file.
47 write_to_file = False # File is written to only if this flag is set.
48
49 # Run the line modifiers for each line in this file.
50 for line in lines:
51 original_line = line
52 line_number += 1
53
54 for modifier in line_modifiers:
55 line = modifier(line, full_item_path, line_number)
56 if original_line != line:
57 write_to_file = True
58 new_lines.append(line)
59
60 # Run the file modifiers.
61 old_content = ''.join(lines)
62 new_content = ''.join(new_lines)
63 for modifier in file_modifiers:
64 new_content = modifier(new_content, full_item_path)
65 if new_content != old_content:
66 write_to_file = True
67
68 # Write modifications to the file.
69 if write_to_file:
70 f = file(full_item_path, 'w')
71 try:
72 f.write(new_content)
73 finally:
74 f.close()
75 print 'Made changes to %s' % full_item_path
76
77 elif item not in _SUBDIRS_TO_IGNORE:
78 # Item is a directory recursively call the method.
79 SanitizeFilesWithModifiers(full_item_path, file_modifiers, line_modifiers)
80
81
82############## Line Modification methods ##############
83
84
85def TrailingWhitespaceRemover(line, file_path, line_number):
86 """Strips out trailing whitespaces from the specified line."""
87 stripped_line = line.rstrip() + '\n'
88 if line != stripped_line:
89 print 'Removing trailing whitespace in %s:%s' % (file_path, line_number)
90 return stripped_line
91
92
93def CrlfReplacer(line, file_path, line_number):
94 """Replaces CRLF with LF."""
95 if '\r\n' in line:
96 print 'Replacing CRLF with LF in %s:%s' % (file_path, line_number)
97 return line.replace('\r\n', '\n')
98
99
100def TabReplacer(line, file_path, line_number):
101 """Replaces Tabs with 4 whitespaces."""
102 if '\t' in line:
103 print 'Replacing Tab with whitespace in %s:%s' % (file_path, line_number)
104 return line.replace('\t', ' ')
105
106
107############## File Modification methods ##############
108
109
110def CopywriteChecker(file_content, unused_file_path):
111 """Ensures that the copywrite information is correct."""
112 # TODO(rmistry): Figure out the legal implications of changing old copyright
113 # headers.
114 return file_content
115
116
117def EOFNewlineAdder(file_content, file_path):
118 """Adds a LF at the end of the file if it does not have one."""
rmistry@google.com3de7b212012-08-23 14:46:18 +0000119 if file_content and file_content[-1] != '\n':
rmistry@google.comb1faddf2012-08-22 18:10:37 +0000120 file_content += '\n'
121 print 'Added newline to %s' % file_path
122 return file_content
123
124
125def SvnEOLChecker(file_content, file_path):
126 """Sets svn:eol-style property to LF."""
127 output = commands.getoutput(
128 'svn propget svn:eol-style %s' % file_path)
129 if output != 'LF':
130 print 'Setting svn:eol-style property to LF in %s' % file_path
131 os.system('svn ps svn:eol-style LF %s' % file_path)
132 return file_content
133
134
135#######################################################
136
137
138if '__main__' == __name__:
139 sys.exit(SanitizeFilesWithModifiers(
140 os.getcwd(),
141 file_modifiers=[
142 CopywriteChecker,
143 EOFNewlineAdder,
144 SvnEOLChecker,
145 ],
146 line_modifiers=[
147 CrlfReplacer,
148 TabReplacer,
149 TrailingWhitespaceRemover,
150 ],
151 ))
152