| // 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.cmdline; | |
| import static com.google.common.util.concurrent.Futures.immediateCancelledFuture; | |
| import static com.google.common.util.concurrent.Futures.immediateFailedFuture; | |
| import static com.google.common.util.concurrent.Futures.immediateVoidFuture; | |
| import com.google.common.collect.ImmutableSet; | |
| import com.google.common.util.concurrent.ListenableFuture; | |
| import com.google.common.util.concurrent.ListeningExecutorService; | |
| import com.google.devtools.build.lib.io.InconsistentFilesystemException; | |
| import com.google.devtools.build.lib.io.ProcessPackageDirectoryException; | |
| import com.google.devtools.build.lib.vfs.PathFragment; | |
| import java.util.Collection; | |
| /** | |
| * A callback that is used during the process of converting target patterns (such as <code>//foo:all | |
| * </code>) into one or more lists of targets (such as <code>//foo:foo, | |
| * //foo:bar</code>). During a call to {@link TargetPattern#eval}, the {@link TargetPattern} makes | |
| * calls to this interface to implement the target pattern semantics. The generic type {@code T} is | |
| * only for compile-time type safety; there are no requirements to the actual type. | |
| */ | |
| public abstract class TargetPatternResolver<T> { | |
| /** Reports the given warning. */ | |
| public abstract void warn(String msg); | |
| /** | |
| * Returns a single target corresponding to the given label, or null. This method may only throw | |
| * an exception if the current thread was interrupted. | |
| */ | |
| public abstract T getTargetOrNull(Label label) | |
| throws InterruptedException, InconsistentFilesystemException; | |
| /** Returns a single target corresponding to the given label, or an empty or failed result. */ | |
| public abstract ResolvedTargets<T> getExplicitTarget(Label label) | |
| throws TargetParsingException, InterruptedException; | |
| /** | |
| * Returns the set containing the targets found in the given package. The specified directory is | |
| * not necessarily a valid package name. If {@code rulesOnly} is true, then this method should | |
| * only return rules in the given package. | |
| * | |
| * @param originalPattern the original target pattern for error reporting purposes | |
| * @param packageIdentifier the identifier of the package | |
| * @param rulesOnly whether to return rules only | |
| */ | |
| public abstract Collection<T> getTargetsInPackage( | |
| String originalPattern, PackageIdentifier packageIdentifier, boolean rulesOnly) | |
| throws TargetParsingException, InterruptedException; | |
| /** | |
| * Computes the set containing the targets found below the given {@code directory}, passing it in | |
| * batches to {@code callback}. Conceptually, this method should look for all packages that start | |
| * with the {@code directory} (as a proper prefix directory, i.e., "foo/ba" is not a proper prefix | |
| * of "foo/bar/"), and then collect all targets in each such package (subject to {@code | |
| * rulesOnly}) as if calling {@link #getTargetsInPackage}. The specified directory is not | |
| * necessarily a valid package name. | |
| * | |
| * <p>Note that the {@code directory} can be empty, which corresponds to the "//..." pattern. | |
| * Implementations may choose not to support this case and throw an {@link | |
| * IllegalArgumentException} exception instead, or may restrict the set of directories that are | |
| * considered by default. | |
| * | |
| * <p>If the {@code directory} points to a package, then that package should also be part of the | |
| * result. | |
| * | |
| * @param originalPattern the original target pattern for error reporting purposes | |
| * @param directory the directory in which to look for packages | |
| * @param rulesOnly whether to return rules only | |
| * @param forbiddenSubdirectories a set of transitive subdirectories beneath {@code directory} to | |
| * ignore | |
| * @param excludedSubdirectories another set of transitive subdirectories beneath {@code | |
| * directory} to ignore | |
| * @param callback the callback to receive the result, possibly in multiple batches. | |
| * @param exceptionClass The class type of the parameterized exception. | |
| * @throws TargetParsingException under implementation-specific failure conditions | |
| * @throws ProcessPackageDirectoryException only when called from within Skyframe and an | |
| * inconsistent filesystem state is observed | |
| */ | |
| public abstract <E extends Exception & QueryExceptionMarkerInterface> | |
| void findTargetsBeneathDirectory( | |
| RepositoryName repository, | |
| String originalPattern, | |
| String directory, | |
| boolean rulesOnly, | |
| IgnoredSubdirectories forbiddenSubdirectories, | |
| ImmutableSet<PathFragment> excludedSubdirectories, | |
| BatchCallback<T, E> callback, | |
| Class<E> exceptionClass) | |
| throws TargetParsingException, E, InterruptedException, ProcessPackageDirectoryException; | |
| /** | |
| * Async version of {@link #findTargetsBeneathDirectory}. Never call this from within Skyframe | |
| * evaluation. | |
| * | |
| * <p>Default implementation is synchronous. | |
| */ | |
| public <E extends Exception & QueryExceptionMarkerInterface> | |
| ListenableFuture<Void> findTargetsBeneathDirectoryAsync( | |
| RepositoryName repository, | |
| String originalPattern, | |
| String directory, | |
| boolean rulesOnly, | |
| IgnoredSubdirectories forbiddenSubdirectories, | |
| ImmutableSet<PathFragment> excludedSubdirectories, | |
| BatchCallback<T, E> callback, | |
| Class<E> exceptionClass, | |
| ListeningExecutorService executor) { | |
| try { | |
| findTargetsBeneathDirectory( | |
| repository, | |
| originalPattern, | |
| directory, | |
| rulesOnly, | |
| forbiddenSubdirectories, | |
| excludedSubdirectories, | |
| callback, | |
| exceptionClass); | |
| return immediateVoidFuture(); | |
| } catch (TargetParsingException e) { | |
| return immediateFailedFuture(e); | |
| } catch (InterruptedException e) { | |
| return immediateCancelledFuture(); | |
| } catch (ProcessPackageDirectoryException e) { | |
| throw new IllegalStateException( | |
| "Async find targets beneath directory isn't called from within Skyframe: traversing " | |
| + directory | |
| + " for " | |
| + originalPattern, | |
| e); | |
| } catch (Exception e) { | |
| if (exceptionClass.isInstance(e)) { | |
| return immediateFailedFuture(e); | |
| } | |
| throw new IllegalStateException(e); | |
| } | |
| } | |
| /** | |
| * Returns true, if and only if the given package identifier corresponds to a package, i.e., a | |
| * file with the name {@code packageName/BUILD} exists in the appropriate repository. | |
| */ | |
| public abstract boolean isPackage(PackageIdentifier packageIdentifier) | |
| throws InterruptedException, InconsistentFilesystemException; | |
| /** Returns the target kind of the given target, for example {@code cc_library rule}. */ | |
| public abstract String getTargetKind(T target); | |
| } |