| // Copyright 2024 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.skyframe; | |
| import com.google.auto.value.AutoValue; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableMap; | |
| import com.google.common.collect.ImmutableSet; | |
| import com.google.devtools.build.lib.cmdline.Label; | |
| import com.google.devtools.build.lib.cmdline.LabelSyntaxException; | |
| import com.google.devtools.build.lib.collect.SimpleTargetPatternMatcher; | |
| import com.google.devtools.build.skyframe.SkyFunctionName; | |
| import com.google.devtools.build.skyframe.SkyKey; | |
| import com.google.devtools.build.skyframe.SkyValue; | |
| import java.util.Collection; | |
| import java.util.Objects; | |
| import javax.annotation.Nullable; | |
| /** A SkyValue representing the parsed definitions from a PROJECT.scl file. */ | |
| public final class ProjectValue implements SkyValue { | |
| /** | |
| * Represents the enforcement policy for a PROJECT.scl file. | |
| * | |
| * <p>"warn" (default) - warn if the user set any output-affecting options that are not present in | |
| * the selected config in a blazerc or on the command line. | |
| * | |
| * <p>"compatible" - fail if the user set any options that are present in the selected config to a | |
| * different value than the one in the config. Also warn for other output-affecting options | |
| * | |
| * <p>"strict" - fail if the user set any output-affecting options that are not present in the | |
| * selected config. | |
| */ | |
| public enum EnforcementPolicy { | |
| WARN("warn"), // Default, enforced in ProjectFunction#compute. | |
| COMPATIBLE("compatible"), | |
| STRICT("strict"); | |
| EnforcementPolicy(String value) { | |
| this.value = value; | |
| } | |
| private final String value; | |
| public static EnforcementPolicy fromString(String value) { | |
| for (EnforcementPolicy policy : EnforcementPolicy.values()) { | |
| if (policy.value.equals(value)) { | |
| return policy; | |
| } | |
| } | |
| throw new IllegalArgumentException(String.format("invalid enforcement_policy '%s'", value)); | |
| } | |
| } | |
| private final EnforcementPolicy enforcementPolicy; | |
| private final ImmutableMap<String, Collection<String>> projectDirectories; | |
| @Nullable private final ImmutableMap<String, BuildableUnit> buildableUnits; | |
| @Nullable private final ImmutableList<String> alwaysAllowedConfigs; | |
| @Nullable private final Label actualProjectFile; | |
| /** | |
| * A project's buildable units. | |
| * | |
| * <p>A buildable unit is a named pair of build flags and target patterns. The name is stored as a | |
| * map key in {@link ProjectValue#getBuildableUnits()} | |
| * | |
| * <p>See {@code third_party/bazel/src/main/protobuf/project/project.proto} for precise | |
| * definitions. | |
| */ | |
| @AutoValue | |
| public abstract static class BuildableUnit { | |
| /** | |
| * Creates a buildable unit. | |
| * | |
| * @param name the buildable unit's name | |
| * @param targetPatterns the buildable unit's target patterns, or empty if they weren't set | |
| * @param description the buildable unit's user-friendly description, or empty if not set | |
| * @param flags the buildable unit's flags | |
| * @param isDefault whether this is the default buildable unit | |
| */ | |
| public static BuildableUnit create( | |
| String name, | |
| ImmutableList<String> targetPatterns, | |
| String description, | |
| ImmutableList<String> flags, | |
| boolean isDefault) | |
| throws LabelSyntaxException { | |
| return new AutoValue_ProjectValue_BuildableUnit( | |
| name, SimpleTargetPatternMatcher.create(targetPatterns), description, flags, isDefault); | |
| } | |
| public abstract String name(); | |
| public abstract SimpleTargetPatternMatcher targetPatternMatcher(); | |
| public abstract String description(); | |
| public abstract ImmutableList<String> flags(); | |
| public abstract boolean isDefault(); | |
| } | |
| public ProjectValue( | |
| EnforcementPolicy enforcementPolicy, | |
| ImmutableMap<String, Collection<String>> projectDirectories, | |
| @Nullable ImmutableMap<String, BuildableUnit> buildableUnits, | |
| @Nullable ImmutableList<String> alwaysAllowedConfigs, | |
| @Nullable Label actualProjectFile) { | |
| this.enforcementPolicy = enforcementPolicy; | |
| this.projectDirectories = projectDirectories; | |
| this.buildableUnits = buildableUnits; | |
| this.alwaysAllowedConfigs = alwaysAllowedConfigs; | |
| this.actualProjectFile = actualProjectFile; | |
| } | |
| /** | |
| * Return the "default" {@code project_directories} map entry. If there are zero entries, returns | |
| * an empty set. | |
| */ | |
| public ImmutableSet<String> getDefaultProjectDirectories() { | |
| if (projectDirectories.isEmpty()) { | |
| return ImmutableSet.of(); | |
| } | |
| // TODO: b/409377907 - Make sure this check still makes sense with the new format. | |
| Preconditions.checkArgument( | |
| projectDirectories.containsKey("default"), | |
| "project_directories must contain the 'default' key"); | |
| return ImmutableSet.copyOf(projectDirectories.get("default")); | |
| } | |
| /** | |
| * If a project file has the content | |
| * | |
| * {@snippet : | |
| * project = { | |
| * "actual": "//other:PROJECT.scl" | |
| * } | |
| * } | |
| * | |
| * <p>then this is the same project defined canonically in {@code //other:PROJECT.scl} and this | |
| * method returns {@code //other:PROJECT.scl}. Else returns the {@link ProjectValue.Key} label | |
| * that produces this value. | |
| * | |
| * <p>Files that define "actual" cannot define any other content. That's considered a parsing | |
| * error. | |
| */ | |
| public Label getActualProjectFile() { | |
| return actualProjectFile; | |
| } | |
| public EnforcementPolicy getEnforcementPolicy() { | |
| return enforcementPolicy; | |
| } | |
| /** | |
| * Maps buildable unit names to definitions. Null if not specified. Note that an empty list is not | |
| * the same as unspecified. | |
| * | |
| * <p>Builds can trigger a buildable unit by setting {@code --scl_config=<name>}. | |
| */ | |
| @Nullable | |
| public ImmutableMap<String, BuildableUnit> getBuildableUnits() { | |
| return buildableUnits; | |
| } | |
| @Nullable | |
| public ImmutableList<String> getAlwaysAllowedConfigs() { | |
| return alwaysAllowedConfigs; | |
| } | |
| /** | |
| * Returns the map of named {@code project_directories} in the project. If the map is not defined | |
| * in the file, returns an empty map. | |
| */ | |
| public ImmutableMap<String, Collection<String>> getProjectDirectories() { | |
| return projectDirectories; | |
| } | |
| /** The SkyKey. Uses the label of the project file as the input. */ | |
| public static final class Key implements SkyKey { | |
| private final Label projectFile; | |
| public Key(Label projectFile) { | |
| this.projectFile = Preconditions.checkNotNull(projectFile); | |
| } | |
| public Label getProjectFile() { | |
| return projectFile; | |
| } | |
| @Override | |
| public SkyFunctionName functionName() { | |
| return SkyFunctions.PROJECT; | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) { | |
| return true; | |
| } | |
| if (o == null || getClass() != o.getClass()) { | |
| return false; | |
| } | |
| ProjectValue.Key key = (ProjectValue.Key) o; | |
| return Objects.equals(projectFile, key.projectFile); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return Objects.hashCode(projectFile); | |
| } | |
| } | |
| } |