// Copyright 2014 The Bazel Authors. All rights reserved. // // 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 com.google.devtools.build.lib.util; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.annotation.concurrent.Immutable; /** A base class for FileType matchers. */ @Immutable public abstract class FileType implements Predicate { // A special file type @AutoCodec @VisibleForSerialization public static final FileType NO_EXTENSION = new FileType() { @Override public boolean apply(String path) { int lastSlashIndex = path.lastIndexOf('/'); return path.indexOf('.', lastSlashIndex + 1) == -1; } }; public static FileType of(final String ext) { return new SingletonFileType(ext); } @AutoCodec.VisibleForSerialization @AutoCodec static final class SingletonFileType extends FileType { private final String ext; @AutoCodec.VisibleForSerialization SingletonFileType(String ext) { this.ext = ext; } @Override public boolean apply(String path) { return path.endsWith(ext); } @Override public List getExtensions() { return ImmutableList.of(ext); } } public static FileType of(final List extensions) { return new ListFileType(ImmutableList.copyOf(extensions)); } @AutoCodec.VisibleForSerialization @AutoCodec static final class ListFileType extends FileType { private final ImmutableList extensions; @AutoCodec.VisibleForSerialization ListFileType(ImmutableList extensions) { this.extensions = Preconditions.checkNotNull(extensions); } @Override public boolean apply(String path) { for (String ext : extensions) { if (path.endsWith(ext)) { return true; } } return false; } @Override public List getExtensions() { return ImmutableList.copyOf(extensions); } @Override public int hashCode() { return extensions.hashCode(); } @Override public boolean equals(Object obj) { return (obj instanceof ListFileType && this.extensions.equals(((ListFileType) obj).extensions)); } } public static FileType of(final String... extensions) { return of(Arrays.asList(extensions)); } @Override public String toString() { return getExtensions().toString(); } /** Returns true if the file matches. Subclasses are expected to handle a full path. */ @Override public abstract boolean apply(String path); /** * Get a list of filename extensions this matcher handles. The first entry in the list (if * available) is the primary extension that code can use to construct output file names. * The list can be empty for some matchers. * * @return a list of filename extensions */ public List getExtensions() { return ImmutableList.of(); } /** Return true if a file path is matched by this FileType */ @Deprecated public boolean matches(String path) { return apply(path); } /** Return true if the item is matched by this FileType */ public boolean matches(HasFileType item) { return apply(item.filePathForFileTypeMatcher()); } // Check FileTypes /** An interface for entities that have a file type. */ public interface HasFileType { /** * Return a file path that ends with the file name. * *

The path will be used by {@link FileType} for matching. An example valid implementation * could return the full path of the file, or just the file name, depending on what can * efficiently be provided. */ String filePathForFileTypeMatcher(); } /** * Checks whether an Iterable contains any of the specified file types. * *

At least one FileType must be specified. */ public static boolean contains( final Iterable items, FileType... fileTypes) { Preconditions.checkState(fileTypes.length > 0, "Must specify at least one file type"); final FileTypeSet fileTypeSet = FileTypeSet.of(fileTypes); for (T item : items) { if (fileTypeSet.matches(item.filePathForFileTypeMatcher())) { return true; } } return false; } /** * Checks whether a HasFileType is any of the specified file types. * *

At least one FileType must be specified. */ public static boolean contains(T item, FileType... fileTypes) { return FileTypeSet.of(fileTypes).matches(item.filePathForFileTypeMatcher()); } private static Predicate typeMatchingPredicateFor( final FileType matchingType) { return item -> matchingType.matches(item.filePathForFileTypeMatcher()); } private static Predicate typeMatchingPredicateFor( final FileTypeSet matchingTypes) { return item -> matchingTypes.matches(item.filePathForFileTypeMatcher()); } private static Predicate typeMatchingPredicateFrom( final Predicate fileTypePredicate) { return item -> fileTypePredicate.apply(item.filePathForFileTypeMatcher()); } /** * A filter for Iterable that returns only those whose FileType matches the * specified Predicate. */ public static Iterable filter( final Iterable items, final Predicate predicate) { return Iterables.filter(items, typeMatchingPredicateFrom(predicate)); } /** * A filter for Iterable that returns only those of the specified file * types. */ public static Iterable filter( final Iterable items, FileType... fileTypes) { return filter(items, FileTypeSet.of(fileTypes)); } /** * A filter for Iterable that returns only those of the specified file * types. */ public static Iterable filter( final Iterable items, FileTypeSet fileTypes) { return Iterables.filter(items, typeMatchingPredicateFor(fileTypes)); } /** * A filter for Iterable that returns only those of the specified file * type. */ public static Iterable filter( final Iterable items, FileType fileType) { return Iterables.filter(items, typeMatchingPredicateFor(fileType)); } /** * A filter for Iterable that returns everything except the specified file * type. */ public static Iterable except( final Iterable items, FileType fileType) { return Iterables.filter(items, Predicates.not(typeMatchingPredicateFor(fileType))); } /** * A filter for List that returns only those of the specified file types. * The result is a mutable list, computed eagerly; see {@link #filter} for a lazy variant. */ public static List filterList( final Iterable items, FileType... fileTypes) { if (fileTypes.length > 0) { return filterList(items, FileTypeSet.of(fileTypes)); } else { return new ArrayList<>(); } } /** * A filter for List that returns only those of the specified file type. * The result is a mutable list, computed eagerly. */ public static List filterList( final Iterable items, final FileType fileType) { List result = new ArrayList<>(); for (T item : items) { if (fileType.matches(item.filePathForFileTypeMatcher())) { result.add(item); } } return result; } /** * A filter for List that returns only those of the specified file types. * The result is a mutable list, computed eagerly. */ public static List filterList( final Iterable items, final FileTypeSet fileTypeSet) { List result = new ArrayList<>(); for (T item : items) { if (fileTypeSet.matches(item.filePathForFileTypeMatcher())) { result.add(item); } } return result; } }