Skip to content

Commit 042c840

Browse files
authored
Merge pull request #202 from dlgallagher/file_contents_sorter_hook
File contents sorter hook
2 parents d419bef + 4c421e2 commit 042c840

File tree

6 files changed

+95
-0
lines changed

6 files changed

+95
-0
lines changed

.pre-commit-hooks.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@
105105
entry: end-of-file-fixer
106106
language: python
107107
files: \.(asciidoc|adoc|coffee|cpp|css|c|ejs|erb|groovy|h|haml|hh|hpp|hxx|html|in|j2|jade|json|js|less|markdown|md|ml|mli|pp|py|rb|rs|R|scala|scss|sh|slim|tex|tmpl|ts|txt|yaml|yml)$
108+
- id: file-contents-sorter
109+
name: File Contents Sorter
110+
description: Sort the lines in specified files (defaults to alphabetical). You must provide list of target files as input in your .pre-commit-config.yaml file.
111+
entry: file-contents-sorter
112+
language: python
113+
files: '^$'
108114
- id: fix-encoding-pragma
109115
name: Fix python encoding pragma
110116
language: python

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Add this to your `.pre-commit-config.yaml`
5151
with single quoted strings.
5252
- `end-of-file-fixer` - Makes sure files end in a newline and only a newline.
5353
- `fix-encoding-pragma` - Add `# -*- coding: utf-8 -*-` to the top of python files.
54+
- `file-contents-sorter` - Sort the lines in specified files (defaults to alphabetical). You must provide list of target files as input to it.
5455
- To remove the coding pragma pass `--remove` (useful in a python3-only codebase)
5556
- `flake8` - Run flake8 on your python files.
5657
- `forbid-new-submodules` - Prevent addition of new git submodules.

hooks.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@
105105
entry: end-of-file-fixer
106106
language: python
107107
files: \.(asciidoc|adoc|coffee|cpp|css|c|ejs|erb|groovy|h|haml|hh|hpp|hxx|html|in|j2|jade|json|js|less|markdown|md|ml|mli|pp|py|rb|rs|R|scala|scss|sh|slim|tex|tmpl|ts|txt|yaml|yml)$
108+
- id: file-contents-sorter
109+
name: File Contents Sorter
110+
description: Sort the lines in specified files (defaults to alphabetical). You must provide list of target files as input in your .pre-commit-config.yaml file.
111+
entry: file-contents-sorter
112+
language: python
113+
files: '^$'
108114
- id: fix-encoding-pragma
109115
name: Fix python encoding pragma
110116
language: python
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
A very simple pre-commit hook that, when passed one or more filenames
3+
as arguments, will sort the lines in those files.
4+
5+
An example use case for this: you have a deploy-whitelist.txt file
6+
in a repo that contains a list of filenames that is used to specify
7+
files to be included in a docker container. This file has one filename
8+
per line. Various users are adding/removing lines from this file; using
9+
this hook on that file should reduce the instances of git merge
10+
conflicts and keep the file nicely ordered.
11+
"""
12+
from __future__ import print_function
13+
14+
import argparse
15+
16+
PASS = 0
17+
FAIL = 1
18+
19+
20+
def sort_file_contents(f):
21+
before = tuple(f)
22+
after = sorted(before)
23+
24+
before_string = b''.join(before)
25+
after_string = b''.join(after)
26+
27+
if before_string == after_string:
28+
return PASS
29+
else:
30+
f.seek(0)
31+
f.write(after_string)
32+
f.truncate()
33+
return FAIL
34+
35+
36+
def main(argv=None):
37+
parser = argparse.ArgumentParser()
38+
parser.add_argument('filenames', nargs='+', help='Files to sort')
39+
args = parser.parse_args(argv)
40+
41+
retv = PASS
42+
43+
for arg in args.filenames:
44+
with open(arg, 'rb+') as file_obj:
45+
ret_for_file = sort_file_contents(file_obj)
46+
47+
if ret_for_file:
48+
print('Sorting {}'.format(arg))
49+
50+
retv |= ret_for_file
51+
52+
return retv

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
'detect-private-key = pre_commit_hooks.detect_private_key:detect_private_key',
5050
'double-quote-string-fixer = pre_commit_hooks.string_fixer:main',
5151
'end-of-file-fixer = pre_commit_hooks.end_of_file_fixer:end_of_file_fixer',
52+
'file-contents-sorter = pre_commit_hooks.file_contents_sorter:main',
5253
'fix-encoding-pragma = pre_commit_hooks.fix_encoding_pragma:main',
5354
'forbid-new-submodules = pre_commit_hooks.forbid_new_submodules:main',
5455
'name-tests-test = pre_commit_hooks.tests_should_end_in_test:validate_files',

tests/file_contents_sorter_test.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pytest
2+
3+
from pre_commit_hooks.file_contents_sorter import FAIL
4+
from pre_commit_hooks.file_contents_sorter import main
5+
from pre_commit_hooks.file_contents_sorter import PASS
6+
7+
8+
@pytest.mark.parametrize(
9+
('input_s', 'expected_retval', 'output'),
10+
(
11+
(b'', PASS, b''),
12+
(b'lonesome\n', PASS, b'lonesome\n'),
13+
(b'missing_newline', PASS, b'missing_newline'),
14+
(b'alpha\nbeta\n', PASS, b'alpha\nbeta\n'),
15+
(b'beta\nalpha\n', FAIL, b'alpha\nbeta\n'),
16+
(b'C\nc\n', PASS, b'C\nc\n'),
17+
(b'c\nC\n', FAIL, b'C\nc\n'),
18+
(b'mag ical \n tre vor\n', FAIL, b' tre vor\nmag ical \n'),
19+
(b'@\n-\n_\n#\n', FAIL, b'#\n-\n@\n_\n'),
20+
)
21+
)
22+
def test_integration(input_s, expected_retval, output, tmpdir):
23+
path = tmpdir.join('file.txt')
24+
path.write_binary(input_s)
25+
26+
output_retval = main([path.strpath])
27+
28+
assert path.read_binary() == output
29+
assert output_retval == expected_retval

0 commit comments

Comments
 (0)