blob: 5531c21bcc61176bd50f5acc081da1e9dc369694 [file] [log] [blame]
/*
* Copyright 2017 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.idea.blaze.base.sync.sharding;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.idea.blaze.base.async.FutureUtil;
import com.google.idea.blaze.base.async.FutureUtil.FutureResult;
import com.google.idea.blaze.base.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.io.FileAttributeProvider;
import com.google.idea.blaze.base.model.primitives.TargetExpression;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.prefetch.FetchExecutor;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
import com.google.idea.blaze.base.util.WorkspacePathUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
/**
* Traverses blaze packages specified by wildcard target patterns, expanding to a set of
* single-package target patterns.
*/
class PackageLister {
private PackageLister() {}
/** The set of blaze packages to prefetch prior to traversing the directory tree. */
static Set<File> getDirectoriesToPrefetch(
WorkspacePathResolver pathResolver,
Collection<WildcardTargetPattern> includes,
Predicate<WorkspacePath> excluded) {
Set<WorkspacePath> prefetchPaths = new HashSet<>();
for (WildcardTargetPattern pattern : includes) {
WorkspacePath workspacePath = pattern.getBasePackage();
if (excluded.test(workspacePath)) {
continue;
}
prefetchPaths.add(workspacePath);
}
return WorkspacePathUtil.calculateMinimalWorkspacePaths(prefetchPaths)
.stream()
.map(pathResolver::resolveToFile)
.collect(Collectors.toSet());
}
/**
* Expands all-in-package-recursive wildcard targets into all-in-single-package targets by
* traversing the file system, looking for child blaze packages.
*
* <p>Returns null if directory traversal failed or was cancelled.
*/
@Nullable
static Map<TargetExpression, List<TargetExpression>> expandPackageTargets(
BuildSystemProvider provider,
BlazeContext context,
WorkspacePathResolver pathResolver,
Collection<WildcardTargetPattern> wildcardPatterns) {
List<ListenableFuture<Entry<TargetExpression, List<TargetExpression>>>> futures =
Lists.newArrayList();
for (WildcardTargetPattern pattern : wildcardPatterns) {
if (!pattern.isRecursive() || pattern.toString().startsWith("-")) {
continue;
}
File dir = pathResolver.resolveToFile(pattern.getBasePackage());
if (!FileAttributeProvider.getInstance().isDirectory(dir)) {
continue;
}
futures.add(
FetchExecutor.EXECUTOR.submit(
() -> {
List<TargetExpression> expandedTargets = new ArrayList<>();
traversePackageRecursively(provider, pathResolver, dir, expandedTargets);
return Maps.immutableEntry(pattern.originalPattern, expandedTargets);
}));
}
if (futures.isEmpty()) {
return ImmutableMap.of();
}
FutureResult<List<Entry<TargetExpression, List<TargetExpression>>>> result =
FutureUtil.waitForFuture(context, Futures.allAsList(futures))
.withProgressMessage("Expanding wildcard target patterns...")
.timed("ExpandWildcardTargets")
.onError("Expanding wildcard target patterns failed")
.run();
if (!result.success()) {
return null;
}
return result
.result()
.stream()
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (x, y) -> x));
}
private static void traversePackageRecursively(
BuildSystemProvider provider,
WorkspacePathResolver pathResolver,
File dir,
List<TargetExpression> output) {
WorkspacePath path = pathResolver.getWorkspacePath(dir);
if (path == null) {
return;
}
if (provider.findBuildFileInDirectory(dir) != null) {
output.add(TargetExpression.allFromPackageNonRecursive(path));
}
FileAttributeProvider attributeProvider = FileAttributeProvider.getInstance();
File[] children = attributeProvider.listFiles(dir);
if (children == null) {
return;
}
for (File child : children) {
if (attributeProvider.isDirectory(child)) {
traversePackageRecursively(provider, pathResolver, child, output);
}
}
}
}