blob: ef7242dc9acd13083232a3e2e51da0801910d579 [file] [log] [blame]
// Copyright 2022 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.bazel.bzlmod;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.devtools.build.lib.skyframe.SkyFunctions;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.HashMap;
import java.util.Map;
/**
* The result of running Bazel module inspection pre-processing, containing the un-pruned and
* augmented wrappers of the Bazel module dependency graph (post-version-resolution).
*/
@AutoValue
public abstract class BazelModuleInspectorValue implements SkyValue {
@SerializationConstant
public static final SkyKey KEY = () -> SkyFunctions.BAZEL_MODULE_INSPECTION;
public static BazelModuleInspectorValue create(
ImmutableMap<ModuleKey, AugmentedModule> depGraph,
ImmutableMap<String, ImmutableSet<ModuleKey>> modulesIndex,
ImmutableSetMultimap<ModuleExtensionId, String> extensionToRepoInternalNames) {
return new AutoValue_BazelModuleInspectorValue(
depGraph, modulesIndex, extensionToRepoInternalNames);
}
/**
* The (bidirectional) inspection dep graph, containing wrappers of the {@link Module}, augmented
* with references to dependants. The order is non-deterministic, inherited from the {@code
* completeDepGraph} of {@link BazelModuleResolutionValue}. For any KEY in the returned map, it's
* guaranteed that {@code depGraph[KEY].getKey() == KEY}.
*/
public abstract ImmutableMap<ModuleKey, AugmentedModule> getDepGraph();
/**
* Index of all module keys mentioned in the un-pruned dep graph (loaded or not) for easy lookup.
* It is a map from <i>module name</i> to the set of {@link ModuleKey}s that point to a version of
* that module.
*/
public abstract ImmutableMap<String, ImmutableSet<ModuleKey>> getModulesIndex();
/**
* A mapping from a module extension ID, to the list of "internal" names of the repos generated by
* that extension. The "internal" name is the name directly used by the extension when
* instantiating a repo rule.
*/
public abstract ImmutableSetMultimap<ModuleExtensionId, String> getExtensionToRepoInternalNames();
/**
* A wrapper for {@link Module}, augmented with references to dependants (and also those who are
* not used in the final dep graph).
*/
@AutoValue
public abstract static class AugmentedModule {
/** Name of the module. Same as in {@link Module}. */
public abstract String getName();
/** Version of the module. Same as in {@link Module}. */
public abstract Version getVersion();
/** {@link ModuleKey} of this module. Same as in {@link Module} */
public abstract ModuleKey getKey();
/**
* The set of modules in the resolved dep graph that depend on this module
* <strong>after</strong> the module resolution.
*/
public abstract ImmutableSet<ModuleKey> getDependants();
/**
* The set of modules in the complete dep graph that originally depended on this module *before*
* the module resolution (can contain unused nodes).
*/
public abstract ImmutableSet<ModuleKey> getOriginalDependants();
/**
* A bi-map from the repo names of the resolved dependencies of this module to their actual
* module keys. The inverse lookup is used to check how and why the dependency changed using the
* other maps.
*/
public abstract ImmutableBiMap<String, ModuleKey> getDeps();
/**
* A bi-map from the repo names of the unused dependencies of this module to their actual module
* keys. The inverse lookup is used to check how and why the dependency changed using the other
* maps.
*/
public abstract ImmutableBiMap<String, ModuleKey> getUnusedDeps();
/**
* A map from the repo name of the dependencies of this module to the rules that were used for
* their resolution (can be either the original dependency, changed by the Minimal-Version
* Selection algorithm or by an override rule.
*/
public abstract ImmutableMap<String, ResolutionReason> getDepReasons();
/**
* Shortcut for retrieving the sorted union of both used and unused deps based on the unused
* flag.
*/
public ImmutableSortedMap<ModuleKey, String> getAllDeps(boolean unused) {
if (!unused) {
return ImmutableSortedMap.copyOf(getDeps().inverse(), ModuleKey.LEXICOGRAPHIC_COMPARATOR);
} else {
Map<ModuleKey, String> map = new HashMap<>();
map.putAll(getDeps().inverse());
map.putAll(getUnusedDeps().inverse());
return ImmutableSortedMap.copyOf(map, ModuleKey.LEXICOGRAPHIC_COMPARATOR);
}
}
/**
* Flag that tell whether the module was loaded and added to the dependency graph. Modules
* overridden by {@code single_version_override} and {@link NonRegistryOverride} are not loaded
* so their {@code originalDeps} are (yet) unknown.
*/
public abstract boolean isLoaded();
/** Flag for checking whether the module is present in the resolved dep graph. */
public boolean isUsed() {
return getKey().equals(ModuleKey.ROOT) || !getDependants().isEmpty();
}
/** Returns a new {@link AugmentedModule.Builder} with {@code key} set. */
public static AugmentedModule.Builder builder(ModuleKey key) {
return new AutoValue_BazelModuleInspectorValue_AugmentedModule.Builder()
.setName(key.getName())
.setVersion(key.getVersion())
.setKey(key)
.setLoaded(false);
}
/** Builder type for {@link AugmentedModule}. */
@AutoValue.Builder
public abstract static class Builder {
public abstract AugmentedModule.Builder setName(String value);
public abstract AugmentedModule.Builder setVersion(Version value);
public abstract AugmentedModule.Builder setKey(ModuleKey value);
public abstract AugmentedModule.Builder setLoaded(boolean value);
abstract ImmutableSet.Builder<ModuleKey> originalDependantsBuilder();
@CanIgnoreReturnValue
public AugmentedModule.Builder addOriginalDependant(ModuleKey depKey) {
originalDependantsBuilder().add(depKey);
return this;
}
abstract ImmutableSet.Builder<ModuleKey> dependantsBuilder();
@CanIgnoreReturnValue
public AugmentedModule.Builder addDependant(ModuleKey depKey) {
dependantsBuilder().add(depKey);
return this;
}
abstract ImmutableBiMap.Builder<String, ModuleKey> depsBuilder();
@CanIgnoreReturnValue
public AugmentedModule.Builder addDep(String repoName, ModuleKey key) {
depsBuilder().put(repoName, key);
return this;
}
abstract ImmutableBiMap.Builder<String, ModuleKey> unusedDepsBuilder();
@CanIgnoreReturnValue
public AugmentedModule.Builder addUnusedDep(String repoName, ModuleKey key) {
unusedDepsBuilder().put(repoName, key);
return this;
}
abstract ImmutableMap.Builder<String, ResolutionReason> depReasonsBuilder();
@CanIgnoreReturnValue
public AugmentedModule.Builder addDepReason(String repoName, ResolutionReason reason) {
depReasonsBuilder().put(repoName, reason);
return this;
}
public abstract AugmentedModule build();
}
/** The reason why a final dependency of a module was resolved the way it was. */
public enum ResolutionReason {
/** The dependency is the original dependency defined in the MODULE.bazel file. */
ORIGINAL(""),
/** The dependency was replaced by the Minimal-Version Selection algorithm. */
MINIMAL_VERSION_SELECTION("MVS"),
/** The dependency was replaced by a {@code single_version_override} rule. */
SINGLE_VERSION_OVERRIDE("SVO"),
/** The dependency was replaced by a {@code multiple_version_override} rule. */
MULTIPLE_VERSION_OVERRIDE("MVO"),
/** The dependency was replaced by one of the {@link NonRegistryOverride} rules. */
ARCHIVE_OVERRIDE("archive"),
GIT_OVERRIDE("git"),
LOCAL_PATH_OVERRIDE("local");
private final String label;
ResolutionReason(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
}
}