blob: 646bdc0824a7c46bc2bc2327d82c7f55105ba1e0 [file] [log] [blame]
#!/usr/bin/python
# Copyright (c) 2006-2008 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.
"""Find and fix files with inconsistent line endings.
This script requires 'dos2unix.exe' and 'unix2dos.exe' from Cygwin; they
must be in the user's PATH.
Arg: a file containing a list of relative or absolute file paths. The
argument passed to this script, as well as the paths in the file, may be
relative paths or absolute Windows-style paths (with either type of
slash). The list might be generated with 'find -type f' or extracted from
a gvn changebranch listing, for example.
"""
import errno
import logging
import subprocess
import sys
# Whether to produce excessive debugging output for each file in the list.
DEBUGGING = False
class Error(Exception):
"""Local exception class."""
pass
def CountChars(text, str):
"""Count the number of instances of the given string in the text."""
split = text.split(str)
logging.debug(len(split) - 1)
return len(split) - 1
def PrevailingEOLName(crlf, cr, lf):
"""Describe the most common line ending.
Args:
crlf: How many CRLF (\r\n) sequences are in the file.
cr: How many CR (\r) characters are in the file, excluding CRLF sequences.
lf: How many LF (\n) characters are in the file, excluding CRLF sequences.
Returns:
A string describing the most common of the three line endings.
"""
most = max(crlf, cr, lf)
if most == cr:
return 'cr'
if most == crlf:
return 'crlf'
return 'lf'
def FixEndings(file, crlf, cr, lf):
"""Change the file's line endings to CRLF or LF, whichever is more common."""
most = max(crlf, cr, lf)
if most == crlf:
result = subprocess.call('unix2dos.exe %s' % file, shell=True)
if result:
raise Error('Error running unix2dos.exe %s' % file)
else:
result = subprocess.call('dos2unix.exe %s' % file, shell=True)
if result:
raise Error('Error running dos2unix.exe %s' % file)
def main(argv=None):
"""Process the list of files."""
if not argv or len(argv) < 2:
raise Error('No file list given.')
for filename in open(argv[1], 'r'):
filename = filename.strip()
logging.debug(filename)
try:
# Open in binary mode to preserve existing line endings.
text = open(filename, 'rb').read()
except IOError, e:
if e.errno != errno.ENOENT:
raise
logging.warning('File %s not found.' % filename)
continue
crlf = CountChars(text, '\r\n')
cr = CountChars(text, '\r') - crlf
lf = CountChars(text, '\n') - crlf
if ((crlf > 0 and cr > 0) or
(crlf > 0 and lf > 0) or
( lf > 0 and cr > 0)):
print ('%s: mostly %s' % (filename, PrevailingEOLName(crlf, cr, lf)))
FixEndings(filename, crlf, cr, lf)
if '__main__' == __name__:
if DEBUGGING:
debug_level = logging.DEBUG
else:
debug_level = logging.INFO
logging.basicConfig(level=debug_level,
format='%(asctime)s %(levelname)-7s: %(message)s',
datefmt='%H:%M:%S')
sys.exit(main(sys.argv))