Updating trunk VERSION from 903.0 to 904.0
[chromium-blink-merge.git] / chrome / tools / inconsistent-eol.py
blob4ab35967f265f9d5e2459546b92289b6a6b839db
1 #!/usr/bin/python
2 # Copyright (c) 2006-2008 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.
6 """Find and fix files with inconsistent line endings.
8 This script requires 'dos2unix.exe' and 'unix2dos.exe' from Cygwin; they
9 must be in the user's PATH.
11 Arg: Either one or more files to examine, or (with --file-list) one or more
12 files that themselves contain lists of files. The argument(s) passed to
13 this script, as well as the paths in the file if any, may be relative or
14 absolute Windows-style paths (with either type of slash). The list might
15 be generated with 'find -type f' or extracted from a gcl change listing,
16 for example.
17 """
19 import errno
20 import logging
21 import optparse
22 import subprocess
23 import sys
26 # Whether to produce excessive debugging output for each file in the list.
27 DEBUGGING = False
30 class Error(Exception):
31 """Local exception class."""
32 pass
35 def CountChars(text, str):
36 """Count the number of instances of the given string in the text."""
37 split = text.split(str)
38 logging.debug(len(split) - 1)
39 return len(split) - 1
41 def PrevailingEOLName(crlf, cr, lf):
42 """Describe the most common line ending.
44 Args:
45 crlf: How many CRLF (\r\n) sequences are in the file.
46 cr: How many CR (\r) characters are in the file, excluding CRLF sequences.
47 lf: How many LF (\n) characters are in the file, excluding CRLF sequences.
49 Returns:
50 A string describing the most common of the three line endings.
51 """
52 most = max(crlf, cr, lf)
53 if most == cr:
54 return 'cr'
55 if most == crlf:
56 return 'crlf'
57 return 'lf'
59 def FixEndings(file, crlf, cr, lf):
60 """Change the file's line endings to CRLF or LF, whichever is more common."""
61 most = max(crlf, cr, lf)
62 if most == crlf:
63 result = subprocess.call('unix2dos.exe %s' % file, shell=True)
64 if result:
65 raise Error('Error running unix2dos.exe %s' % file)
66 else:
67 result = subprocess.call('dos2unix.exe %s' % file, shell=True)
68 if result:
69 raise Error('Error running dos2unix.exe %s' % file)
72 def ProcessFiles(filelist):
73 """Fix line endings in each file in the filelist list."""
74 for filename in filelist:
75 filename = filename.strip()
76 logging.debug(filename)
77 try:
78 # Open in binary mode to preserve existing line endings.
79 text = open(filename, 'rb').read()
80 except IOError, e:
81 if e.errno != errno.ENOENT:
82 raise
83 logging.warning('File %s not found.' % filename)
84 continue
86 crlf = CountChars(text, '\r\n')
87 cr = CountChars(text, '\r') - crlf
88 lf = CountChars(text, '\n') - crlf
90 if options.force_lf:
91 if crlf > 0 or cr > 0:
92 print '%s: forcing to LF' % filename
93 # Fudge the counts to force switching to LF.
94 FixEndings(filename, 0, 0, 1)
95 else:
96 if ((crlf > 0 and cr > 0) or
97 (crlf > 0 and lf > 0) or
98 ( lf > 0 and cr > 0)):
99 print '%s: mostly %s' % (filename, PrevailingEOLName(crlf, cr, lf))
100 FixEndings(filename, crlf, cr, lf)
102 def main(options, args):
103 """Process the files."""
104 if not args or len(args) < 1:
105 raise Error('No files given.')
107 if options.file_list:
108 for arg in args:
109 filelist = open(arg, 'r').readlines()
110 ProcessFiles(filelist)
111 else:
112 filelist = args
113 ProcessFiles(filelist)
115 if '__main__' == __name__:
116 if DEBUGGING:
117 debug_level = logging.DEBUG
118 else:
119 debug_level = logging.INFO
120 logging.basicConfig(level=debug_level,
121 format='%(asctime)s %(levelname)-7s: %(message)s',
122 datefmt='%H:%M:%S')
124 option_parser = optparse.OptionParser()
125 option_parser.add_option("", "--file-list", action="store_true",
126 default=False,
127 help="Treat the arguments as files containing "
128 "lists of files to examine, rather than as "
129 "the files to be checked.")
130 option_parser.add_option("", "--force-lf", action="store_true",
131 default=False,
132 help="Force any files with CRLF to LF instead.")
133 options, args = option_parser.parse_args()
135 sys.exit(main(options, args))