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 }