View Javadoc
1   /*
2    * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
3    * and other copyright owners as documented in the project's IP log.
4    *
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
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
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.
23   *
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
27   *   written permission.
28   *
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.
42   */
43  
44  package org.eclipse.jgit.treewalk.filter;
45  
46  import java.io.IOException;
47  
48  import org.eclipse.jgit.dircache.DirCacheIterator;
49  import org.eclipse.jgit.errors.IncorrectObjectTypeException;
50  import org.eclipse.jgit.errors.MissingObjectException;
51  import org.eclipse.jgit.treewalk.TreeWalk;
52  import org.eclipse.jgit.treewalk.WorkingTreeIterator;
53  
54  /**
55   * Selects interesting tree entries during walking.
56   * <p>
57   * This is an abstract interface. Applications may implement a subclass, or use
58   * one of the predefined implementations already available within this package.
59   * <p>
60   * Unless specifically noted otherwise a TreeFilter implementation is not thread
61   * safe and may not be shared by different TreeWalk instances at the same time.
62   * This restriction allows TreeFilter implementations to cache state within
63   * their instances during {@link #include(TreeWalk)} if it is beneficial to
64   * their implementation. Deep clones created by {@link #clone()} may be used to
65   * construct a thread-safe copy of an existing filter.
66   *
67   * <p>
68   * <b>Path filters:</b>
69   * <ul>
70   * <li>Matching pathname:
71   * {@link org.eclipse.jgit.treewalk.filter.PathFilter}</li>
72   * </ul>
73   *
74   * <p>
75   * <b>Difference filters:</b>
76   * <ul>
77   * <li>Only select differences: {@link #ANY_DIFF}.</li>
78   * </ul>
79   *
80   * <p>
81   * <b>Boolean modifiers:</b>
82   * <ul>
83   * <li>AND: {@link org.eclipse.jgit.treewalk.filter.AndTreeFilter}</li>
84   * <li>OR: {@link org.eclipse.jgit.treewalk.filter.OrTreeFilter}</li>
85   * <li>NOT: {@link org.eclipse.jgit.treewalk.filter.NotTreeFilter}</li>
86   * </ul>
87   */
88  public abstract class TreeFilter {
89  	/** Selects all tree entries. */
90  	public static final TreeFilter ALL = new AllFilter();
91  
92  	private static final class AllFilter extends TreeFilter {
93  		@Override
94  		public boolean include(TreeWalk walker) {
95  			return true;
96  		}
97  
98  		@Override
99  		public boolean shouldBeRecursive() {
100 			return false;
101 		}
102 
103 		@Override
104 		public TreeFilter clone() {
105 			return this;
106 		}
107 
108 		@Override
109 		public String toString() {
110 			return "ALL"; //$NON-NLS-1$
111 		}
112 	}
113 
114 	/**
115 	 * Selects only tree entries which differ between at least 2 trees.
116 	 * <p>
117 	 * This filter also prevents a TreeWalk from recursing into a subtree if all
118 	 * parent trees have the identical subtree at the same path. This
119 	 * dramatically improves walk performance as only the changed subtrees are
120 	 * entered into.
121 	 * <p>
122 	 * If this filter is applied to a walker with only one tree it behaves like
123 	 * {@link #ALL}, or as though the walker was matching a virtual empty tree
124 	 * against the single tree it was actually given. Applications may wish to
125 	 * treat such a difference as "all names added".
126 	 * <p>
127 	 * When comparing {@link WorkingTreeIterator} and {@link DirCacheIterator}
128 	 * applications should use {@link IndexDiffFilter}.
129 	 */
130 	public static final TreeFilter ANY_DIFF = new AnyDiffFilter();
131 
132 	private static final class AnyDiffFilter extends TreeFilter {
133 		private static final int baseTree = 0;
134 
135 		@Override
136 		public boolean include(TreeWalk walker) {
137 			final int n = walker.getTreeCount();
138 			if (n == 1) // Assume they meant difference to empty tree.
139 				return true;
140 
141 			final int m = walker.getRawMode(baseTree);
142 			for (int i = 1; i < n; i++)
143 				if (walker.getRawMode(i) != m || !walker.idEqual(i, baseTree))
144 					return true;
145 			return false;
146 		}
147 
148 		@Override
149 		public boolean shouldBeRecursive() {
150 			return false;
151 		}
152 
153 		@Override
154 		public TreeFilter clone() {
155 			return this;
156 		}
157 
158 		@Override
159 		public String toString() {
160 			return "ANY_DIFF"; //$NON-NLS-1$
161 		}
162 	}
163 
164 	/**
165 	 * Create a new filter that does the opposite of this filter.
166 	 *
167 	 * @return a new filter that includes tree entries this filter rejects.
168 	 */
169 	public TreeFilter negate() {
170 		return NotTreeFilter.create(this);
171 	}
172 
173 	/**
174 	 * Determine if the current entry is interesting to report.
175 	 * <p>
176 	 * This method is consulted for subtree entries even if
177 	 * {@link org.eclipse.jgit.treewalk.TreeWalk#isRecursive()} is enabled. The
178 	 * consultation allows the filter to bypass subtree recursion on a
179 	 * case-by-case basis, even when recursion is enabled at the application
180 	 * level.
181 	 *
182 	 * @param walker
183 	 *            the walker the filter needs to examine.
184 	 * @return true if the current entry should be seen by the application;
185 	 *         false to hide the entry.
186 	 * @throws org.eclipse.jgit.errors.MissingObjectException
187 	 *             an object the filter needs to consult to determine its answer
188 	 *             does not exist in the Git repository the walker is operating
189 	 *             on. Filtering this current walker entry is impossible without
190 	 *             the object.
191 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
192 	 *             an object the filter needed to consult was not of the
193 	 *             expected object type. This usually indicates a corrupt
194 	 *             repository, as an object link is referencing the wrong type.
195 	 * @throws java.io.IOException
196 	 *             a loose object or pack file could not be read to obtain data
197 	 *             necessary for the filter to make its decision.
198 	 */
199 	public abstract boolean include(TreeWalk walker)
200 			throws MissingObjectException, IncorrectObjectTypeException,
201 			IOException;
202 
203 	/**
204 	 * Determine if the current entry is a parent, a match, or no match.
205 	 * <p>
206 	 * This method extends the result returned by {@link #include(TreeWalk)}
207 	 * with a third option (-1), splitting the value true. This gives the
208 	 * application a possibility to distinguish between an exact match and the
209 	 * case when a subtree to the current entry might be a match.
210 	 *
211 	 * @param walker
212 	 *            the walker the filter needs to examine.
213 	 * @return -1 if the current entry is a parent of the filter but no exact
214 	 *         match has been made; 0 if the current entry should be seen by the
215 	 *         application; 1 if it should be hidden.
216 	 * @throws org.eclipse.jgit.errors.MissingObjectException
217 	 *             as thrown by {@link #include(TreeWalk)}
218 	 * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
219 	 *             as thrown by {@link #include(TreeWalk)}
220 	 * @throws java.io.IOException
221 	 *             as thrown by {@link #include(TreeWalk)}
222 	 * @since 4.7
223 	 */
224 	public int matchFilter(TreeWalk walker)
225 			throws MissingObjectException, IncorrectObjectTypeException,
226 			IOException
227 	{
228 		return include(walker) ? 0 : 1;
229 	}
230 
231 	/**
232 	 * Does this tree filter require a recursive walk to match everything?
233 	 * <p>
234 	 * If this tree filter is matching on full entry path names and its pattern
235 	 * is looking for a '/' then the filter would require a recursive TreeWalk
236 	 * to accurately make its decisions. The walker is not required to enable
237 	 * recursive behavior for any particular filter, this is only a hint.
238 	 *
239 	 * @return true if the filter would like to have the walker recurse into
240 	 *         subtrees to make sure it matches everything correctly; false if
241 	 *         the filter does not require entering subtrees.
242 	 */
243 	public abstract boolean shouldBeRecursive();
244 
245 	/**
246 	 * {@inheritDoc}
247 	 *
248 	 * Clone this tree filter, including its parameters.
249 	 * <p>
250 	 * This is a deep clone. If this filter embeds objects or other filters it
251 	 * must also clone those, to ensure the instances do not share mutable data.
252 	 */
253 	@Override
254 	public abstract TreeFilter clone();
255 
256 	/** {@inheritDoc} */
257 	@Override
258 	public String toString() {
259 		String n = getClass().getName();
260 		int lastDot = n.lastIndexOf('.');
261 		if (lastDot >= 0) {
262 			n = n.substring(lastDot + 1);
263 		}
264 		return n.replace('$', '.');
265 	}
266 }