Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e8a209f

Browse files
authored
Merge pull request #605 from pre-commit/non_ascii_filenames
Handle non-ascii filenames from git
2 parents 8b14c6c + 0815108 commit e8a209f

4 files changed

Lines changed: 85 additions & 29 deletions

File tree

pre_commit/commands/run.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,6 @@ def _hook_msg_start(hook, verbose):
3636
)
3737

3838

39-
def get_changed_files(new, old):
40-
return cmd_output(
41-
'git', 'diff', '--no-ext-diff', '--name-only',
42-
'{}...{}'.format(old, new),
43-
)[1].splitlines()
44-
45-
4639
def filter_filenames_by_types(filenames, types, exclude_types):
4740
types, exclude_types = frozenset(types), frozenset(exclude_types)
4841
ret = []
@@ -56,7 +49,7 @@ def filter_filenames_by_types(filenames, types, exclude_types):
5649
def get_filenames(args, include_expr, exclude_expr):
5750
if args.origin and args.source:
5851
getter = git.get_files_matching(
59-
lambda: get_changed_files(args.origin, args.source),
52+
lambda: git.get_changed_files(args.origin, args.source),
6053
)
6154
elif args.hook_stage == 'commit-msg':
6255
def getter(*_):

pre_commit/git.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
logger = logging.getLogger('pre_commit')
1616

1717

18+
def zsplit(s):
19+
s = s.strip('\0')
20+
if s:
21+
return s.split('\0')
22+
else:
23+
return []
24+
25+
1826
def get_root():
1927
try:
2028
return cmd_output('git', 'rev-parse', '--show-toplevel')[1].strip()
@@ -67,25 +75,32 @@ def get_conflicted_files():
6775
# If they resolved the merge conflict by choosing a mesh of both sides
6876
# this will also include the conflicted files
6977
tree_hash = cmd_output('git', 'write-tree')[1].strip()
70-
merge_diff_filenames = cmd_output(
71-
'git', 'diff', '--no-ext-diff',
72-
'-m', tree_hash, 'HEAD', 'MERGE_HEAD', '--name-only',
73-
)[1].splitlines()
78+
merge_diff_filenames = zsplit(cmd_output(
79+
'git', 'diff', '--name-only', '--no-ext-diff', '-z',
80+
'-m', tree_hash, 'HEAD', 'MERGE_HEAD',
81+
)[1])
7482
return set(merge_conflict_filenames) | set(merge_diff_filenames)
7583

7684

7785
@memoize_by_cwd
7886
def get_staged_files():
79-
return cmd_output(
80-
'git', 'diff', '--staged', '--name-only', '--no-ext-diff',
87+
return zsplit(cmd_output(
88+
'git', 'diff', '--staged', '--name-only', '--no-ext-diff', '-z',
8189
# Everything except for D
8290
'--diff-filter=ACMRTUXB',
83-
)[1].splitlines()
91+
)[1])
8492

8593

8694
@memoize_by_cwd
8795
def get_all_files():
88-
return cmd_output('git', 'ls-files')[1].splitlines()
96+
return zsplit(cmd_output('git', 'ls-files', '-z')[1])
97+
98+
99+
def get_changed_files(new, old):
100+
return zsplit(cmd_output(
101+
'git', 'diff', '--name-only', '--no-ext-diff', '-z',
102+
'{}...{}'.format(old, new),
103+
)[1])
89104

90105

91106
def get_files_matching(all_file_list_strategy):

tests/commands/run_test.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from pre_commit.commands.run import _compute_cols
1616
from pre_commit.commands.run import _get_skips
1717
from pre_commit.commands.run import _has_unmerged_paths
18-
from pre_commit.commands.run import get_changed_files
1918
from pre_commit.commands.run import run
2019
from pre_commit.runner import Runner
2120
from pre_commit.util import cmd_output
@@ -501,18 +500,6 @@ def test_hook_install_failure(mock_out_store_directory, tempdir_factory):
501500
assert '☃'.encode('UTF-8') + '²'.encode('latin1') in stdout
502501

503502

504-
def test_get_changed_files():
505-
files = get_changed_files(
506-
'78c682a1d13ba20e7cb735313b9314a74365cd3a',
507-
'3387edbb1288a580b37fe25225aa0b856b18ad1a',
508-
)
509-
assert files == ['CHANGELOG.md', 'setup.py']
510-
511-
# files changed in source but not in origin should not be returned
512-
files = get_changed_files('HEAD~10', 'HEAD')
513-
assert files == []
514-
515-
516503
def test_lots_of_files(mock_out_store_directory, tempdir_factory):
517504
# windows xargs seems to have a bug, here's a regression test for
518505
# our workaround

tests/git_test.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
from __future__ import absolute_import
23
from __future__ import unicode_literals
34

@@ -162,3 +163,63 @@ def test_get_conflicted_files_unstaged_files(in_merge_conflict):
162163
def test_parse_merge_msg_for_conflicts(input, expected_output):
163164
ret = git.parse_merge_msg_for_conflicts(input)
164165
assert ret == expected_output
166+
167+
168+
def test_get_changed_files():
169+
files = git.get_changed_files(
170+
'78c682a1d13ba20e7cb735313b9314a74365cd3a',
171+
'3387edbb1288a580b37fe25225aa0b856b18ad1a',
172+
)
173+
assert files == ['CHANGELOG.md', 'setup.py']
174+
175+
# files changed in source but not in origin should not be returned
176+
files = git.get_changed_files('HEAD~10', 'HEAD')
177+
assert files == []
178+
179+
180+
@pytest.mark.parametrize(
181+
('s', 'expected'),
182+
(
183+
('foo\0bar\0', ['foo', 'bar']),
184+
('foo\0', ['foo']),
185+
('', []),
186+
('foo', ['foo']),
187+
),
188+
)
189+
def test_zsplit(s, expected):
190+
assert git.zsplit(s) == expected
191+
192+
193+
@pytest.fixture
194+
def non_ascii_repo(tmpdir):
195+
repo = tmpdir.join('repo').ensure_dir()
196+
with repo.as_cwd():
197+
cmd_output('git', 'init', '.')
198+
cmd_output('git', 'commit', '--allow-empty', '-m', 'initial commit')
199+
repo.join('интервью').ensure()
200+
cmd_output('git', 'add', '.')
201+
cmd_output('git', 'commit', '--allow-empty', '-m', 'initial commit')
202+
yield repo
203+
204+
205+
def test_all_files_non_ascii(non_ascii_repo):
206+
ret = git.get_all_files()
207+
assert ret == ['интервью']
208+
209+
210+
def test_staged_files_non_ascii(non_ascii_repo):
211+
non_ascii_repo.join('интервью').write('hi')
212+
cmd_output('git', 'add', '.')
213+
assert git.get_staged_files() == ['интервью']
214+
215+
216+
def test_changed_files_non_ascii(non_ascii_repo):
217+
ret = git.get_changed_files('HEAD', 'HEAD^')
218+
assert ret == ['интервью']
219+
220+
221+
def test_get_conflicted_files_non_ascii(in_merge_conflict):
222+
open('интервью', 'a').close()
223+
cmd_output('git', 'add', '.')
224+
ret = git.get_conflicted_files()
225+
assert ret == {'conflict_file', 'интервью'}

0 commit comments

Comments
 (0)