blob: d5d558d9f1fc781f1ace830dd5320d5778f312dc [file] [log] [blame]
// Copyright 2019 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.repository;
import com.google.common.collect.ImmutableSortedSet;
import com.google.devtools.build.lib.cmdline.LabelConstants;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.WorkspaceFileValue;
import com.google.devtools.build.lib.skyframe.PackageLookupValue;
import com.google.devtools.build.lib.vfs.RootedPath;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import com.google.devtools.build.skyframe.SkyKey;
import javax.annotation.Nullable;
/** Utility class to centralize looking up data from the external package. */
public class ExternalPackageUtil {
/**
* Returns directories, that should not be symlinked under the execroot.
*
* <p>Searches for dont_symlink_directories_in_execroot calls in the WORKSPACE file, and gathers
* values of all "paths" attributes.
*/
public static ImmutableSortedSet<String> getNotSymlinkedInExecrootDirectories(Environment env)
throws InterruptedException {
ImmutableSortedSet.Builder<String> builder = ImmutableSortedSet.naturalOrder();
WorkspaceFileValueProcessor gatherer =
workspaceFileValue -> {
ImmutableSortedSet<String> paths = workspaceFileValue.getDoNotSymlinkInExecrootPaths();
if (paths != null) {
builder.addAll(paths);
}
// Continue to read all the fragments.
return true;
};
if (!iterateWorkspaceFragments(env, gatherer)) {
return null;
}
return builder.build();
}
/** Uses a rule name to fetch the corresponding Rule from the external package. */
@Nullable
public static Rule getRuleByName(final String ruleName, Environment env)
throws ExternalPackageException, InterruptedException {
ExternalPackageRuleExtractor extractor = new ExternalPackageRuleExtractor(env, ruleName);
if (!iterateWorkspaceFragments(env, extractor)) {
// Values missing
return null;
}
return extractor.getRule();
}
/** Returns false if some SkyValues were missing. */
private static boolean iterateWorkspaceFragments(
Environment env, WorkspaceFileValueProcessor processor) throws InterruptedException {
SkyKey packageLookupKey = PackageLookupValue.key(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER);
PackageLookupValue packageLookupValue = (PackageLookupValue) env.getValue(packageLookupKey);
if (packageLookupValue == null) {
return false;
}
RootedPath workspacePath =
packageLookupValue.getRootedPath(LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER);
SkyKey workspaceKey = WorkspaceFileValue.key(workspacePath);
WorkspaceFileValue value;
do {
value = (WorkspaceFileValue) env.getValue(workspaceKey);
if (value == null) {
return false;
}
} while (processor.processAndShouldContinue(value) && (workspaceKey = value.next()) != null);
return true;
}
private static class ExternalPackageRuleExtractor implements WorkspaceFileValueProcessor {
private final Environment env;
private final String ruleName;
private ExternalPackageException exception;
private Rule rule;
private ExternalPackageRuleExtractor(Environment env, String ruleName) {
this.env = env;
this.ruleName = ruleName;
}
@Override
public boolean processAndShouldContinue(WorkspaceFileValue workspaceFileValue) {
Package externalPackage = workspaceFileValue.getPackage();
if (externalPackage.containsErrors()) {
Event.replayEventsOn(env.getListener(), externalPackage.getEvents());
exception =
new ExternalPackageException(
new BuildFileContainsErrorsException(
LabelConstants.EXTERNAL_PACKAGE_IDENTIFIER,
"Could not load //external package"),
Transience.PERSISTENT);
// Stop iteration when encountered errors.
return false;
}
rule = externalPackage.getRule(ruleName);
// Stop if the rule is found = continue while it is null.
return rule == null;
}
public Rule getRule() throws ExternalPackageException {
if (exception != null) {
throw exception;
}
if (rule == null) {
throw new ExternalRuleNotFoundException(ruleName);
}
return rule;
}
}
private interface WorkspaceFileValueProcessor {
boolean processAndShouldContinue(WorkspaceFileValue value);
}
}