Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgIgnore.java @ 269:7af843ecc378
Respect glob pattern with alternatives {a,b}
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Tue, 23 Aug 2011 23:47:38 +0200 |
| parents | fad70a9e6c7f |
| children | c8baeb813d74 |
comparison
equal
deleted
inserted
replaced
| 268:c5980f287cc4 | 269:7af843ecc378 |
|---|---|
| 43 | 43 |
| 44 /* package-local */void read(File hgignoreFile) throws IOException { | 44 /* package-local */void read(File hgignoreFile) throws IOException { |
| 45 if (!hgignoreFile.exists()) { | 45 if (!hgignoreFile.exists()) { |
| 46 return; | 46 return; |
| 47 } | 47 } |
| 48 BufferedReader fr = new BufferedReader(new FileReader(hgignoreFile)); | |
| 49 try { | |
| 50 read(fr); | |
| 51 } finally { | |
| 52 fr.close(); | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 /* package-local */void read(BufferedReader content) throws IOException { | |
| 48 ArrayList<Pattern> result = new ArrayList<Pattern>(entries); // start with existing | 57 ArrayList<Pattern> result = new ArrayList<Pattern>(entries); // start with existing |
| 49 String syntax = "regex"; // or "glob" | 58 String syntax = "regexp"; // or "glob" |
| 50 BufferedReader fr = new BufferedReader(new FileReader(hgignoreFile)); | |
| 51 String line; | 59 String line; |
| 52 while ((line = fr.readLine()) != null) { | 60 while ((line = content.readLine()) != null) { |
| 53 line = line.trim(); | 61 line = line.trim(); |
| 54 if (line.startsWith("syntax:")) { | 62 if (line.startsWith("syntax:")) { |
| 55 syntax = line.substring("syntax:".length()).trim(); | 63 syntax = line.substring("syntax:".length()).trim(); |
| 56 if (!"regex".equals(syntax) && !"glob".equals(syntax)) { | 64 if (!"regexp".equals(syntax) && !"glob".equals(syntax)) { |
| 57 throw new IllegalStateException(line); | 65 throw new IllegalStateException(line); |
| 58 } | 66 } |
| 59 } else if (line.length() > 0) { | 67 } else if (line.length() > 0) { |
| 60 // shall I account for local paths in the file (i.e. | 68 // shall I account for local paths in the file (i.e. |
| 61 // back-slashed on windows)? | 69 // back-slashed on windows)? |
| 62 int x; | 70 int x, s = 0; |
| 63 if ((x = line.indexOf('#')) >= 0) { | 71 while ((x = line.indexOf('#', s)) >= 0) { |
| 64 line = line.substring(0, x).trim(); | 72 if (x > 0 && line.charAt(x-1) == '\\') { |
| 65 if (line.length() == 0) { | 73 // remove escape char |
| 66 continue; | 74 line = line.substring(0, x-1).concat(line.substring(x)); |
| 75 s = x; // with exclusion of char at [x], s now points to what used to be at [x+1] | |
| 76 } else { | |
| 77 line = line.substring(0, x).trim(); | |
| 67 } | 78 } |
| 79 } | |
| 80 if (line.length() == 0) { | |
| 81 continue; | |
| 68 } | 82 } |
| 69 if ("glob".equals(syntax)) { | 83 if ("glob".equals(syntax)) { |
| 70 // hgignore(5) | 84 // hgignore(5) |
| 71 // (http://www.selenic.com/mercurial/hgignore.5.html) says slashes '\' are escape characters, | 85 // (http://www.selenic.com/mercurial/hgignore.5.html) says slashes '\' are escape characters, |
| 72 // hence no special treatment of Windows path | 86 // hence no special treatment of Windows path |
| 74 line = glob2regex(line); | 88 line = glob2regex(line); |
| 75 } | 89 } |
| 76 result.add(Pattern.compile(line)); // case-sensitive | 90 result.add(Pattern.compile(line)); // case-sensitive |
| 77 } | 91 } |
| 78 } | 92 } |
| 79 fr.close(); | |
| 80 result.trimToSize(); | 93 result.trimToSize(); |
| 81 entries = result; | 94 entries = result; |
| 82 } | 95 } |
| 83 | 96 |
| 84 // note, #isIgnored(), even if queried for directories and returned positive reply, may still get | 97 // note, #isIgnored(), even if queried for directories and returned positive reply, may still get |
| 92 // might be interesting, although looks like of no direct use in my case | 105 // might be interesting, although looks like of no direct use in my case |
| 93 // @see http://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java-util-regex-for-glob-type-patterns | 106 // @see http://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java-util-regex-for-glob-type-patterns |
| 94 private String glob2regex(String line) { | 107 private String glob2regex(String line) { |
| 95 assert line.length() > 0; | 108 assert line.length() > 0; |
| 96 StringBuilder sb = new StringBuilder(line.length() + 10); | 109 StringBuilder sb = new StringBuilder(line.length() + 10); |
| 97 sb.append('^'); // help avoid matcher.find() to match 'bin' pattern in the middle of the filename | 110 if (line.charAt(0) != '*') { |
| 111 sb.append('^'); // help avoid matcher.find() to match 'bin' pattern in the middle of the filename | |
| 112 } | |
| 98 int start = 0, end = line.length() - 1; | 113 int start = 0, end = line.length() - 1; |
| 99 // '*' at the beginning and end of a line are useless for Pattern | 114 // '*' at the beginning and end of a line are useless for Pattern |
| 100 // XXX although how about **.txt - such globs can be seen in a config, are they valid for HgIgnore? | 115 // XXX although how about **.txt - such globs can be seen in a config, are they valid for HgIgnore? |
| 101 while (start <= end && line.charAt(start) == '*') start++; | 116 while (start <= end && line.charAt(start) == '*') start++; |
| 102 while (end > start && line.charAt(end) == '*') end--; | 117 while (end > start && line.charAt(end) == '*') end--; |
| 103 | 118 |
| 119 if (line.endsWith(".so")) { | |
| 120 System.out.println(); | |
| 121 } | |
| 122 int inCurly = 0; | |
| 104 for (int i = start; i <= end; i++) { | 123 for (int i = start; i <= end; i++) { |
| 105 char ch = line.charAt(i); | 124 char ch = line.charAt(i); |
| 106 if (ch == '.' || ch == '\\') { | 125 if (ch == '.' || ch == '\\') { |
| 107 sb.append('\\'); | 126 sb.append('\\'); |
| 108 } else if (ch == '?') { | 127 } else if (ch == '?') { |
| 114 // it shall neither be matched by the asterisk or question-mark special characters nor by a bracket expression" | 133 // it shall neither be matched by the asterisk or question-mark special characters nor by a bracket expression" |
| 115 sb.append("[^/]"); | 134 sb.append("[^/]"); |
| 116 continue; | 135 continue; |
| 117 } else if (ch == '*') { | 136 } else if (ch == '*') { |
| 118 sb.append("[^/]*?"); | 137 sb.append("[^/]*?"); |
| 138 continue; | |
| 139 } else if (ch == '{') { | |
| 140 // XXX in fact, need to respect if last char was escaping ('\\'), then don't need to treat this as special | |
| 141 // see link at javadoc above for reasonable example | |
| 142 inCurly++; | |
| 143 sb.append('('); | |
| 144 continue; | |
| 145 } else if (ch == '}') { | |
| 146 if (inCurly > 0) { | |
| 147 inCurly--; | |
| 148 sb.append(')'); | |
| 149 continue; | |
| 150 } | |
| 151 } else if (ch == ',' && inCurly > 0) { | |
| 152 sb.append('|'); | |
| 119 continue; | 153 continue; |
| 120 } | 154 } |
| 121 sb.append(ch); | 155 sb.append(ch); |
| 122 } | 156 } |
| 123 return sb.toString(); | 157 return sb.toString(); |
