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 }