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