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 }