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(); |