Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgIgnore.java @ 414:bb278ccf9866
Pull changes from smartgit3 branch
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 21 Mar 2012 20:51:12 +0100 |
parents | 0f5696623512 |
children | 7f136a3fa671 |
comparison
equal
deleted
inserted
replaced
413:7f27122011c3 | 414:bb278ccf9866 |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2010-2011 TMate Software Ltd | 2 * Copyright (c) 2010-2012 TMate Software Ltd |
3 * | 3 * |
4 * This program is free software; you can redistribute it and/or modify | 4 * This program is free software; you can redistribute it and/or modify |
5 * it under the terms of the GNU General Public License as published by | 5 * it under the terms of the GNU General Public License as published by |
6 * the Free Software Foundation; version 2 of the License. | 6 * the Free Software Foundation; version 2 of the License. |
7 * | 7 * |
25 import java.util.List; | 25 import java.util.List; |
26 import java.util.regex.Pattern; | 26 import java.util.regex.Pattern; |
27 import java.util.regex.PatternSyntaxException; | 27 import java.util.regex.PatternSyntaxException; |
28 | 28 |
29 import org.tmatesoft.hg.util.Path; | 29 import org.tmatesoft.hg.util.Path; |
30 import org.tmatesoft.hg.util.PathRewrite; | |
30 | 31 |
31 /** | 32 /** |
32 * Handling of ignored paths according to .hgignore configuration | 33 * Handling of ignored paths according to .hgignore configuration |
33 * | 34 * |
34 * @author Artem Tikhomirov | 35 * @author Artem Tikhomirov |
35 * @author TMate Software Ltd. | 36 * @author TMate Software Ltd. |
36 */ | 37 */ |
37 public class HgIgnore implements Path.Matcher { | 38 public class HgIgnore implements Path.Matcher { |
38 | 39 |
39 private List<Pattern> entries; | 40 private List<Pattern> entries; |
40 | 41 private final PathRewrite globPathHelper; |
41 HgIgnore() { | 42 |
43 HgIgnore(PathRewrite globPathRewrite) { | |
42 entries = Collections.emptyList(); | 44 entries = Collections.emptyList(); |
43 } | 45 globPathHelper = globPathRewrite; |
44 | 46 } |
45 /* package-local */List<String> read(File hgignoreFile) throws IOException { | 47 |
48 /* package-local */ List<String> read(File hgignoreFile) throws IOException { | |
46 if (!hgignoreFile.exists()) { | 49 if (!hgignoreFile.exists()) { |
47 return null; | 50 return null; |
48 } | 51 } |
49 BufferedReader fr = new BufferedReader(new FileReader(hgignoreFile)); | 52 BufferedReader fr = new BufferedReader(new FileReader(hgignoreFile)); |
50 try { | 53 try { |
52 } finally { | 55 } finally { |
53 fr.close(); | 56 fr.close(); |
54 } | 57 } |
55 } | 58 } |
56 | 59 |
57 /* package-local */List<String> read(BufferedReader content) throws IOException { | 60 /* package-local */ List<String> read(BufferedReader content) throws IOException { |
61 final String REGEXP = "regexp", GLOB = "glob"; | |
62 final String REGEXP_PREFIX = REGEXP + ":", GLOB_PREFIX = GLOB + ":"; | |
58 ArrayList<String> errors = new ArrayList<String>(); | 63 ArrayList<String> errors = new ArrayList<String>(); |
59 ArrayList<Pattern> result = new ArrayList<Pattern>(entries); // start with existing | 64 ArrayList<Pattern> result = new ArrayList<Pattern>(entries); // start with existing |
60 String syntax = "regexp"; // or "glob" | 65 String syntax = REGEXP; |
61 String line; | 66 String line; |
62 while ((line = content.readLine()) != null) { | 67 while ((line = content.readLine()) != null) { |
63 line = line.trim(); | 68 line = line.trim(); |
64 if (line.startsWith("syntax:")) { | 69 if (line.startsWith("syntax:")) { |
65 syntax = line.substring("syntax:".length()).trim(); | 70 syntax = line.substring("syntax:".length()).trim(); |
66 if (!"regexp".equals(syntax) && !"glob".equals(syntax)) { | 71 if (!REGEXP.equals(syntax) && !GLOB.equals(syntax)) { |
67 errors.add(line); | 72 errors.add(line); |
68 continue; | 73 continue; |
69 //throw new IllegalStateException(line); | 74 //throw new IllegalStateException(line); |
70 } | 75 } |
71 } else if (line.length() > 0) { | 76 } else if (line.length() > 0) { |
79 s = x; // with exclusion of char at [x], s now points to what used to be at [x+1] | 84 s = x; // with exclusion of char at [x], s now points to what used to be at [x+1] |
80 } else { | 85 } else { |
81 line = line.substring(0, x).trim(); | 86 line = line.substring(0, x).trim(); |
82 } | 87 } |
83 } | 88 } |
89 // due to the nature of Mercurial implementation, lines prefixed with syntax kind | |
90 // are processed correctly (despite the fact hgignore(5) suggest "syntax:<kind>" as the | |
91 // only way to specify it). lineSyntax below leaves a chance for the line to switch | |
92 // syntax in use without affecting default kind. | |
93 String lineSyntax; | |
94 if (line.startsWith(GLOB_PREFIX)) { | |
95 line = line.substring(GLOB_PREFIX.length()).trim(); | |
96 lineSyntax = GLOB; | |
97 } else if (line.startsWith(REGEXP_PREFIX)) { | |
98 line = line.substring(REGEXP_PREFIX.length()).trim(); | |
99 lineSyntax = REGEXP; | |
100 } else { | |
101 lineSyntax = syntax; | |
102 } | |
84 if (line.length() == 0) { | 103 if (line.length() == 0) { |
85 continue; | 104 continue; |
86 } | 105 } |
87 if ("glob".equals(syntax)) { | 106 if (GLOB.equals(lineSyntax)) { |
88 // hgignore(5) | 107 // hgignore(5) says slashes '\' are escape characters, |
89 // (http://www.selenic.com/mercurial/hgignore.5.html) says slashes '\' are escape characters, | 108 // however, for glob patterns on Windows first get backslashes converted to slashes |
90 // hence no special treatment of Windows path | 109 if (globPathHelper != null) { |
91 // however, own attempts make me think '\' on Windows are not treated as escapes | 110 line = globPathHelper.rewrite(line).toString(); |
111 } | |
92 line = glob2regex(line); | 112 line = glob2regex(line); |
93 } else { | 113 } else { |
94 assert "regexp".equals(syntax); | 114 assert REGEXP.equals(lineSyntax); |
95 // regular expression patterns need not match start of the line unless demanded explicitly | 115 // regular expression patterns need not match start of the line unless demanded explicitly |
96 line = line.charAt(0) == '^' ? line : ".*" + line; | 116 line = line.charAt(0) == '^' ? line : ".*" + line; |
97 } | 117 } |
98 try { | 118 try { |
99 result.add(Pattern.compile(line)); // case-sensitive | 119 result.add(Pattern.compile(line)); // case-sensitive |
158 sb.append('|'); | 178 sb.append('|'); |
159 continue; | 179 continue; |
160 } | 180 } |
161 sb.append(ch); | 181 sb.append(ch); |
162 } | 182 } |
163 sb.append("(?:/|$)"); | 183 // Python impl doesn't keep empty segments in directory names (ntpath.normpath and posixpath.normpath), |
184 // effectively removing trailing separators, thus patterns like "bin/" get translated into "bin$" | |
185 // Our glob rewriter doesn't strip last empty segment, and "bin/$" would be incorrect pattern, | |
186 // (e.g. isIgnored("bin/file") performs two matches, against "bin/file" and "bin") hence the check. | |
187 if (sb.charAt(sb.length() - 1) != '/') { | |
188 sb.append('$'); | |
189 } | |
164 return sb.toString(); | 190 return sb.toString(); |
165 } | 191 } |
166 | 192 |
167 /** | 193 /** |
168 * @param path file or directory name in question | 194 * @param path file or directory name in question |