1 package org.codehaus.plexus.components.io.fileselectors;
2
3 /*
4 * Copyright 2007 The Codehaus Foundation.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 import javax.annotation.Nonnull;
20 import javax.annotation.Nullable;
21 import javax.inject.Named;
22
23 import java.io.File;
24
25 import org.codehaus.plexus.util.FileUtils;
26 import org.codehaus.plexus.util.MatchPatterns;
27 import org.codehaus.plexus.util.SelectorUtils;
28
29 /**
30 * This file selector uses a set of patterns for including/excluding
31 * files.
32 */
33 @Named(IncludeExcludeFileSelector.ROLE_HINT)
34 public class IncludeExcludeFileSelector implements FileSelector {
35 /**
36 * The include/exclude file selectors role-hint: "standard".
37 */
38 public static final String ROLE_HINT = "standard";
39
40 private static final MatchPatterns ALL_INCLUDES = MatchPatterns.from(getCanonicalName("**/*"));
41
42 private static final MatchPatterns ZERO_EXCLUDES = MatchPatterns.from();
43
44 private boolean isCaseSensitive = true;
45
46 private boolean useDefaultExcludes = true;
47
48 private String[] includes;
49
50 private String[] excludes;
51
52 private MatchPatterns computedIncludes = ALL_INCLUDES;
53
54 private MatchPatterns computedExcludes = ZERO_EXCLUDES;
55
56 /**
57 * Tests whether or not a name matches against at least one exclude
58 * pattern.
59 *
60 * @param name The name to match. Must not be <code>null</code>.
61 * @return <code>true</code> when the name matches against at least one
62 * exclude pattern, or <code>false</code> otherwise.
63 */
64 protected boolean isExcluded(@Nonnull String name) {
65 return computedExcludes.matches(name, isCaseSensitive);
66 }
67
68 /**
69 * Sets the list of include patterns to use. All '/' and '\' characters
70 * are replaced by <code>File.separatorChar</code>, so the separator used
71 * need not match <code>File.separatorChar</code>.
72 * <p>
73 * When a pattern ends with a '/' or '\', "**" is appended.
74 *
75 * @param includes A list of include patterns.
76 * May be <code>null</code>, indicating that all files
77 * should be included. If a non-<code>null</code>
78 * list is given, all elements must be
79 * non-<code>null</code>.
80 */
81 public void setIncludes(@Nullable String[] includes) {
82 this.includes = includes;
83 if (includes == null) {
84 computedIncludes = ALL_INCLUDES;
85 } else {
86 String[] cleaned;
87 cleaned = new String[includes.length];
88 for (int i = 0; i < includes.length; i++) {
89 cleaned[i] = asPattern(includes[i]);
90 }
91 computedIncludes = MatchPatterns.from(cleaned);
92 }
93 }
94
95 private static @Nonnull String getCanonicalName(@Nonnull String pName) {
96 return pName.replace('/', File.separatorChar).replace('\\', File.separatorChar);
97 }
98
99 private String asPattern(@Nonnull String pPattern) {
100 String pattern = getCanonicalName(pPattern.trim());
101 if (pattern.endsWith(File.separator)) {
102 pattern += "**";
103 }
104 return pattern;
105 }
106
107 /**
108 * Returns the list of include patterns to use.
109 *
110 * @return A list of include patterns.
111 * May be <code>null</code>, indicating that all files
112 * should be included. If a non-<code>null</code>
113 * list is given, all elements must be
114 * non-<code>null</code>.
115 */
116 public @Nullable String[] getIncludes() {
117 return includes;
118 }
119
120 /**
121 * Sets the list of exclude patterns to use. All '/' and '\' characters
122 * are replaced by <code>File.separatorChar</code>, so the separator used
123 * need not match <code>File.separatorChar</code>.
124 * <p>
125 * When a pattern ends with a '/' or '\', "**" is appended.
126 *
127 * @param excludes A list of exclude patterns.
128 * May be <code>null</code>, indicating that no files
129 * should be excluded. If a non-<code>null</code> list is
130 * given, all elements must be non-<code>null</code>.
131 */
132 public void setExcludes(@Nullable String[] excludes) {
133 this.excludes = excludes;
134 final String[] defaultExcludes = useDefaultExcludes ? FileUtils.getDefaultExcludes() : new String[] {};
135 if (excludes == null) {
136 computedExcludes = MatchPatterns.from(defaultExcludes);
137 } else {
138 String[] temp = new String[excludes.length + defaultExcludes.length];
139 for (int i = 0; i < excludes.length; i++) {
140 temp[i] = asPattern(excludes[i]);
141 }
142
143 if (defaultExcludes.length > 0) {
144 System.arraycopy(defaultExcludes, 0, temp, excludes.length, defaultExcludes.length);
145 }
146 computedExcludes = MatchPatterns.from(temp);
147 }
148 }
149
150 /**
151 * Returns the list of exclude patterns to use.
152 *
153 * @return A list of exclude patterns.
154 * May be <code>null</code>, indicating that no files
155 * should be excluded. If a non-<code>null</code> list is
156 * given, all elements must be non-<code>null</code>.
157 */
158 public @Nullable String[] getExcludes() {
159 return excludes;
160 }
161
162 /**
163 * Tests, whether the given pattern is matching the given name.
164 * @param pattern The pattern to match
165 * @param name The name to test
166 * @param isCaseSensitive Whether the pattern is case sensitive.
167 * @return True, if the pattern matches, otherwise false
168 */
169 protected boolean matchPath(@Nonnull String pattern, @Nonnull String name, boolean isCaseSensitive) {
170 return SelectorUtils.matchPath(pattern, name, isCaseSensitive);
171 }
172
173 /**
174 * Tests whether or not a name matches against at least one include
175 * pattern.
176 *
177 * @param name The name to match. Must not be <code>null</code>.
178 * @return <code>true</code> when the name matches against at least one
179 * include pattern, or <code>false</code> otherwise.
180 */
181 protected boolean isIncluded(@Nonnull String name) {
182 return computedIncludes.matches(name, isCaseSensitive);
183 }
184
185 public boolean isSelected(@Nonnull FileInfo fileInfo) {
186 final String name = getCanonicalName(fileInfo.getName());
187 return isIncluded(name) && !isExcluded(name);
188 }
189
190 /**
191 * Returns, whether the include/exclude patterns are case sensitive.
192 * @return True, if the patterns are case sensitive (default), or false.
193 */
194 public boolean isCaseSensitive() {
195 return isCaseSensitive;
196 }
197
198 /**
199 * Sets, whether the include/exclude patterns are case sensitive.
200 * @param caseSensitive True, if the patterns are case sensitive (default), or false.
201 */
202 public void setCaseSensitive(boolean caseSensitive) {
203 isCaseSensitive = caseSensitive;
204 }
205
206 /**
207 * Returns, whether to use the default excludes, as specified by
208 * {@link FileUtils#getDefaultExcludes()}.
209 */
210 public boolean isUseDefaultExcludes() {
211 return useDefaultExcludes;
212 }
213
214 /**
215 * Sets, whether to use the default excludes, as specified by
216 * {@link FileUtils#getDefaultExcludes()}.
217 */
218 public void setUseDefaultExcludes(boolean pUseDefaultExcludes) {
219 useDefaultExcludes = pUseDefaultExcludes;
220 setExcludes(excludes);
221 }
222 }