blob: 097e17dc2eae394dccc2b247e61178eeec807f55 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.freemarker.generator.base.file;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.io.filefilter.OrFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.io.FileUtils.listFiles;
import static org.apache.commons.io.filefilter.HiddenFileFilter.HIDDEN;
import static org.apache.commons.io.filefilter.HiddenFileFilter.VISIBLE;
import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty;
/**
* Resolve a list of files or directories recursively.
*
* <ul>
* <li>Matching a list of include patterns</li>
* <li>Matching a list of exclude patterns</li>
* <li>Ignoring invisible files and directories</li>
* </ul>
*/
public class RecursiveFileSupplier implements Supplier<List<File>> {
/** List of sources containing files and directories */
private final Collection<String> sources;
/** File filter to apply */
private final IOFileFilter fileFilter;
/** Diectory filter to apply */
private final IOFileFilter directoryFilter;
public RecursiveFileSupplier(Collection<String> sources, Collection<String> includes, Collection<String> excludes) {
this.sources = sources;
this.fileFilter = fileFilter(includes, excludes);
this.directoryFilter = directoryFilter();
}
@Override
public List<File> get() {
if (sources == null || sources.isEmpty()) {
return emptyList();
}
return sources.stream()
.map(this::resolve)
.flatMap(Collection::stream)
.collect(toList());
}
private List<File> resolve(String source) {
final File file = new File(source);
if (file.isFile()) {
return resolveFile(file);
} else if (file.isDirectory()) {
return new ArrayList<>(resolveDirectory(file));
} else {
throw new IllegalArgumentException("Unable to find source: " + source);
}
}
private List<File> resolveFile(File file) {
return fileFilter.accept(file) ? singletonList(file) : emptyList();
}
private List<File> resolveDirectory(File directory) {
return new ArrayList<>(listFiles(directory, fileFilter, directoryFilter));
}
private static IOFileFilter fileFilter(Collection<String> includes, Collection<String> excludes) {
final List<IOFileFilter> fileFilters = new ArrayList<>();
fileFilters.addAll(includeFilters(includes));
fileFilters.addAll(excludeFilters(excludes));
return new AndFileFilter(fileFilters);
}
private static List<IOFileFilter> includeFilters(Collection<String> includes) {
if (includes == null || includes.isEmpty()) {
return emptyList();
}
return includes.stream().map(RecursiveFileSupplier::includeFilter).collect(toList());
}
private static IOFileFilter includeFilter(String include) {
return isEmpty(include) ? VISIBLE : new AndFileFilter(new WildcardFileFilter(include), VISIBLE);
}
private static List<IOFileFilter> excludeFilters(Collection<String> excludes) {
if (excludes == null || excludes.isEmpty()) {
return emptyList();
}
return excludes.stream().map(RecursiveFileSupplier::exludeFilter).collect(toList());
}
private static IOFileFilter exludeFilter(String exclude) {
return isEmpty(exclude) ?
VISIBLE :
new NotFileFilter(new OrFileFilter(new WildcardFileFilter(exclude), HIDDEN));
}
private static IOFileFilter directoryFilter() {
return VISIBLE;
}
}