Merge pull request #1 from pre-commit/end_of_file_fixer
Added end of file fixer hook.
This commit is contained in:
commit
7673990291
|
@ -19,3 +19,8 @@
|
|||
description: This verifies that test files are named correctly
|
||||
entry: name-tests-test
|
||||
language: python
|
||||
- id: end-of-file-fixer
|
||||
name: Fix End of Files
|
||||
description: Ensures that a file is either empty, or ends with one newline.
|
||||
entry: end-of-file-fixer
|
||||
language: python
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pre_commit_hooks.util import entry
|
||||
|
||||
|
||||
def fix_file(file_obj):
|
||||
# Test for newline at end of file
|
||||
# Empty files will throw IOError here
|
||||
try:
|
||||
file_obj.seek(-1, os.SEEK_END)
|
||||
except IOError:
|
||||
return 0
|
||||
last_character = file_obj.read(1)
|
||||
# last_character will be '' for an empty file
|
||||
if last_character != '\n' and last_character != '':
|
||||
file_obj.write('\n')
|
||||
return 1
|
||||
|
||||
while last_character == '\n':
|
||||
# Deal with the beginning of the file
|
||||
if file_obj.tell() == 1:
|
||||
# If we've reached the beginning of the file and it is all
|
||||
# linebreaks then we can make this file empty
|
||||
file_obj.seek(0)
|
||||
file_obj.truncate()
|
||||
return 1
|
||||
|
||||
# Go back two bytes and read a character
|
||||
file_obj.seek(-2, os.SEEK_CUR)
|
||||
last_character = file_obj.read(1)
|
||||
|
||||
# Our current position is at the end of the file just before any amount of
|
||||
# newlines. If we read two characters and get two newlines back we know
|
||||
# there are extraneous newlines at the ned of the file. Then backtrack and
|
||||
# trim the end off.
|
||||
if len(file_obj.read(2)) == 2:
|
||||
file_obj.seek(-1, os.SEEK_CUR)
|
||||
file_obj.truncate()
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@entry
|
||||
def end_of_file_fixer(argv):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('filenames', nargs='*', help='Filenames to fix')
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
retv = 0
|
||||
|
||||
for filename in args.filenames:
|
||||
# Read as binary so we can read byte-by-byte
|
||||
with open(filename, 'rb+') as file_obj:
|
||||
ret_for_file = fix_file(file_obj)
|
||||
if ret_for_file:
|
||||
print('Fixing {0}'.format(filename))
|
||||
retv |= ret_for_file
|
||||
|
||||
return retv
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(end_of_file_fixer())
|
1
setup.py
1
setup.py
|
@ -16,6 +16,7 @@ setup(
|
|||
'debug-statement-hook = pre_commit_hooks.debug_statement_hook:debug_statement_hook',
|
||||
'trailing-whitespace-fixer = pre_commit_hooks.trailing_whitespace_fixer:fix_trailing_whitespace',
|
||||
'name-tests-test = pre_commit_hooks.tests_should_end_in_test:validate_files',
|
||||
'end-of-file-fixer = pre_commit_hooks.end_of_file_fixer:end_of_file_fixer',
|
||||
],
|
||||
},
|
||||
)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
import cStringIO
|
||||
import os.path
|
||||
import pytest
|
||||
|
||||
from pre_commit_hooks.end_of_file_fixer import end_of_file_fixer
|
||||
from pre_commit_hooks.end_of_file_fixer import fix_file
|
||||
|
||||
|
||||
# Input, expected return value, expected output
|
||||
TESTS = (
|
||||
('foo\n', 0, 'foo\n'),
|
||||
('', 0, ''),
|
||||
('\n\n', 1, ''),
|
||||
('\n\n\n\n', 1, ''),
|
||||
('foo', 1, 'foo\n'),
|
||||
('foo\n\n\n', 1, 'foo\n'),
|
||||
('\xe2\x98\x83', 1, '\xe2\x98\x83\n'),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('input', 'expected_retval', 'output'), TESTS)
|
||||
def test_fix_file(input, expected_retval, output):
|
||||
file_obj = cStringIO.StringIO()
|
||||
file_obj.write(input)
|
||||
ret = fix_file(file_obj)
|
||||
assert file_obj.getvalue() == output
|
||||
assert ret == expected_retval
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('input', 'expected_retval', 'output'), TESTS)
|
||||
def test_integration(input, expected_retval, output, tmpdir):
|
||||
file_path = os.path.join(tmpdir.strpath, 'file.txt')
|
||||
|
||||
with open(file_path, 'w') as file_obj:
|
||||
file_obj.write(input)
|
||||
|
||||
ret = end_of_file_fixer([file_path])
|
||||
file_output = open(file_path, 'r').read()
|
||||
|
||||
assert file_output == output
|
||||
assert ret == expected_retval
|
Loading…
Reference in New Issue