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: {@link PathFilter}</li>
71   * </ul>
72   *
73   * <p>
74   * <b>Difference filters:</b>
75   * <ul>
76   * <li>Only select differences: {@link #ANY_DIFF}.</li>
77   * </ul>
78   *
79   * <p>
80   * <b>Boolean modifiers:</b>
81   * <ul>
82   * <li>AND: {@link AndTreeFilter}</li>
83   * <li>OR: {@link OrTreeFilter}</li>
84   * <li>NOT: {@link NotTreeFilter}</li>
85   * </ul>
86   */
87  public abstract class TreeFilter {
88  	/** Selects all tree entries. */
89  	public static final TreeFilter ALL = new AllFilter();
90  
91  	private static final class AllFilter extends TreeFilter {
92  		@Override
93  		public boolean include(final TreeWalk walker) {
94  			return true;
95  		}
96  
97  		@Override
98  		public boolean shouldBeRecursive() {
99  			return false;
100 		}
101 
102 		@Override
103 		public TreeFilter clone() {
104 			return this;
105 		}
106 
107 		@Override
108 		public String toString() {
109 			return "ALL"; //$NON-NLS-1$
110 		}
111 	}
112 
113 	/**
114 	 * Selects only tree entries which differ between at least 2 trees.
115 	 * <p>
116 	 * This filter also prevents a TreeWalk from recursing into a subtree if all
117 	 * parent trees have the identical subtree at the same path. This
118 	 * dramatically improves walk performance as only the changed subtrees are
119 	 * entered into.
120 	 * <p>
121 	 * If this filter is applied to a walker with only one tree it behaves like
122 	 * {@link #ALL}, or as though the walker was matching a virtual empty tree
123 	 * against the single tree it was actually given. Applications may wish to
124 	 * treat such a difference as "all names added".
125 	 * <p>
126 	 * When comparing {@link WorkingTreeIterator} and {@link DirCacheIterator}
127 	 * applications should use {@link IndexDiffFilter}.
128 	 */
129 	public static final TreeFilter ANY_DIFF = new AnyDiffFilter();
130 
131 	private static final class AnyDiffFilter extends TreeFilter {
132 		private static final int baseTree = 0;
133 
134 		@Override
135 		public boolean include(final TreeWalk walker) {
136 			final int n = walker.getTreeCount();
137 			if (n == 1) // Assume they meant difference to empty tree.
138 				return true;
139 
140 			final int m = walker.getRawMode(baseTree);
141 			for (int i = 1; i < n; i++)
142 				if (walker.getRawMode(i) != m || !walker.idEqual(i, baseTree))
143 					return true;
144 			return false;
145 		}
146 
147 		@Override
148 		public boolean shouldBeRecursive() {
149 			return false;
150 		}
151 
152 		@Override
153 		public TreeFilter clone() {
154 			return this;
155 		}
156 
157 		@Override
158 		public String toString() {
159 			return "ANY_DIFF"; //$NON-NLS-1$
160 		}
161 	}
162 
163 	/**
164 	 * Create a new filter that does the opposite of this filter.
165 	 *
166 	 * @return a new filter that includes tree entries this filter rejects.
167 	 */
168 	public TreeFilter negate() {
169 		return NotTreeFilter.create(this);
170 	}
171 
172 	/**
173 	 * Determine if the current entry is interesting to report.
174 	 * <p>
175 	 * This method is consulted for subtree entries even if
176 	 * {@link TreeWalk#isRecursive()} is enabled. The consultation allows the
177 	 * filter to bypass subtree recursion on a case-by-case basis, even when
178 	 * recursion is enabled at the application level.
179 	 *
180 	 * @param walker
181 	 *            the walker the filter needs to examine.
182 	 * @return true if the current entry should be seen by the application;
183 	 *         false to hide the entry.
184 	 * @throws MissingObjectException
185 	 *             an object the filter needs to consult to determine its answer
186 	 *             does not exist in the Git repository the walker is operating
187 	 *             on. Filtering this current walker entry is impossible without
188 	 *             the object.
189 	 * @throws IncorrectObjectTypeException
190 	 *             an object the filter needed to consult was not of the
191 	 *             expected object type. This usually indicates a corrupt
192 	 *             repository, as an object link is referencing the wrong type.
193 	 * @throws IOException
194 	 *             a loose object or pack file could not be read to obtain data
195 	 *             necessary for the filter to make its decision.
196 	 */
197 	public abstract boolean include(TreeWalk walker)
198 			throws MissingObjectException, IncorrectObjectTypeException,
199 			IOException;
200 
201 	/**
202 	 * Does this tree filter require a recursive walk to match everything?
203 	 * <p>
204 	 * If this tree filter is matching on full entry path names and its pattern
205 	 * is looking for a '/' then the filter would require a recursive TreeWalk
206 	 * to accurately make its decisions. The walker is not required to enable
207 	 * recursive behavior for any particular filter, this is only a hint.
208 	 *
209 	 * @return true if the filter would like to have the walker recurse into
210 	 *         subtrees to make sure it matches everything correctly; false if
211 	 *         the filter does not require entering subtrees.
212 	 */
213 	public abstract boolean shouldBeRecursive();
214 
215 	/**
216 	 * Clone this tree filter, including its parameters.
217 	 * <p>
218 	 * This is a deep clone. If this filter embeds objects or other filters it
219 	 * must also clone those, to ensure the instances do not share mutable data.
220 	 *
221 	 * @return another copy of this filter, suitable for another thread.
222 	 */
223 	public abstract TreeFilter clone();
224 
225 	@Override
226 	public String toString() {
227 		String n = getClass().getName();
228 		int lastDot = n.lastIndexOf('.');
229 		if (lastDot >= 0) {
230 			n = n.substring(lastDot + 1);
231 		}
232 		return n.replace('$', '.');
233 	}
234 }