/* * Copyright 2009 the original author or authors. * * Licensed 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.gradle.api.internal.file; import groovy.lang.Closure; import org.gradle.api.Buildable; import org.gradle.api.InvalidUserDataException; import org.gradle.api.file.DirectoryTree; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTreeElement; import org.gradle.api.file.SourceDirectorySet; import org.gradle.api.internal.file.collections.DirectoryFileTree; import org.gradle.api.internal.file.collections.DirectoryFileTreeFactory; import org.gradle.api.internal.file.collections.FileCollectionAdapter; import org.gradle.api.internal.file.collections.FileCollectionResolveContext; import org.gradle.api.internal.file.collections.MinimalFileSet; import org.gradle.api.internal.provider.DefaultProviderFactory; import org.gradle.api.internal.tasks.TaskDependencyResolveContext; import org.gradle.api.provider.PropertyState; import org.gradle.api.provider.Provider; import org.gradle.api.provider.ProviderFactory; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.TaskDependency; import org.gradle.api.tasks.util.PatternFilterable; import org.gradle.api.tasks.util.PatternSet; import org.gradle.util.GUtil; import java.io.File; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; public class DefaultSourceDirectorySet extends CompositeFileTree implements SourceDirectorySet { private final List<Object> source = new ArrayList<Object>(); private final String name; private final String displayName; private final FileResolver fileResolver; private final DirectoryFileTreeFactory directoryFileTreeFactory; private final PatternSet patterns; private final PatternSet filter; private final FileCollection dirs; private final PropertyState<File> outputDir; public DefaultSourceDirectorySet(String name, String displayName, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory) { this.name = name; this.displayName = displayName; this.fileResolver = fileResolver; this.directoryFileTreeFactory = directoryFileTreeFactory; this.patterns = fileResolver.getPatternSetFactory().create(); this.filter = fileResolver.getPatternSetFactory().create(); this.dirs = new FileCollectionAdapter(new SourceDirectories()); ProviderFactory providerFactory = new DefaultProviderFactory(); this.outputDir = providerFactory.property(File.class); } public DefaultSourceDirectorySet(String name, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory) { this(name, name, fileResolver, directoryFileTreeFactory); } public String getName() { return this.name; } @Override public FileCollection getSourceDirectories() { return dirs; } public Set<File> getSrcDirs() { Set<File> dirs = new LinkedHashSet<File>(); for (DirectoryTree tree : getSrcDirTrees()) { dirs.add(tree.getDir()); } return dirs; } public Set<String> getIncludes() { return patterns.getIncludes(); } public Set<String> getExcludes() { return patterns.getExcludes(); } public PatternFilterable setIncludes(Iterable<String> includes) { patterns.setIncludes(includes); return this; } public PatternFilterable setExcludes(Iterable<String> excludes) { patterns.setExcludes(excludes); return this; } public PatternFilterable include(String... includes) { patterns.include(includes); return this; } public PatternFilterable include(Iterable<String> includes) { patterns.include(includes); return this; } public PatternFilterable include(Spec<FileTreeElement> includeSpec) { patterns.include(includeSpec); return this; } public PatternFilterable include(Closure includeSpec) { patterns.include(includeSpec); return this; } public PatternFilterable exclude(Iterable<String> excludes) { patterns.exclude(excludes); return this; } public PatternFilterable exclude(String... excludes) { patterns.exclude(excludes); return this; } public PatternFilterable exclude(Spec<FileTreeElement> excludeSpec) { patterns.exclude(excludeSpec); return this; } public PatternFilterable exclude(Closure excludeSpec) { patterns.exclude(excludeSpec); return this; } public PatternFilterable getFilter() { return filter; } @Override public File getOutputDir() { return outputDir.get(); } @Override public void setOutputDir(Provider<File> provider) { this.outputDir.set(provider); } @Override public void setOutputDir(File outputDir) { this.outputDir.set(outputDir); } public Set<DirectoryTree> getSrcDirTrees() { // This implementation is broken. It does not consider include and exclude patterns Map<File, DirectoryTree> trees = new LinkedHashMap<File, DirectoryTree>(); for (DirectoryTree tree : doGetSrcDirTrees()) { if (!trees.containsKey(tree.getDir())) { trees.put(tree.getDir(), tree); } } return new LinkedHashSet<DirectoryTree>(trees.values()); } private Set<DirectoryTree> doGetSrcDirTrees() { Set<DirectoryTree> result = new LinkedHashSet<DirectoryTree>(); for (Object path : source) { if (path instanceof SourceDirectorySet) { SourceDirectorySet nested = (SourceDirectorySet) path; result.addAll(nested.getSrcDirTrees()); } else { for (File srcDir : fileResolver.resolveFiles(path)) { if (srcDir.exists() && !srcDir.isDirectory()) { throw new InvalidUserDataException(String.format("Source directory '%s' is not a directory.", srcDir)); } result.add(directoryFileTreeFactory.create(srcDir, patterns)); } } } return result; } @Override public void visitDependencies(TaskDependencyResolveContext context) { for (Object path : source) { if (path instanceof SourceDirectorySet) { context.add(((SourceDirectorySet) path).getBuildDependencies()); } else { context.add(fileResolver.resolveFiles(path)); } } } @Override public void visitContents(FileCollectionResolveContext context) { for (DirectoryTree directoryTree : doGetSrcDirTrees()) { context.add(((DirectoryFileTree) directoryTree).filter(filter)); } } @Override public String getDisplayName() { return displayName; } public SourceDirectorySet srcDir(Object srcDir) { source.add(srcDir); return this; } public SourceDirectorySet srcDirs(Object... srcDirs) { for (Object srcDir : srcDirs) { source.add(srcDir); } return this; } public SourceDirectorySet setSrcDirs(Iterable<?> srcPaths) { source.clear(); GUtil.addToCollection(source, srcPaths); return this; } public SourceDirectorySet source(SourceDirectorySet source) { this.source.add(source); return this; } private class SourceDirectories implements MinimalFileSet, Buildable { @Override public TaskDependency getBuildDependencies() { return DefaultSourceDirectorySet.this.getBuildDependencies(); } @Override public Set<File> getFiles() { return getSrcDirs(); } @Override public String getDisplayName() { return displayName; } } }