Skip to content

Commit

Permalink
Fix another test case mentioned by Segev in #526
Browse files Browse the repository at this point in the history
  • Loading branch information
jelmer committed Jul 20, 2017
1 parent 0e84729 commit e2a5563
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 37 deletions.
79 changes: 44 additions & 35 deletions dulwich/ignore.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,41 @@
import sys


def _translate_segment(segment):
if segment == b"*":
return b'[^/]+'
res = b""
i, n = 0, len(segment)
while i < n:
c = segment[i:i+1]
i = i+1
if c == b'*':
res += b'[^/]*'
elif c == b'?':
res += b'.'
elif c == b'[':
j = i
if j < n and segment[j:j+1] == b'!':
j = j+1
if j < n and segment[j:j+1] == b']':
j = j+1
while j < n and segment[j:j+1] != b']':
j = j+1
if j >= n:
res += b'\\['
else:
stuff = segment[i:j].replace(b'\\', b'\\\\')
i = j+1
if stuff.startswith(b'!'):
stuff = b'^' + stuff[1:]
elif stuff.startswith(b'^'):
stuff = b'\\' + stuff
res += b'[' + stuff + b']'
else:
res += re.escape(c)
return res


def translate(pat):
"""Translate a shell PATTERN to a regular expression.
Expand All @@ -40,52 +75,26 @@ def translate(pat):

if b'/' not in pat[:-1]:
# If there's no slash, this is a filename-based match
res = res + b'(.*/)?'
res += b'(.*/)?'

if pat.startswith(b'**/'):
# Leading **/
pat = pat[2:]
res = res + b'(.*/)?'
res += b'(.*/)?'

if pat.startswith(b'/'):
pat = pat[1:]

i, n = 0, len(pat)

while i < n:
if pat[i:i+3] == b'/**':
res = res + b'(/.*)?'
i = i+3
for i, segment in enumerate(pat.split(b'/')):
if segment == b'**':
res += b'(/.*)?'
continue
c = pat[i:i+1]
i = i+1
if c == b'*':
res = res + b'[^/]*'
elif c == b'?':
res = res + b'.'
elif c == b'[':
j = i
if j < n and pat[j:j+1] == b'!':
j = j+1
if j < n and pat[j:j+1] == b']':
j = j+1
while j < n and pat[j:j+1] != b']':
j = j+1
if j >= n:
res = res + b'\\['
else:
stuff = pat[i:j].replace(b'\\', b'\\\\')
i = j+1
if stuff.startswith(b'!'):
stuff = b'^' + stuff[1:]
elif stuff.startswith(b'^'):
stuff = b'\\' + stuff
res = res + b'[' + stuff + b']'
else:
res = res + re.escape(c)
res += ((re.escape(b'/') if i > 0 else b'') +
_translate_segment(segment))

if not res.endswith(b'/'):
res = res + b'/?'
if not pat.endswith(b'/'):
res += b'/?'

return res + b'\Z'

Expand Down
19 changes: 17 additions & 2 deletions dulwich/tests/test_ignore.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,15 @@
(b"foo/bla/bar", b"foo/**/bar"),
(b"foo/bar/", b"bar/"),
(b"foo/bar/", b"bar"),
(b"foo/bar/", b"foo/bar/*"),
(b"foo/bar/something", b"foo/bar/*"),
]

NEGATIVE_MATCH_TESTS = [
(b"foo.c", b"foo.[dh]"),
(b"foo/foo.c", b"/foo.c"),
(b"foo/foo.c", b"/*.c"),
(b"foo/bar/", b"/bar/"),
(b"foo/bar/", b"foo/bar/*"),
]


Expand All @@ -79,7 +80,7 @@
(b"foo/**/blie.c", b'(?ms)foo(/.*)?\\/blie\\.c/?\\Z'),
(b"**/bla.c", b'(?ms)(.*/)?bla\\.c/?\\Z'),
(b"foo/**/bar", b'(?ms)foo(/.*)?\\/bar/?\\Z'),
(b"foo/bar/*", b'(?ms)foo\\/bar\\/[^/]*/?\\Z'),
(b"foo/bar/*", b'(?ms)foo\\/bar\\/[^/]+/?\\Z'),
]


Expand Down Expand Up @@ -243,3 +244,17 @@ def test_load_ignore_ignorecase(self):
m = IgnoreFilterManager.from_repo(repo)
self.assertTrue(m.is_ignored(os.path.join('dir', 'blie')))
self.assertTrue(m.is_ignored(os.path.join('DIR', 'blie')))

def test_ignored_contents(self):
tmp_dir = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, tmp_dir)
repo = Repo.init(tmp_dir)
with open(os.path.join(repo.path, '.gitignore'), 'wb') as f:
f.write(b'a/*\n')
f.write(b'!a/*.txt\n')
m = IgnoreFilterManager.from_repo(repo)
os.mkdir(os.path.join(repo.path, 'a'))
self.assertIs(None, m.is_ignored('a'))
self.assertIs(None, m.is_ignored('a/'))
self.assertFalse(m.is_ignored('a/b.txt'))
self.assertTrue(m.is_ignored('a/c.dat'))

0 comments on commit e2a5563

Please sign in to comment.