View Javadoc
1   /*
2    * Copyright (C) 2010, Red Hat Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.ignore;
11  
12  import static java.nio.charset.StandardCharsets.UTF_8;
13  
14  import java.io.BufferedReader;
15  import java.io.IOException;
16  import java.io.InputStream;
17  import java.io.InputStreamReader;
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.List;
21  
22  /**
23   * Represents a bundle of ignore rules inherited from a base directory.
24   *
25   * This class is not thread safe, it maintains state about the last match.
26   */
27  public class IgnoreNode {
28  	/** Result from {@link IgnoreNode#isIgnored(String, boolean)}. */
29  	public enum MatchResult {
30  		/** The file is not ignored, due to a rule saying its not ignored. */
31  		NOT_IGNORED,
32  
33  		/** The file is ignored due to a rule in this node. */
34  		IGNORED,
35  
36  		/** The ignore status is unknown, check inherited rules. */
37  		CHECK_PARENT,
38  
39  		/**
40  		 * The first previous (parent) ignore rule match (if any) should be
41  		 * negated, and then inherited rules applied.
42  		 *
43  		 * @since 3.6
44  		 */
45  		CHECK_PARENT_NEGATE_FIRST_MATCH;
46  	}
47  
48  	/** The rules that have been parsed into this node. */
49  	private final List<FastIgnoreRule> rules;
50  
51  	/**
52  	 * Create an empty ignore node with no rules.
53  	 */
54  	public IgnoreNode() {
55  		rules = new ArrayList<>();
56  	}
57  
58  	/**
59  	 * Create an ignore node with given rules.
60  	 *
61  	 * @param rules
62  	 *            list of rules.
63  	 */
64  	public IgnoreNode(List<FastIgnoreRule> rules) {
65  		this.rules = rules;
66  	}
67  
68  	/**
69  	 * Parse files according to gitignore standards.
70  	 *
71  	 * @param in
72  	 *            input stream holding the standard ignore format. The caller is
73  	 *            responsible for closing the stream.
74  	 * @throws java.io.IOException
75  	 *             Error thrown when reading an ignore file.
76  	 */
77  	public void parse(InputStream in) throws IOException {
78  		BufferedReader br = asReader(in);
79  		String txt;
80  		while ((txt = br.readLine()) != null) {
81  			if (txt.length() > 0 && !txt.startsWith("#") && !txt.equals("/")) { //$NON-NLS-1$ //$NON-NLS-2$
82  				FastIgnoreRule rule = new FastIgnoreRule(txt);
83  				if (!rule.isEmpty()) {
84  					rules.add(rule);
85  				}
86  			}
87  		}
88  	}
89  
90  	private static BufferedReader asReader(InputStream in) {
91  		return new BufferedReader(new InputStreamReader(in, UTF_8));
92  	}
93  
94  	/**
95  	 * Get list of all ignore rules held by this node
96  	 *
97  	 * @return list of all ignore rules held by this node
98  	 */
99  	public List<FastIgnoreRule> getRules() {
100 		return Collections.unmodifiableList(rules);
101 	}
102 
103 	/**
104 	 * Determine if an entry path matches an ignore rule.
105 	 *
106 	 * @param entryPath
107 	 *            the path to test. The path must be relative to this ignore
108 	 *            node's own repository path, and in repository path format
109 	 *            (uses '/' and not '\').
110 	 * @param isDirectory
111 	 *            true if the target item is a directory.
112 	 * @return status of the path.
113 	 */
114 	public MatchResult isIgnored(String entryPath, boolean isDirectory) {
115 		final Boolean result = checkIgnored(entryPath, isDirectory);
116 		if (result == null) {
117 			return MatchResult.CHECK_PARENT;
118 		}
119 
120 		return result.booleanValue() ? MatchResult.IGNORED
121 				: MatchResult.NOT_IGNORED;
122 	}
123 
124 	/**
125 	 * Determine if an entry path matches an ignore rule.
126 	 *
127 	 * @param entryPath
128 	 *            the path to test. The path must be relative to this ignore
129 	 *            node's own repository path, and in repository path format
130 	 *            (uses '/' and not '\').
131 	 * @param isDirectory
132 	 *            true if the target item is a directory.
133 	 * @return Boolean.TRUE, if the entry is ignored; Boolean.FALSE, if the
134 	 *         entry is forced to be not ignored (negated match); or null, if
135 	 *         undetermined
136 	 * @since 4.11
137 	 */
138 	public Boolean checkIgnored(String entryPath, boolean isDirectory) {
139 		// Parse rules in the reverse order that they were read because later
140 		// rules have higher priority
141 		for (int i = rules.size() - 1; i > -1; i--) {
142 			FastIgnoreRule rule = rules.get(i);
143 			if (rule.isMatch(entryPath, isDirectory, true)) {
144 				return Boolean.valueOf(rule.getResult());
145 			}
146 		}
147 		return null;
148 	}
149 
150 	/** {@inheritDoc} */
151 	@Override
152 	public String toString() {
153 		return rules.toString();
154 	}
155 }