Skip to content

Commit 9c272ab

Browse files
committed
fix(encoding): in untracked_files() and index
* untracked_files could, if there were spaces in the path returned, re-rencode the previously decoded unicode string thanks to a `decode("string_escape")` call. Now re-encode into utf-8 afterwards - added test to assure this works indeed * IndexFile.add() didn't handle unicode correctly and would write broken index files. The solution was to compute the path length after encoding it into utf-8 bytes, not before ... . Closes #320
1 parent af44258 commit 9c272ab

File tree

4 files changed

+20
-17
lines changed

4 files changed

+20
-17
lines changed

‎git/index/base.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ def _store_path(self, filepath, fprogress):
583583
stream = None
584584
if S_ISLNK(st.st_mode):
585585
# in PY3, readlink is string, but we need bytes. In PY2, it's just OS encoded bytes, we assume UTF-8
586-
stream = BytesIO(force_bytes(os.readlink(filepath), encoding='utf-8'))
586+
stream = BytesIO(force_bytes(os.readlink(filepath), encoding=defenc))
587587
else:
588588
stream = open(filepath, 'rb')
589589
# END handle stream
@@ -610,7 +610,7 @@ def _entries_for_paths(self, paths, path_rewriter, fprogress, entries):
610610

611611
blob = Blob(self.repo, Blob.NULL_BIN_SHA,
612612
stat_mode_to_index_mode(os.stat(abspath).st_mode),
613-
to_native_path_linux(gitrelative_path))
613+
to_native_path_linux(gitrelative_path), encoding=defenc)
614614
# TODO: variable undefined
615615
entries.append(BaseIndexEntry.from_blob(blob))
616616
# END for each path

‎git/index/fun.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,13 @@ def write_cache(entries, stream, extension_data=None, ShaStreamCls=IndexFileSHA1
124124
write(entry[4]) # ctime
125125
write(entry[5]) # mtime
126126
path = entry[3]
127+
path = path.encode(defenc)
127128
plen = len(path) & CE_NAMEMASK # path length
128129
assert plen == len(path), "Path %s too long to fit into index" % entry[3]
129130
flags = plen | (entry[2] & CE_NAMEMASK_INV) # clear possible previous values
130131
write(pack(">LLLLLL20sH", entry[6], entry[7], entry[0],
131132
entry[8], entry[9], entry[10], entry[1], flags))
132-
write(path.encode(defenc))
133+
write(path)
133134
real_size = ((tell() - beginoffset + 8) & ~7)
134135
write(b"\0" * ((beginoffset + real_size) - tell()))
135136
# END for each entry

‎git/repo/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ def _get_untracked_files(self, **kwargs):
625625
filename = line[len(prefix):].rstrip('\n')
626626
# Special characters are escaped
627627
if filename[0] == filename[-1] == '"':
628-
filename = filename[1:-1].decode('string_escape')
628+
filename = filename[1:-1].decode('string_escape').decode(defenc)
629629
untracked_files.append(filename)
630630
finalize_process(proc)
631631
return untracked_files

‎git/test/test_repo.py

+15-13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#-*-coding:utf-8-*-
12
# test_repo.py
23
# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
34
#
@@ -324,31 +325,32 @@ def test_blame_complex_revision(self, git):
324325
assert len(res) == 1
325326
assert len(res[0][1]) == 83, "Unexpected amount of parsed blame lines"
326327

327-
def test_untracked_files(self):
328-
base = self.rorepo.working_tree_dir
329-
files = (join_path_native(base, "__test_myfile"),
330-
join_path_native(base, "__test_other_file"))
331-
num_recently_untracked = 0
332-
try:
328+
@with_rw_repo('HEAD', bare=False)
329+
def test_untracked_files(self, rwrepo):
330+
for (run, repo_add) in enumerate((rwrepo.index.add, rwrepo.git.add)):
331+
base = rwrepo.working_tree_dir
332+
files = (join_path_native(base, u"%i_test _myfile" % run),
333+
join_path_native(base, "%i_test_other_file" % run),
334+
join_path_native(base, u"%i__çava verböten" % run),
335+
join_path_native(base, u"%i_çava-----verböten" % run))
336+
337+
num_recently_untracked = 0
333338
for fpath in files:
334339
fd = open(fpath, "wb")
335340
fd.close()
336341
# END for each filename
337-
untracked_files = self.rorepo.untracked_files
342+
untracked_files = rwrepo.untracked_files
338343
num_recently_untracked = len(untracked_files)
339344

340345
# assure we have all names - they are relative to the git-dir
341346
num_test_untracked = 0
342347
for utfile in untracked_files:
343348
num_test_untracked += join_path_native(base, utfile) in files
344349
assert len(files) == num_test_untracked
345-
finally:
346-
for fpath in files:
347-
if os.path.isfile(fpath):
348-
os.remove(fpath)
349-
# END handle files
350350

351-
assert len(self.rorepo.untracked_files) == (num_recently_untracked - len(files))
351+
repo_add(untracked_files)
352+
assert len(rwrepo.untracked_files) == (num_recently_untracked - len(files))
353+
# end for each run
352354

353355
def test_config_reader(self):
354356
reader = self.rorepo.config_reader() # all config files

0 commit comments

Comments
 (0)