blob: 71917b6e73d81e0c7c041f5d276dda5666bf2418 [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
Eric Borena1db7992021-03-25 09:04:43 -04006
rmistry@google.comb1faddf2012-08-22 18:10:37 +00007"""Module that sanitizes source files with specified modifiers."""
8
9
Eric Borena1db7992021-03-25 09:04:43 -040010from __future__ import print_function
rmistry@google.comb1faddf2012-08-22 18:10:37 +000011import commands
12import os
13import sys
14
15
Mike Klein160907f2017-02-06 12:26:51 -050016_FILE_EXTENSIONS_TO_SANITIZE = ['cpp', 'h', 'c']
rmistry@google.comb1faddf2012-08-22 18:10:37 +000017
borenet@google.com7aa80442013-09-11 13:01:27 +000018_SUBDIRS_TO_IGNORE = ['.git', '.svn', 'third_party']
rmistry@google.comb1faddf2012-08-22 18:10:37 +000019
20
21def SanitizeFilesWithModifiers(directory, file_modifiers, line_modifiers):
22 """Sanitizes source files with the specified file and line modifiers.
23
24 Args:
25 directory: string - The directory which will be recursively traversed to
26 find source files to apply modifiers to.
27 file_modifiers: list - file-modification methods which should be applied to
rmistry@google.com647ca8b2013-01-25 18:26:58 +000028 the complete file content (Eg: EOFOneAndOnlyOneNewlineAdder).
rmistry@google.comb1faddf2012-08-22 18:10:37 +000029 line_modifiers: list - line-modification methods which should be applied to
30 lines in a file (Eg: TabReplacer).
31 """
32 for item in os.listdir(directory):
33
34 full_item_path = os.path.join(directory, item)
35
36 if os.path.isfile(full_item_path): # Item is a file.
37
38 # Only sanitize files with extensions we care about.
39 if (len(full_item_path.split('.')) > 1 and
40 full_item_path.split('.')[-1] in _FILE_EXTENSIONS_TO_SANITIZE):
41 f = file(full_item_path)
42 try:
43 lines = f.readlines()
44 finally:
45 f.close()
46
47 new_lines = [] # Collect changed lines here.
48 line_number = 0 # Keeps track of line numbers in the source file.
49 write_to_file = False # File is written to only if this flag is set.
50
51 # Run the line modifiers for each line in this file.
52 for line in lines:
53 original_line = line
54 line_number += 1
55
56 for modifier in line_modifiers:
57 line = modifier(line, full_item_path, line_number)
58 if original_line != line:
59 write_to_file = True
60 new_lines.append(line)
61
62 # Run the file modifiers.
63 old_content = ''.join(lines)
64 new_content = ''.join(new_lines)
65 for modifier in file_modifiers:
66 new_content = modifier(new_content, full_item_path)
67 if new_content != old_content:
68 write_to_file = True
69
70 # Write modifications to the file.
71 if write_to_file:
72 f = file(full_item_path, 'w')
73 try:
74 f.write(new_content)
75 finally:
76 f.close()
Eric Borena1db7992021-03-25 09:04:43 -040077 print('Made changes to %s' % full_item_path)
rmistry@google.comb1faddf2012-08-22 18:10:37 +000078
79 elif item not in _SUBDIRS_TO_IGNORE:
80 # Item is a directory recursively call the method.
81 SanitizeFilesWithModifiers(full_item_path, file_modifiers, line_modifiers)
82
83
84############## Line Modification methods ##############
85
86
87def TrailingWhitespaceRemover(line, file_path, line_number):
88 """Strips out trailing whitespaces from the specified line."""
89 stripped_line = line.rstrip() + '\n'
90 if line != stripped_line:
Eric Borena1db7992021-03-25 09:04:43 -040091 print('Removing trailing whitespace in %s:%s' % (file_path, line_number))
rmistry@google.comb1faddf2012-08-22 18:10:37 +000092 return stripped_line
93
94
95def CrlfReplacer(line, file_path, line_number):
96 """Replaces CRLF with LF."""
97 if '\r\n' in line:
Eric Borena1db7992021-03-25 09:04:43 -040098 print('Replacing CRLF with LF in %s:%s' % (file_path, line_number))
rmistry@google.comb1faddf2012-08-22 18:10:37 +000099 return line.replace('\r\n', '\n')
100
101
102def TabReplacer(line, file_path, line_number):
103 """Replaces Tabs with 4 whitespaces."""
104 if '\t' in line:
Eric Borena1db7992021-03-25 09:04:43 -0400105 print('Replacing Tab with whitespace in %s:%s' % (file_path, line_number))
rmistry@google.comb1faddf2012-08-22 18:10:37 +0000106 return line.replace('\t', ' ')
107
108
109############## File Modification methods ##############
110
111
112def CopywriteChecker(file_content, unused_file_path):
113 """Ensures that the copywrite information is correct."""
114 # TODO(rmistry): Figure out the legal implications of changing old copyright
115 # headers.
116 return file_content
117
118
rmistry@google.com647ca8b2013-01-25 18:26:58 +0000119def EOFOneAndOnlyOneNewlineAdder(file_content, file_path):
120 """Adds one and only one LF at the end of the file."""
121 if file_content and (file_content[-1] != '\n' or file_content[-2:-1] == '\n'):
122 file_content = file_content.rstrip()
rmistry@google.comb1faddf2012-08-22 18:10:37 +0000123 file_content += '\n'
Eric Borena1db7992021-03-25 09:04:43 -0400124 print('Added exactly one newline to %s' % file_path)
rmistry@google.comb1faddf2012-08-22 18:10:37 +0000125 return file_content
126
127
128def SvnEOLChecker(file_content, file_path):
129 """Sets svn:eol-style property to LF."""
130 output = commands.getoutput(
131 'svn propget svn:eol-style %s' % file_path)
132 if output != 'LF':
Eric Borena1db7992021-03-25 09:04:43 -0400133 print('Setting svn:eol-style property to LF in %s' % file_path)
rmistry@google.comb1faddf2012-08-22 18:10:37 +0000134 os.system('svn ps svn:eol-style LF %s' % file_path)
135 return file_content
136
137
138#######################################################
139
140
141if '__main__' == __name__:
142 sys.exit(SanitizeFilesWithModifiers(
143 os.getcwd(),
144 file_modifiers=[
145 CopywriteChecker,
rmistry@google.com647ca8b2013-01-25 18:26:58 +0000146 EOFOneAndOnlyOneNewlineAdder,
rmistry@google.comb1faddf2012-08-22 18:10:37 +0000147 SvnEOLChecker,
148 ],
149 line_modifiers=[
150 CrlfReplacer,
151 TabReplacer,
152 TrailingWhitespaceRemover,
153 ],
154 ))