2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
/// A single ignore rule corresponding to one line in a .gitignore or
55
/// A single ignore rule corresponding to one line in a .gitignore or
56
/// ignore file. Parses the ignore pattern
57
/// Inspiration from: Ferry Huberts
59
public class IgnoreRule
61
private string pattern;
63
private bool negation;
65
private bool nameOnly;
69
private FileNameMatcher matcher;
71
/// <summary>Create a new ignore rule with the given pattern.</summary>
73
/// Create a new ignore rule with the given pattern. Assumes that
74
/// the pattern is already trimmed.
76
/// <param name="pattern">
77
/// Base pattern for the ignore rule. This pattern will
78
/// be parsed to generate rule parameters.
80
public IgnoreRule(string pattern)
82
this.pattern = pattern;
90
/// <summary>Remove leading/trailing characters as needed.</summary>
92
/// Remove leading/trailing characters as needed. Set up
93
/// rule variables for later matching.
98
int endIndex = pattern.Length;
99
if (pattern.StartsWith("!"))
104
if (pattern.EndsWith("/"))
109
pattern = Sharpen.Runtime.Substring(pattern, startIndex, endIndex);
110
bool hasSlash = pattern.Contains("/");
117
if (!pattern.StartsWith("/"))
119
//Contains "/" but does not start with one
120
//Adding / to the start should not interfere with matching
121
pattern = "/" + pattern;
124
if (pattern.Contains("*") || pattern.Contains("?") || pattern.Contains("["))
128
matcher = new FileNameMatcher(pattern, '/');
130
catch (InvalidPatternException e)
132
Sharpen.Runtime.PrintStackTrace(e);
137
/// <returns>True if the pattern is just a file name and not a path</returns>
138
public virtual bool GetNameOnly()
143
/// <returns>True if the pattern should match directories only</returns>
144
public virtual bool DirOnly()
149
/// <returns>True if the pattern had a "!" in front of it</returns>
150
public virtual bool GetNegation()
155
/// <returns>The blob pattern to be used as a matcher</returns>
156
public virtual string GetPattern()
161
/// <summary>Returns true if a match was made.</summary>
163
/// Returns true if a match was made.
165
/// This function does NOT return the actual ignore status of the
166
/// target! Please consult
167
/// <see cref="GetResult()">GetResult()</see>
168
/// for the ignore status. The actual
169
/// ignore status may be true or false depending on whether this rule is
170
/// an ignore rule or a negation rule.
172
/// <param name="target">Name pattern of the file, relative to the base directory of this rule
174
/// <param name="isDirectory">Whether the target file is a directory or not</param>
176
/// True if a match was made. This does not necessarily mean that
177
/// the target is ignored. Call
178
/// <see cref="GetResult()">getResult()</see>
181
public virtual bool IsMatch(string target, bool isDirectory)
183
if (!target.StartsWith("/"))
185
target = "/" + target;
189
if (target.Equals(pattern))
192
if (dirOnly && !isDirectory)
194
//Directory expectations not met
199
//Directory expectations met
203
if ((target).StartsWith(pattern + "/"))
209
//Iterate through each sub-name
210
string[] segments = target.Split("/");
211
for (int idx = 0; idx < segments.Length; idx++)
213
string segmentName = segments[idx];
214
if (segmentName.Equals(pattern) && DoesMatchDirectoryExpectations(isDirectory, idx
224
matcher.Append(target);
225
if (matcher.IsMatch())
229
string[] segments = target.Split("/");
232
for (int idx = 0; idx < segments.Length; idx++)
234
string segmentName = segments[idx];
235
//Iterate through each sub-directory
237
matcher.Append(segmentName);
238
if (matcher.IsMatch() && DoesMatchDirectoryExpectations(isDirectory, idx, segments
247
//TODO: This is the slowest operation
248
//This matches e.g. "/src/ne?" to "/src/new/file.c"
250
for (int idx = 0; idx < segments.Length; idx++)
252
string segmentName = segments[idx];
253
if (segmentName.Length > 0)
255
matcher.Append("/" + segmentName);
257
if (matcher.IsMatch() && DoesMatchDirectoryExpectations(isDirectory, idx, segments
269
/// If a call to <code>isMatch(String, boolean)</code> was previously
270
/// made, this will return whether or not the target was ignored.
273
/// If a call to <code>isMatch(String, boolean)</code> was previously
274
/// made, this will return whether or not the target was ignored. Otherwise
275
/// this just indicates whether the rule is non-negation or negation.
277
/// <returns>True if the target is to be ignored, false otherwise.</returns>
278
public virtual bool GetResult()
283
private bool DoesMatchDirectoryExpectations(bool isDirectory, int segmentIdx, int
286
// The segment we are checking is a directory, expectations are met.
287
if (segmentIdx < segmentLength - 1)
291
// We are checking the last part of the segment for which isDirectory has to be considered.
292
return !dirOnly || isDirectory;