# HG changeset patch # User Artem Tikhomirov # Date 1321589433 -3600 # Node ID 516b817415ba97eab9371b1c816f52c2c1363c67 # Parent 75c452fdd76ac9364846bb034f2aa449740947ca HgIgnore: regex patterns to match part of the filename do not work diff -r 75c452fdd76a -r 516b817415ba src/org/tmatesoft/hg/repo/HgIgnore.java --- a/src/org/tmatesoft/hg/repo/HgIgnore.java Thu Nov 17 07:04:58 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgIgnore.java Fri Nov 18 05:10:33 2011 +0100 @@ -90,6 +90,10 @@ // hence no special treatment of Windows path // however, own attempts make me think '\' on Windows are not treated as escapes line = glob2regex(line); + } else { + assert "regexp".equals(syntax); + // regular expression patterns need not match start of the line unless demanded explicitly + line = line.charAt(0) == '^' ? line : ".*" + line; } try { result.add(Pattern.compile(line)); // case-sensitive @@ -119,6 +123,7 @@ assert line.length() > 0; StringBuilder sb = new StringBuilder(line.length() + 10); int start = 0, end = line.length() - 1; + sb.append("(?:|.*/)"); // glob patterns shall match file in any directory int inCurly = 0; for (int i = start; i <= end; i++) { @@ -163,17 +168,18 @@ * @return true if matches repository configuration of ignored files. */ public boolean isIgnored(Path path) { - boolean isDeep = path.toString().indexOf('/') != -1; + String ps = path.toString(); for (Pattern p : entries) { - if (p.matcher(path).matches()) { + int x = ps.indexOf('/'); // reset for each pattern + if (p.matcher(ps).find()) { return true; } - if (isDeep) { - for (String segment : path.segments()) { - if (p.matcher(segment).matches()) { - return true; - } + while (x != -1 && x+1 != ps.length() /*skip very last segment not to check complete string twice*/) { + String fragment = ps.substring(0, x); + if (p.matcher(fragment).matches()) { + return true; } + x = ps.indexOf('/', x+1); } } return false; diff -r 75c452fdd76a -r 516b817415ba test/org/tmatesoft/hg/test/TestIgnore.java --- a/test/org/tmatesoft/hg/test/TestIgnore.java Thu Nov 17 07:04:58 2011 +0100 +++ b/test/org/tmatesoft/hg/test/TestIgnore.java Fri Nov 18 05:10:33 2011 +0100 @@ -41,7 +41,7 @@ TestIgnore test = new TestIgnore(); test.testGlobWithAlternatives(); test.testComplexFileParse(); - test.testSegmentsMatch(); + test.testSegmentsGlobMatch(); test.testWildcardsDoNotMatchDirectorySeparator(); test.errorCollector.verify(); } @@ -74,7 +74,7 @@ } @Test - public void testSegmentsMatch() throws Exception { + public void testSegmentsGlobMatch() throws Exception { String s = "syntax:glob\nbin\n.*\nTEST-*.xml"; HgIgnore hgIgnore = HgInternals.newHgIgnore(new StringReader(s)); Path[] toCheck = new Path[] { @@ -89,7 +89,27 @@ errorCollector.assertTrue(p.toString(), hgIgnore.isIgnored(p)); } } - + + @Test + public void testSegmentsRegexMatch() throws Exception { + // regex patterns that don't start with explicit ^ are allowed to match anywhere in the string + String s = "syntax:regex\n/\\.git\n^abc\n"; + HgIgnore hgIgnore = HgInternals.newHgIgnore(new StringReader(s)); + Path p = Path.create(".git/aa"); + errorCollector.assertTrue(p.toString(), !hgIgnore.isIgnored(p)); + p = Path.create("dir/.git/bb"); + errorCollector.assertTrue(p.toString(), hgIgnore.isIgnored(p)); + p = Path.create("dir/abc/aa"); + errorCollector.assertTrue(p.toString(), !hgIgnore.isIgnored(p)); + p = Path.create("abc/bb"); + errorCollector.assertTrue(p.toString(), hgIgnore.isIgnored(p)); + // Mercurial (in fact, likely pyton's regex match() function) treats + // regex patterns as having .* at the end (unless there's explicit $). + // IOW, matches to the beginning of the string, not to the whole string + p = Path.create("abcde/fg"); + errorCollector.assertTrue(p.toString(), hgIgnore.isIgnored(p)); + } + @Test public void testWildcardsDoNotMatchDirectorySeparator() throws Exception { String s = "syntax:glob\na?b\nc*d";