diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD index bd02cc51fcdec3..5c4f4adbab73bf 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD @@ -94,8 +94,10 @@ java_library( "BazelModuleResolutionValue.java", "BzlmodFlagsAndEnvVars.java", "GitOverride.java", + "InterimModule.java", "LocalPathOverride.java", "Module.java", + "ModuleBase.java", "ModuleExtensionEvalStarlarkThreadContext.java", "ModuleFileValue.java", "ModuleOverride.java", diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java index 0394de65277e22..c2c3ffe57a5751 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunction.java @@ -55,7 +55,7 @@ public SkyValue compute(SkyKey skyKey, Environment env) return null; } ImmutableMap overrides = root.getOverrides(); - ImmutableMap unprunedDepGraph = resolutionValue.getUnprunedDepGraph(); + ImmutableMap unprunedDepGraph = resolutionValue.getUnprunedDepGraph(); ImmutableMap resolvedDepGraph = resolutionValue.getResolvedDepGraph(); ImmutableMap depGraph = @@ -74,7 +74,7 @@ public SkyValue compute(SkyKey skyKey, Environment env) } public static ImmutableMap computeAugmentedGraph( - ImmutableMap unprunedDepGraph, + ImmutableMap unprunedDepGraph, ImmutableSet usedModules, ImmutableMap overrides) { Map depGraphAugmentBuilder = new HashMap<>(); @@ -83,9 +83,9 @@ public static ImmutableMap computeAugmentedGraph( // to their children AugmentedModule as dependant. Also fill in their own AugmentedModule // with a map from their dependencies to the resolution reason that was applied to each. // The newly created graph will also contain ModuleAugments for non-loaded modules. - for (Entry e : unprunedDepGraph.entrySet()) { + for (Entry e : unprunedDepGraph.entrySet()) { ModuleKey parentKey = e.getKey(); - Module parentModule = e.getValue(); + InterimModule parentModule = e.getValue(); AugmentedModule.Builder parentBuilder = depGraphAugmentBuilder @@ -95,10 +95,10 @@ public static ImmutableMap computeAugmentedGraph( .setLoaded(true); for (String childDep : parentModule.getDeps().keySet()) { - ModuleKey originalKey = parentModule.getOriginalDeps().get(childDep); - Module originalModule = unprunedDepGraph.get(originalKey); - ModuleKey key = parentModule.getDeps().get(childDep); - Module module = unprunedDepGraph.get(key); + ModuleKey originalKey = parentModule.getOriginalDeps().get(childDep).toModuleKey(); + InterimModule originalModule = unprunedDepGraph.get(originalKey); + ModuleKey key = parentModule.getDeps().get(childDep).toModuleKey(); + InterimModule module = unprunedDepGraph.get(key); AugmentedModule.Builder originalChildBuilder = depGraphAugmentBuilder.computeIfAbsent(originalKey, AugmentedModule::builder); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java index 3c9f1c825e6c97..39092c993d6b0b 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java @@ -21,8 +21,10 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; import com.google.devtools.build.lib.analysis.BlazeVersionInfo; import com.google.devtools.build.lib.bazel.BazelVersion; +import com.google.devtools.build.lib.bazel.bzlmod.InterimModule.DepSpec; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue; import com.google.devtools.build.lib.bazel.bzlmod.Version.ParseException; import com.google.devtools.build.lib.bazel.repository.RepositoryOptions.BazelCompatibilityMode; @@ -78,18 +80,18 @@ public SkyValue compute(SkyKey skyKey, Environment env) if (root == null) { return null; } - ImmutableMap initialDepGraph = Discovery.run(env, root); + ImmutableMap initialDepGraph = Discovery.run(env, root); if (initialDepGraph == null) { return null; } - BazelModuleResolutionValue selectionResultValue; + Selection.Result selectionResult; try { - selectionResultValue = Selection.run(initialDepGraph, root.getOverrides()); + selectionResult = Selection.run(initialDepGraph, root.getOverrides()); } catch (ExternalDepsException e) { throw new BazelModuleResolutionFunctionException(e, Transience.PERSISTENT); } - ImmutableMap resolvedDepGraph = selectionResultValue.getResolvedDepGraph(); + ImmutableMap resolvedDepGraph = selectionResult.getResolvedDepGraph(); verifyRootModuleDirectDepsAreAccurate( initialDepGraph.get(ModuleKey.ROOT), @@ -109,40 +111,15 @@ public SkyValue compute(SkyKey skyKey, Environment env) Objects.requireNonNull(ALLOWED_YANKED_VERSIONS.get(env))), env.getListener()); - // Add repo spec to each module and remove registry - try { - ImmutableMap.Builder mapBuilder = ImmutableMap.builder(); - for (Map.Entry entry : resolvedDepGraph.entrySet()) { - Module module = entry.getValue(); - // Only change modules with registry (not overridden) - if (module.getRegistry() != null) { - RepoSpec moduleRepoSpec = - module - .getRegistry() - .getRepoSpec(module.getKey(), module.getCanonicalRepoName(), env.getListener()); - ModuleOverride override = root.getOverrides().get(entry.getKey().getName()); - moduleRepoSpec = maybeAppendAdditionalPatches(moduleRepoSpec, override); - module = module.toBuilder().setRepoSpec(moduleRepoSpec).setRegistry(null).build(); - } - mapBuilder.put(entry.getKey(), module); - } - resolvedDepGraph = mapBuilder.buildOrThrow(); - } catch (IOException e) { - throw new BazelModuleResolutionFunctionException( - ExternalDepsException.withMessage( - Code.ERROR_ACCESSING_REGISTRY, - "Unable to get module repo spec from registry: %s", - e.getMessage()), - Transience.PERSISTENT); - } + ImmutableMap finalDepGraph = + computeFinalDepGraph(resolvedDepGraph, root.getOverrides(), env.getListener()); - return BazelModuleResolutionValue.create( - resolvedDepGraph, selectionResultValue.getUnprunedDepGraph()); + return BazelModuleResolutionValue.create(finalDepGraph, selectionResult.getUnprunedDepGraph()); } private static void verifyRootModuleDirectDepsAreAccurate( - Module discoveredRootModule, - Module resolvedRootModule, + InterimModule discoveredRootModule, + InterimModule resolvedRootModule, CheckDirectDepsMode mode, EventHandler eventHandler) throws BazelModuleResolutionFunctionException { @@ -151,14 +128,14 @@ private static void verifyRootModuleDirectDepsAreAccurate( } boolean failure = false; - for (Map.Entry dep : discoveredRootModule.getDeps().entrySet()) { - ModuleKey resolved = resolvedRootModule.getDeps().get(dep.getKey()); - if (!dep.getValue().equals(resolved)) { + for (Map.Entry dep : discoveredRootModule.getDeps().entrySet()) { + ModuleKey resolved = resolvedRootModule.getDeps().get(dep.getKey()).toModuleKey(); + if (!dep.getValue().toModuleKey().equals(resolved)) { String message = String.format( "For repository '%s', the root module requires module version %s, but got %s in the" + " resolved dependency graph.", - dep.getKey(), dep.getValue(), resolved); + dep.getKey(), dep.getValue().toModuleKey(), resolved); if (mode == CheckDirectDepsMode.WARNING) { eventHandler.handle(Event.warn(message)); } else { @@ -177,7 +154,9 @@ private static void verifyRootModuleDirectDepsAreAccurate( } public static void checkBazelCompatibility( - ImmutableCollection modules, BazelCompatibilityMode mode, EventHandler eventHandler) + ImmutableCollection modules, + BazelCompatibilityMode mode, + EventHandler eventHandler) throws BazelModuleResolutionFunctionException { if (mode == BazelCompatibilityMode.OFF) { return; @@ -189,7 +168,7 @@ public static void checkBazelCompatibility( } BazelVersion curVersion = BazelVersion.parse(currentBazelVersion); - for (Module module : modules) { + for (InterimModule module : modules) { for (String compatVersion : module.getBazelCompatibility()) { if (!curVersion.satisfiesCompatibility(compatVersion)) { String message = @@ -306,14 +285,14 @@ private boolean parseModuleKeysFromString( return false; } - private void verifyYankedVersions( - ImmutableMap depGraph, + private static void verifyYankedVersions( + ImmutableMap depGraph, Optional> allowedYankedVersions, ExtendedEventHandler eventHandler) throws BazelModuleResolutionFunctionException, InterruptedException { // Check whether all resolved modules are either not yanked or allowed. Modules with a // NonRegistryOverride are ignored as their metadata is not available whatsoever. - for (Module m : depGraph.values()) { + for (InterimModule m : depGraph.values()) { if (m.getKey().equals(ModuleKey.ROOT) || m.getRegistry() == null) { continue; } @@ -349,7 +328,7 @@ private void verifyYankedVersions( } } - private RepoSpec maybeAppendAdditionalPatches(RepoSpec repoSpec, ModuleOverride override) { + private static RepoSpec maybeAppendAdditionalPatches(RepoSpec repoSpec, ModuleOverride override) { if (!(override instanceof SingleVersionOverride)) { return repoSpec; } @@ -369,6 +348,66 @@ private RepoSpec maybeAppendAdditionalPatches(RepoSpec repoSpec, ModuleOverride .build(); } + @Nullable + private static RepoSpec computeRepoSpec( + InterimModule interimModule, ModuleOverride override, ExtendedEventHandler eventHandler) + throws BazelModuleResolutionFunctionException, InterruptedException { + if (interimModule.getRegistry() == null) { + // This module has a non-registry override. We don't need to store the repo spec in this case. + return null; + } + try { + RepoSpec moduleRepoSpec = + interimModule + .getRegistry() + .getRepoSpec( + interimModule.getKey(), interimModule.getCanonicalRepoName(), eventHandler); + return maybeAppendAdditionalPatches(moduleRepoSpec, override); + } catch (IOException e) { + throw new BazelModuleResolutionFunctionException( + ExternalDepsException.withMessage( + Code.ERROR_ACCESSING_REGISTRY, + "Unable to get module repo spec from registry: %s", + e.getMessage()), + Transience.PERSISTENT); + } + } + + /** + * Builds a {@link Module} from an {@link InterimModule}, discarding unnecessary fields and adding + * extra necessary ones (such as the repo spec). + */ + static Module moduleFromInterimModule( + InterimModule interim, ModuleOverride override, ExtendedEventHandler eventHandler) + throws BazelModuleResolutionFunctionException, InterruptedException { + return Module.builder() + .setName(interim.getName()) + .setVersion(interim.getVersion()) + .setKey(interim.getKey()) + .setRepoName(interim.getRepoName()) + .setExecutionPlatformsToRegister(interim.getExecutionPlatformsToRegister()) + .setToolchainsToRegister(interim.getToolchainsToRegister()) + .setDeps(ImmutableMap.copyOf(Maps.transformValues(interim.getDeps(), DepSpec::toModuleKey))) + .setRepoSpec(computeRepoSpec(interim, override, eventHandler)) + .setExtensionUsages(interim.getExtensionUsages()) + .build(); + } + + private static ImmutableMap computeFinalDepGraph( + ImmutableMap resolvedDepGraph, + ImmutableMap overrides, + ExtendedEventHandler eventHandler) + throws BazelModuleResolutionFunctionException, InterruptedException { + ImmutableMap.Builder finalDepGraph = ImmutableMap.builder(); + for (Map.Entry entry : resolvedDepGraph.entrySet()) { + finalDepGraph.put( + entry.getKey(), + moduleFromInterimModule( + entry.getValue(), overrides.get(entry.getKey().getName()), eventHandler)); + } + return finalDepGraph.buildOrThrow(); + } + static class BazelModuleResolutionFunctionException extends SkyFunctionException { BazelModuleResolutionFunctionException(ExternalDepsException e, Transience transience) { super(e, transience); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java index f2c734647478ed..19c642cfa5d7f7 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionValue.java @@ -44,11 +44,11 @@ abstract class BazelModuleResolutionValue implements SkyValue { * overridden by {@code single_version_override} or {@link NonRegistryOverride}, only by {@code * multiple_version_override}. */ - abstract ImmutableMap getUnprunedDepGraph(); + abstract ImmutableMap getUnprunedDepGraph(); static BazelModuleResolutionValue create( ImmutableMap resolvedDepGraph, - ImmutableMap unprunedDepGraph) { + ImmutableMap unprunedDepGraph) { return new AutoValue_BazelModuleResolutionValue(resolvedDepGraph, unprunedDepGraph); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Discovery.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Discovery.java index 7fb3a67f044d84..d041c3ca0cda97 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Discovery.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Discovery.java @@ -16,9 +16,9 @@ package com.google.devtools.build.lib.bazel.bzlmod; import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.bazel.bzlmod.InterimModule.DepSpec; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue; import com.google.devtools.build.skyframe.SkyFunction.Environment; -import com.google.devtools.build.skyframe.SkyFunctionException; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyframeLookupResult; import java.util.ArrayDeque; @@ -42,23 +42,24 @@ private Discovery() {} * dependency is missing and this function needs a restart). */ @Nullable - public static ImmutableMap run(Environment env, RootModuleFileValue root) - throws SkyFunctionException, InterruptedException { + public static ImmutableMap run( + Environment env, RootModuleFileValue root) throws InterruptedException { String rootModuleName = root.getModule().getName(); ImmutableMap overrides = root.getOverrides(); - Map depGraph = new HashMap<>(); - depGraph.put(ModuleKey.ROOT, rewriteDepKeys(root.getModule(), overrides, rootModuleName)); + Map depGraph = new HashMap<>(); + depGraph.put(ModuleKey.ROOT, rewriteDepSpecs(root.getModule(), overrides, rootModuleName)); Queue unexpanded = new ArrayDeque<>(); unexpanded.add(ModuleKey.ROOT); while (!unexpanded.isEmpty()) { Set unexpandedSkyKeys = new HashSet<>(); while (!unexpanded.isEmpty()) { - Module module = depGraph.get(unexpanded.remove()); - for (ModuleKey depKey : module.getDeps().values()) { - if (depGraph.containsKey(depKey)) { + InterimModule module = depGraph.get(unexpanded.remove()); + for (DepSpec depSpec : module.getDeps().values()) { + if (depGraph.containsKey(depSpec.toModuleKey())) { continue; } - unexpandedSkyKeys.add(ModuleFileValue.key(depKey, overrides.get(depKey.getName()))); + unexpandedSkyKeys.add( + ModuleFileValue.key(depSpec.toModuleKey(), overrides.get(depSpec.getName()))); } } SkyframeLookupResult result = env.getValuesAndExceptions(unexpandedSkyKeys); @@ -70,7 +71,7 @@ public static ImmutableMap run(Environment env, RootModuleFil depGraph.put(depKey, null); } else { depGraph.put( - depKey, rewriteDepKeys(moduleFileValue.getModule(), overrides, rootModuleName)); + depKey, rewriteDepSpecs(moduleFileValue.getModule(), overrides, rootModuleName)); unexpanded.add(depKey); } } @@ -81,16 +82,16 @@ public static ImmutableMap run(Environment env, RootModuleFil return ImmutableMap.copyOf(depGraph); } - private static Module rewriteDepKeys( - Module module, ImmutableMap overrides, String rootModuleName) { - return module.withDepKeysTransformed( - depKey -> { - if (rootModuleName.equals(depKey.getName())) { - return ModuleKey.ROOT; + private static InterimModule rewriteDepSpecs( + InterimModule module, ImmutableMap overrides, String rootModuleName) { + return module.withDepSpecsTransformed( + depSpec -> { + if (rootModuleName.equals(depSpec.getName())) { + return DepSpec.fromModuleKey(ModuleKey.ROOT); } - Version newVersion = depKey.getVersion(); - @Nullable ModuleOverride override = overrides.get(depKey.getName()); + Version newVersion = depSpec.getVersion(); + @Nullable ModuleOverride override = overrides.get(depSpec.getName()); if (override instanceof NonRegistryOverride) { newVersion = Version.EMPTY; } else if (override instanceof SingleVersionOverride) { @@ -100,7 +101,7 @@ private static Module rewriteDepKeys( } } - return ModuleKey.create(depKey.getName(), newVersion); + return DepSpec.create(depSpec.getName(), newVersion, depSpec.getMaxCompatibilityLevel()); }); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModule.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModule.java new file mode 100644 index 00000000000000..06f5051a7c0c3a --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModule.java @@ -0,0 +1,213 @@ +// Copyright 2023 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.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.ryanharter.auto.value.gson.GenerateTypeAdapter; +import java.util.Optional; +import java.util.function.UnaryOperator; +import javax.annotation.Nullable; + +/** + * Represents a node in the external dependency graph during module resolution (discovery & + * selection). + * + *

In particular, it represents a specific version of a module; there can be multiple {@link + * InterimModule}s in a dependency graph with the same name but with different versions (such as + * after discovery but before selection, or when there's a multiple_version_override in play). + * + *

Compared to {@link Module}, which is used after module resolution, this class holds some more + * information that's useful only during resolution, such as the {@code max_compatibility_level} for + * each dep, the {@code compatibility_level}, the {@code registry} the module comes from, etc. + */ +@AutoValue +@GenerateTypeAdapter +public abstract class InterimModule extends ModuleBase { + + /** + * The compatibility level of the module, which essentially signifies the "major version" of the + * module in terms of SemVer. + */ + public abstract int getCompatibilityLevel(); + + /** List of bazel compatible versions that would run/fail this module */ + public abstract ImmutableList getBazelCompatibility(); + + /** The specification of a dependency. */ + @AutoValue + public abstract static class DepSpec { + public abstract String getName(); + + public abstract Version getVersion(); + + public abstract int getMaxCompatibilityLevel(); + + public static DepSpec create(String name, Version version, int maxCompatibilityLevel) { + return new AutoValue_InterimModule_DepSpec(name, version, maxCompatibilityLevel); + } + + public static DepSpec fromModuleKey(ModuleKey key) { + return create(key.getName(), key.getVersion(), -1); + } + + public final ModuleKey toModuleKey() { + return ModuleKey.create(getName(), getVersion()); + } + } + + /** + * The resolved direct dependencies of this module, which can be either the original ones, + * overridden by a {@code single_version_override}, by a {@code multiple_version_override}, or by + * a {@link NonRegistryOverride} (the version will be ""). The key type is the repo name of the + * dep. + */ + public abstract ImmutableMap getDeps(); + + /** + * The original direct dependencies of this module as they are declared in their MODULE file. The + * key type is the repo name of the dep. + */ + public abstract ImmutableMap getOriginalDeps(); + + /** + * The registry where this module came from. Must be null iff the module has a {@link + * NonRegistryOverride}. + */ + @Nullable + public abstract Registry getRegistry(); + + /** Returns a {@link Builder} that starts out with the same fields as this object. */ + abstract Builder toBuilder(); + + /** Returns a new, empty {@link Builder}. */ + public static Builder builder() { + return new AutoValue_InterimModule.Builder() + .setName("") + .setVersion(Version.EMPTY) + .setKey(ModuleKey.ROOT) + .setCompatibilityLevel(0); + } + + /** + * Returns a new {@link InterimModule} with all values in {@link #getDeps} transformed using the + * given function. + */ + public InterimModule withDepSpecsTransformed(UnaryOperator transform) { + return toBuilder() + .setDeps(ImmutableMap.copyOf(Maps.transformValues(getDeps(), transform::apply))) + .build(); + } + + /** Builder type for {@link InterimModule}. */ + @AutoValue.Builder + public abstract static class Builder { + /** Optional; defaults to the empty string. */ + public abstract Builder setName(String value); + + /** Optional; defaults to {@link Version#EMPTY}. */ + public abstract Builder setVersion(Version value); + + /** Optional; defaults to {@link ModuleKey#ROOT}. */ + public abstract Builder setKey(ModuleKey value); + + /** Optional; defaults to {@code 0}. */ + public abstract Builder setCompatibilityLevel(int value); + + /** Optional; defaults to {@link #setName}. */ + public abstract Builder setRepoName(String value); + + public abstract Builder setBazelCompatibility(ImmutableList value); + + abstract ImmutableList.Builder bazelCompatibilityBuilder(); + + @CanIgnoreReturnValue + public final Builder addBazelCompatibilityValues(Iterable values) { + bazelCompatibilityBuilder().addAll(values); + return this; + } + + public abstract Builder setExecutionPlatformsToRegister(ImmutableList value); + + abstract ImmutableList.Builder executionPlatformsToRegisterBuilder(); + + @CanIgnoreReturnValue + public final Builder addExecutionPlatformsToRegister(Iterable values) { + executionPlatformsToRegisterBuilder().addAll(values); + return this; + } + + public abstract Builder setToolchainsToRegister(ImmutableList value); + + abstract ImmutableList.Builder toolchainsToRegisterBuilder(); + + @CanIgnoreReturnValue + public final Builder addToolchainsToRegister(Iterable values) { + toolchainsToRegisterBuilder().addAll(values); + return this; + } + + public abstract Builder setOriginalDeps(ImmutableMap value); + + public abstract Builder setDeps(ImmutableMap value); + + abstract ImmutableMap.Builder depsBuilder(); + + @CanIgnoreReturnValue + public Builder addDep(String depRepoName, DepSpec depSpec) { + depsBuilder().put(depRepoName, depSpec); + return this; + } + + abstract ImmutableMap.Builder originalDepsBuilder(); + + @CanIgnoreReturnValue + public Builder addOriginalDep(String depRepoName, DepSpec depSpec) { + originalDepsBuilder().put(depRepoName, depSpec); + return this; + } + + public abstract Builder setRegistry(Registry value); + + public abstract Builder setExtensionUsages(ImmutableList value); + + abstract ImmutableList.Builder extensionUsagesBuilder(); + + @CanIgnoreReturnValue + public Builder addExtensionUsage(ModuleExtensionUsage value) { + extensionUsagesBuilder().add(value); + return this; + } + + abstract ModuleKey getKey(); + + abstract String getName(); + + abstract Optional getRepoName(); + + abstract InterimModule autoBuild(); + + final InterimModule build() { + if (getRepoName().isEmpty()) { + setRepoName(getName()); + } + return autoBuild(); + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java index 86fae25df40b45..36166367cb42cc 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Module.java @@ -18,103 +18,32 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.ryanharter.auto.value.gson.GenerateTypeAdapter; import java.util.Map; -import java.util.Optional; -import java.util.function.UnaryOperator; import javax.annotation.Nullable; /** * Represents a node in the external dependency graph. * *

In particular, it represents a specific version of a module; there can be multiple {@link - * Module}s in a dependency graph with the same name but with different versions (such as after - * discovery but before selection, or when there's a multiple_version_override in play). + * Module}s in a dependency graph with the same name but with different versions (when there's a + * multiple_version_override in play). + * + *

For the intermediate type used during module resolution, see {@link InterimModule}. */ @AutoValue @GenerateTypeAdapter -public abstract class Module { - - /** - * The name of the module, as specified in this module's MODULE.bazel file. Can be empty if this - * is the root module. - */ - public abstract String getName(); - - /** - * The version of the module, as specified in this module's MODULE.bazel file. Can be empty if - * this is the root module, or if this module comes from a {@link NonRegistryOverride}. - */ - public abstract Version getVersion(); - - /** - * The key of this module in the dependency graph. Note that, although a {@link ModuleKey} is also - * just a (name, version) pair, its semantics differ from {@link #getName} and {@link - * #getVersion}, which are always as specified in the MODULE.bazel file. The {@link ModuleKey} - * returned by this method, however, will have the following special semantics: - * - *

    - *
  • The name of the {@link ModuleKey} is the same as {@link #getName}, unless this is the - * root module, in which case the name of the {@link ModuleKey} must be empty. - *
  • The version of the {@link ModuleKey} is the same as {@link #getVersion}, unless this is - * the root module OR this module has a {@link NonRegistryOverride}, in which case the - * version of the {@link ModuleKey} must be empty. - *
- */ - public abstract ModuleKey getKey(); - - public final RepositoryName getCanonicalRepoName() { - return getKey().getCanonicalRepoName(); - } - - /** - * The compatibility level of the module, which essentially signifies the "major version" of the - * module in terms of SemVer. - */ - public abstract int getCompatibilityLevel(); - - /** - * The name of the repository representing this module, as seen by the module itself. By default, - * the name of the repo is the name of the module. This can be specified to ease migration for - * projects that have been using a repo name for itself that differs from its module name. - */ - public abstract String getRepoName(); - - /** List of bazel compatible versions that would run/fail this module */ - public abstract ImmutableList getBazelCompatibility(); - - /** - * Target patterns identifying execution platforms to register when this module is selected. Note - * that these are what was written in module files verbatim, and don't contain canonical repo - * names. - */ - public abstract ImmutableList getExecutionPlatformsToRegister(); +public abstract class Module extends ModuleBase { /** - * Target patterns identifying toolchains to register when this module is selected. Note that - * these are what was written in module files verbatim, and don't contain canonical repo names. - */ - public abstract ImmutableList getToolchainsToRegister(); - - /** - * The resolved direct dependencies of this module, which can be either the original ones, - * overridden by a {@code single_version_override}, by a {@code multiple_version_override}, or by - * a {@link NonRegistryOverride} (the version will be ""). The key type is the repo name of the - * dep, and the value type is the ModuleKey (name+version) of the dep. + * The resolved direct dependencies of this module. The key type is the repo name of the dep, and + * the value type is the ModuleKey ({@link #getKey()}) of the dep. */ public abstract ImmutableMap getDeps(); - /** - * The original direct dependencies of this module as they are declared in their MODULE file. The - * key type is the repo name of the dep, and the value type is the ModuleKey (name+version) of the - * dep. - */ - public abstract ImmutableMap getOriginalDeps(); - /** * Returns a {@link RepositoryMapping} with only Bazel module repos and no repos from module * extensions. For the full mapping, see {@link BazelDepGraphValue#getFullRepoMapping}. @@ -138,97 +67,33 @@ public final RepositoryMapping getRepoMappingWithBazelDepsOnly() { return RepositoryMapping.create(mapping.buildOrThrow(), getCanonicalRepoName()); } - // TODO(salmasamy) create two modules (One with registry, one with repospec and only necessary - // things for lockfile) - /** - * The registry where this module came from. Must be null iff the module has a {@link - * NonRegistryOverride}. Set to null after running selection and verifying yanked versions. - */ - @Nullable - public abstract Registry getRegistry(); - /** - * The repo spec for this module (information about the attributes of its repository rule) Filled - * after running selection to avoid extra calls to the registry. + * The repo spec for this module (information about the attributes of its repository rule). This + * is only non-null for modules coming from registries (i.e. without non-registry overrides). */ @Nullable public abstract RepoSpec getRepoSpec(); - /** The module extensions used in this module. */ - public abstract ImmutableList getExtensionUsages(); - - /** Returns a {@link Builder} that starts out with the same fields as this object. */ - abstract Builder toBuilder(); - /** Returns a new, empty {@link Builder}. */ public static Builder builder() { - return new AutoValue_Module.Builder() - .setName("") - .setVersion(Version.EMPTY) - .setKey(ModuleKey.ROOT) - .setCompatibilityLevel(0); - } - - /** - * Returns a new {@link Module} with all values in {@link #getDeps} transformed using the given - * function. - */ - public Module withDepKeysTransformed(UnaryOperator transform) { - return toBuilder() - .setDeps(ImmutableMap.copyOf(Maps.transformValues(getDeps(), transform::apply))) - .build(); + return new AutoValue_Module.Builder(); } /** Builder type for {@link Module}. */ @AutoValue.Builder public abstract static class Builder { - /** Optional; defaults to the empty string. */ public abstract Builder setName(String value); - /** Optional; defaults to {@link Version#EMPTY}. */ public abstract Builder setVersion(Version value); - /** Optional; defaults to {@link ModuleKey#ROOT}. */ public abstract Builder setKey(ModuleKey value); - /** Optional; defaults to {@code 0}. */ - public abstract Builder setCompatibilityLevel(int value); - - /** Optional; defaults to {@link #setName}. */ public abstract Builder setRepoName(String value); - public abstract Builder setBazelCompatibility(ImmutableList value); - - abstract ImmutableList.Builder bazelCompatibilityBuilder(); - - @CanIgnoreReturnValue - public final Builder addBazelCompatibilityValues(Iterable values) { - bazelCompatibilityBuilder().addAll(values); - return this; - } - public abstract Builder setExecutionPlatformsToRegister(ImmutableList value); - abstract ImmutableList.Builder executionPlatformsToRegisterBuilder(); - - @CanIgnoreReturnValue - public final Builder addExecutionPlatformsToRegister(Iterable values) { - executionPlatformsToRegisterBuilder().addAll(values); - return this; - } - public abstract Builder setToolchainsToRegister(ImmutableList value); - abstract ImmutableList.Builder toolchainsToRegisterBuilder(); - - @CanIgnoreReturnValue - public final Builder addToolchainsToRegister(Iterable values) { - toolchainsToRegisterBuilder().addAll(values); - return this; - } - - public abstract Builder setOriginalDeps(ImmutableMap value); - public abstract Builder setDeps(ImmutableMap value); abstract ImmutableMap.Builder depsBuilder(); @@ -239,16 +104,6 @@ public Builder addDep(String depRepoName, ModuleKey depKey) { return this; } - abstract ImmutableMap.Builder originalDepsBuilder(); - - @CanIgnoreReturnValue - public Builder addOriginalDep(String depRepoName, ModuleKey depKey) { - originalDepsBuilder().put(depRepoName, depKey); - return this; - } - - public abstract Builder setRegistry(Registry value); - public abstract Builder setRepoSpec(RepoSpec value); public abstract Builder setExtensionUsages(ImmutableList value); @@ -261,19 +116,6 @@ public Builder addExtensionUsage(ModuleExtensionUsage value) { return this; } - abstract ModuleKey getKey(); - - abstract String getName(); - - abstract Optional getRepoName(); - - abstract Module autoBuild(); - - final Module build() { - if (getRepoName().isEmpty()) { - setRepoName(getName()); - } - return autoBuild(); - } + abstract Module build(); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleBase.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleBase.java new file mode 100644 index 00000000000000..67e8d37588a5e1 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleBase.java @@ -0,0 +1,78 @@ +// Copyright 2023 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.common.collect.ImmutableList; +import com.google.devtools.build.lib.cmdline.RepositoryName; + +/** Represents a node in the external dependency graph. */ +abstract class ModuleBase { + + /** + * The name of the module, as specified in this module's MODULE.bazel file. Can be empty if this + * is the root module. + */ + public abstract String getName(); + + /** + * The version of the module, as specified in this module's MODULE.bazel file. Can be empty if + * this is the root module, or if this module comes from a {@link NonRegistryOverride}. + */ + public abstract Version getVersion(); + + /** + * The key of this module in the dependency graph. Note that, although a {@link ModuleKey} is also + * just a (name, version) pair, its semantics differ from {@link #getName} and {@link + * #getVersion}, which are always as specified in the MODULE.bazel file. The {@link ModuleKey} + * returned by this method, however, will have the following special semantics: + * + *
    + *
  • The name of the {@link ModuleKey} is the same as {@link #getName}, unless this is the + * root module, in which case the name of the {@link ModuleKey} must be empty. + *
  • The version of the {@link ModuleKey} is the same as {@link #getVersion}, unless this is + * the root module OR this module has a {@link NonRegistryOverride}, in which case the + * version of the {@link ModuleKey} must be empty. + *
+ */ + public abstract ModuleKey getKey(); + + public final RepositoryName getCanonicalRepoName() { + return getKey().getCanonicalRepoName(); + } + + /** + * The name of the repository representing this module, as seen by the module itself. By default, + * the name of the repo is the name of the module. This can be specified to ease migration for + * projects that have been using a repo name for itself that differs from its module name. + */ + public abstract String getRepoName(); + + /** + * Target patterns identifying execution platforms to register when this module is selected. Note + * that these are what was written in module files verbatim, and don't contain canonical repo + * names. + */ + public abstract ImmutableList getExecutionPlatformsToRegister(); + + /** + * Target patterns identifying toolchains to register when this module is selected. Note that + * these are what was written in module files verbatim, and don't contain canonical repo names. + */ + public abstract ImmutableList getToolchainsToRegister(); + + /** The module extensions used in this module. */ + public abstract ImmutableList getExtensionUsages(); +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunction.java index d9714602c8f71c..18efa92425018a 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunction.java @@ -123,7 +123,7 @@ public SkyValue compute(SkyKey skyKey, Environment env) env); // Perform some sanity checks. - Module module = moduleFileGlobals.buildModule(); + InterimModule module = moduleFileGlobals.buildModule(); if (!module.getName().equals(moduleKey.getName())) { throw errorf( Code.BAD_MODULE, @@ -159,12 +159,12 @@ private SkyValue computeForRootModule(StarlarkSemantics starlarkSemantics, Envir ModuleFileGlobals moduleFileGlobals = execModuleFile( moduleFile, - /*registry=*/ null, + /* registry= */ null, ModuleKey.ROOT, /* ignoreDevDeps= */ Objects.requireNonNull(IGNORE_DEV_DEPS.get(env)), starlarkSemantics, env); - Module module = moduleFileGlobals.buildModule(); + InterimModule module = moduleFileGlobals.buildModule(); ImmutableMap moduleOverrides = moduleFileGlobals.buildOverrides(); Map commandOverrides = MODULE_OVERRIDES.get(env); diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileGlobals.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileGlobals.java index a141e2c4c7df49..c2800b99f70759 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileGlobals.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileGlobals.java @@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.docgen.annot.DocumentMethods; +import com.google.devtools.build.lib.bazel.bzlmod.InterimModule.DepSpec; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileGlobals.ModuleExtensionUsageBuilder.ModuleExtensionProxy; import com.google.devtools.build.lib.bazel.bzlmod.Version.ParseException; import com.google.devtools.build.lib.cmdline.RepositoryName; @@ -64,8 +65,8 @@ public class ModuleFileGlobals { private boolean moduleCalled = false; private boolean hadNonModuleCall = false; private final boolean ignoreDevDeps; - private final Module.Builder module; - private final Map deps = new LinkedHashMap<>(); + private final InterimModule.Builder module; + private final Map deps = new LinkedHashMap<>(); private final List extensionUsageBuilders = new ArrayList<>(); private final Map overrides = new HashMap<>(); private final Map repoNameUsages = new HashMap<>(); @@ -75,7 +76,7 @@ public ModuleFileGlobals( ModuleKey key, @Nullable Registry registry, boolean ignoreDevDeps) { - module = Module.builder().setKey(key).setRegistry(registry); + module = InterimModule.builder().setKey(key).setRegistry(registry); this.ignoreDevDeps = ignoreDevDeps; if (ModuleKey.ROOT.equals(key)) { overrides.putAll(builtinModules); @@ -85,7 +86,7 @@ public ModuleFileGlobals( // The built-in module does not depend on itself. continue; } - deps.put(builtinModule, ModuleKey.create(builtinModule, Version.EMPTY)); + deps.put(builtinModule, DepSpec.create(builtinModule, Version.EMPTY, -1)); try { addRepoNameUsage(builtinModule, "as a built-in dependency", Location.BUILTIN); } catch (EvalException e) { @@ -280,6 +281,16 @@ private static ImmutableList checkAllCompatibilityVersions( named = true, positional = false, defaultValue = "''"), + @Param( + name = "max_compatibility_level", + doc = + "The maximum compatibility_level supported for the module to be added" + + " as a direct dependency. The version of the module implies the minimum" + + " compatibility_level supported, as well as the maximum if this attribute is" + + " not specified.", + named = true, + positional = false, + defaultValue = "-1"), @Param( name = "repo_name", doc = @@ -299,7 +310,12 @@ private static ImmutableList checkAllCompatibilityVersions( }, useStarlarkThread = true) public void bazelDep( - String name, String version, String repoName, boolean devDependency, StarlarkThread thread) + String name, + String version, + StarlarkInt maxCompatibilityLevel, + String repoName, + boolean devDependency, + StarlarkThread thread) throws EvalException { hadNonModuleCall = true; if (repoName.isEmpty()) { @@ -315,7 +331,10 @@ public void bazelDep( RepositoryName.validateUserProvidedRepoName(repoName); if (!(ignoreDevDeps && devDependency)) { - deps.put(repoName, ModuleKey.create(name, parsedVersion)); + deps.put( + repoName, + DepSpec.create( + name, parsedVersion, maxCompatibilityLevel.toInt("max_compatibility_level"))); } addRepoNameUsage(repoName, "by a bazel_dep", thread.getCallerLocation()); @@ -879,7 +898,7 @@ public void localPathOverride(String moduleName, String path) throws EvalExcepti addOverride(moduleName, LocalPathOverride.create(path)); } - public Module buildModule() { + public InterimModule buildModule() { return module .setDeps(ImmutableMap.copyOf(deps)) .setOriginalDeps(ImmutableMap.copyOf(deps)) diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileValue.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileValue.java index 48d47e8e87ac02..01628b8df17bc7 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileValue.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileValue.java @@ -38,7 +38,7 @@ public abstract class ModuleFileValue implements SkyValue { * module might not match the one in the requesting {@link SkyKey} in certain circumstances (for * example, for the root module, or when non-registry overrides are in play. */ - public abstract Module getModule(); + public abstract InterimModule getModule(); /** The hash string of Module.bazel (using SHA256) */ public abstract String getModuleFileHash(); @@ -47,7 +47,7 @@ public abstract class ModuleFileValue implements SkyValue { @AutoValue public abstract static class NonRootModuleFileValue extends ModuleFileValue { - public static NonRootModuleFileValue create(Module module, String moduleFileHash) { + public static NonRootModuleFileValue create(InterimModule module, String moduleFileHash) { return new AutoValue_ModuleFileValue_NonRootModuleFileValue(module, moduleFileHash); } } @@ -72,7 +72,7 @@ public abstract static class RootModuleFileValue extends ModuleFileValue { getNonRegistryOverrideCanonicalRepoNameLookup(); public static RootModuleFileValue create( - Module module, + InterimModule module, String moduleFileHash, ImmutableMap overrides, ImmutableMap nonRegistryOverrideCanonicalRepoNameLookup) { diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Selection.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Selection.java index bcacb7b1928ba9..361f5231fe850c 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Selection.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/Selection.java @@ -15,6 +15,10 @@ package com.google.devtools.build.lib.bazel.bzlmod; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap; +import static java.util.Comparator.naturalOrder; + import com.google.auto.value.AutoValue; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; @@ -22,14 +26,19 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.devtools.build.lib.bazel.bzlmod.InterimModule.DepSpec; import com.google.devtools.build.lib.server.FailureDetails.ExternalDeps.Code; import java.util.ArrayDeque; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; +import java.util.function.Function; import javax.annotation.Nullable; /** @@ -62,11 +71,41 @@ * be removed before the end of selection (by becoming unreachable, for example), otherwise * it'll be an error since they're not allowed by the override (these versions are in * selection groups that have no valid target allowed version). + *
  • Things get even more complicated with max_compatibility_level. The difference this + * introduces is that each "DepSpec" could be satisfied by one of multiple choices. (Without + * max_compatibility_level, there is always only one choice.) So what we do is go through all + * the combinations of possible choices for each distinct DepSpec, and for each combination, + * see if the resulting dep graph is valid. As soon as we find a valid combination, we return + * that result. The distinct DepSpecs are sorted by the order they first appear in the dep + * graph if we BFS from the root module. The combinations are attempted in the typical + * cartesian product order (see {@link Lists#cartesianProduct}); the "version choices" of each + * DepSpec are sorted from low to high. * */ final class Selection { private Selection() {} + /** The result of selection. */ + @AutoValue + abstract static class Result { + /** Final dep graph sorted in BFS iteration order, with unused modules removed. */ + abstract ImmutableMap getResolvedDepGraph(); + + /** + * Un-pruned dep graph, with updated dep keys, and additionally containing the unused modules + * which were initially discovered (and their MODULE.bazel files loaded). Does not contain + * modules overridden by {@code single_version_override} or {@link NonRegistryOverride}, only by + * {@code multiple_version_override}. + */ + abstract ImmutableMap getUnprunedDepGraph(); + + static Result create( + ImmutableMap resolvedDepGraph, + ImmutableMap unprunedDepGraph) { + return new AutoValue_Selection_Result(resolvedDepGraph, unprunedDepGraph); + } + } + /** During selection, a version is selected for each distinct "selection group". */ @AutoValue abstract static class SelectionGroup { @@ -102,7 +141,8 @@ static ModuleNameAndCompatibilityLevel create(String moduleName, int compatibili */ private static ImmutableMap> computeAllowedVersionSets( - ImmutableMap overrides, ImmutableMap depGraph) + ImmutableMap overrides, + ImmutableMap depGraph) throws ExternalDepsException { Map> allowedVersionSets = new HashMap<>(); @@ -114,7 +154,8 @@ static ModuleNameAndCompatibilityLevel create(String moduleName, int compatibili } ImmutableList allowedVersions = ((MultipleVersionOverride) override).getVersions(); for (Version allowedVersion : allowedVersions) { - Module allowedVersionModule = depGraph.get(ModuleKey.create(moduleName, allowedVersion)); + InterimModule allowedVersionModule = + depGraph.get(ModuleKey.create(moduleName, allowedVersion)); if (allowedVersionModule == null) { throw ExternalDepsException.withMessage( Code.VERSION_RESOLUTION_ERROR, @@ -143,7 +184,7 @@ static ModuleNameAndCompatibilityLevel create(String moduleName, int compatibili * used to compute its targetAllowedVersion. */ private static SelectionGroup computeSelectionGroup( - Module module, + InterimModule module, ImmutableMap> allowedVersionSets) { ImmutableSortedSet allowedVersionSet = @@ -152,10 +193,11 @@ private static SelectionGroup computeSelectionGroup( module.getName(), module.getCompatibilityLevel())); if (allowedVersionSet == null) { // This means that this module has no multiple-version override. - return SelectionGroup.create(module.getName(), module.getCompatibilityLevel(), Version.EMPTY); + return SelectionGroup.create( + module.getKey().getName(), module.getCompatibilityLevel(), Version.EMPTY); } return SelectionGroup.create( - module.getName(), + module.getKey().getName(), module.getCompatibilityLevel(), // We use the `ceiling` method here to quickly locate the lowest allowed version that's // still no lower than this module's version. @@ -166,10 +208,94 @@ private static SelectionGroup computeSelectionGroup( } /** - * Runs module selection (aka version resolution). Returns a {@link BazelModuleResolutionValue}. + * Computes the possible list of ModuleKeys a single given DepSpec can resolve to. This is + * normally just one ModuleKey, but when max_compatibility_level is involved, multiple choices may + * be possible. + */ + private static ImmutableList computePossibleResolutionResultsForOneDepSpec( + DepSpec depSpec, + ImmutableMap selectionGroups, + Map selectedVersions) { + int minCompatibilityLevel = selectionGroups.get(depSpec.toModuleKey()).getCompatibilityLevel(); + int maxCompatibilityLevel = + depSpec.getMaxCompatibilityLevel() < 0 + ? minCompatibilityLevel + : depSpec.getMaxCompatibilityLevel(); + // First find the selection groups that this DepSpec could use. + return Maps.filterKeys( + selectedVersions, + group -> + group.getModuleName().equals(depSpec.getName()) + && group.getCompatibilityLevel() >= minCompatibilityLevel + && group.getCompatibilityLevel() <= maxCompatibilityLevel + && group.getTargetAllowedVersion().compareTo(depSpec.getVersion()) >= 0) + .entrySet() + .stream() + // Collect into an ImmutableSortedMap so that: + // 1. The final list is sorted by compatibility level, guaranteeing lowest version first; + // 2. Only one ModuleKey is attempted per compatibility level, so that in the case of a + // multiple-version override, we only try the lowest allowed version in that + // compatibility level (note the Comparators::min call). + .collect( + toImmutableSortedMap( + naturalOrder(), + e -> e.getKey().getCompatibilityLevel(), + e -> e.getValue(), + Comparators::min)) + .values() + .stream() + .map(v -> ModuleKey.create(depSpec.getName(), v)) + .collect(toImmutableList()); + } + + /** + * Computes the possible list of ModuleKeys a DepSpec can resolve to, for all distinct DepSpecs in + * the dependency graph. + */ + private static ImmutableMap> computePossibleResolutionResults( + ImmutableMap depGraph, + ImmutableMap selectionGroups, + Map selectedVersions) { + // Important that we use a LinkedHashMap here to ensure reproducibility. + Map> results = new LinkedHashMap<>(); + for (InterimModule module : depGraph.values()) { + for (DepSpec depSpec : module.getDeps().values()) { + results.computeIfAbsent( + depSpec, + ds -> + computePossibleResolutionResultsForOneDepSpec( + ds, selectionGroups, selectedVersions)); + } + } + return ImmutableMap.copyOf(results); + } + + /** + * Given the possible list of ModuleKeys each DepSpec can resolve to, enumerate through all the + * possible resolution strategies. Each strategy assigns each DepSpec to a single ModuleKey out of + * its possible list. */ - public static BazelModuleResolutionValue run( - ImmutableMap depGraph, ImmutableMap overrides) + private static List> enumerateStrategies( + ImmutableMap> possibleResolutionResults) { + Map depSpecToPosition = new HashMap<>(); + int position = 0; + for (DepSpec depSpec : possibleResolutionResults.keySet()) { + depSpecToPosition.put(depSpec, position++); + } + return Lists.transform( + Lists.cartesianProduct(possibleResolutionResults.values().asList()), + (List choices) -> + (DepSpec depSpec) -> choices.get(depSpecToPosition.get(depSpec))); + // TODO(wyv): There are some strategies that we could eliminate earlier. For example, the + // strategy where (foo@1.1, maxCL=3) resolves to foo@2.0 and (foo@1.2, maxCL=3) resolves to + // foo@3.0 is obviously not valid. All foo@? should resolve to the same version (assuming no + // multiple-version override). + } + + /** Runs module selection (aka version resolution). */ + public static Result run( + ImmutableMap depGraph, + ImmutableMap overrides) throws ExternalDepsException { // For any multiple-version overrides, build a mapping from (moduleName, compatibilityLevel) to // the set of allowed versions. @@ -193,42 +319,55 @@ public static BazelModuleResolutionValue run( selectedVersions.merge(selectionGroup, key.getVersion(), Comparators::max); } - // Build a new dep graph where deps with unselected versions are removed. - ImmutableMap.Builder newDepGraphBuilder = new ImmutableMap.Builder<>(); - - // Also keep a version of the full dep graph with updated deps. - ImmutableMap.Builder unprunedDepGraphBuilder = new ImmutableMap.Builder<>(); - for (Module module : depGraph.values()) { - // Rewrite deps to point to the selected version. - ModuleKey key = module.getKey(); - Module updatedModule = - module.withDepKeysTransformed( - depKey -> - ModuleKey.create( - depKey.getName(), selectedVersions.get(selectionGroups.get(depKey)))); - - // Add all updated modules to the un-pruned dep graph. - unprunedDepGraphBuilder.put(key, updatedModule); - - // Remove any dep whose version isn't selected from the resolved graph. - Version selectedVersion = selectedVersions.get(selectionGroups.get(module.getKey())); - if (module.getKey().getVersion().equals(selectedVersion)) { - newDepGraphBuilder.put(key, updatedModule); + // Compute the possible list of ModuleKeys that each DepSpec could resolve to. + ImmutableMap> possibleResolutionResults = + computePossibleResolutionResults(depGraph, selectionGroups, selectedVersions); + for (Map.Entry> e : possibleResolutionResults.entrySet()) { + if (e.getValue().isEmpty()) { + throw ExternalDepsException.withMessage( + Code.VERSION_RESOLUTION_ERROR, + "Unexpected error: %s has no valid resolution result", + e.getKey()); } } - ImmutableMap newDepGraph = newDepGraphBuilder.buildOrThrow(); - ImmutableMap unprunedDepGraph = unprunedDepGraphBuilder.buildOrThrow(); - - // Further, removes unreferenced modules from the graph. We can find out which modules are - // referenced by collecting deps transitively from the root. - // We can also take this opportunity to check that none of the remaining modules conflict with - // each other (e.g. same module name but different compatibility levels, or not satisfying - // multiple_version_override). - ImmutableMap prunedDepGraph = - new DepGraphWalker(newDepGraph, overrides, selectionGroups).walk(); - - // Return the result containing both the pruned and un-pruned dep graphs - return BazelModuleResolutionValue.create(prunedDepGraph, unprunedDepGraph); + + // Each DepSpec may resolve to one or more ModuleKeys. We try out every single possible + // combination; in other words, we enumerate through the cartesian product of the "possible + // resolution result" set for every distinct DepSpec. Each element of this cartesian product is + // essentially a mapping from DepSpecs to ModuleKeys; we can call this mapping a "resolution + // strategy". + // + // Given a resolution strategy, we can walk through the graph from the root module, and see if + // the strategy yields a valid graph (only containing the nodes reachable from the root). If the + // graph is invalid (for example, because there are modules with different compatibility + // levels), we try the next resolution strategy. When all strategies are exhausted, we know + // there is no way to achieve a valid selection result, so we report the failure from the time + // we attempted to walk the graph using the first resolution strategy. + DepGraphWalker depGraphWalker = new DepGraphWalker(depGraph, overrides, selectionGroups); + ExternalDepsException firstFailure = null; + for (Function resolutionStrategy : + enumerateStrategies(possibleResolutionResults)) { + try { + ImmutableMap prunedDepGraph = + depGraphWalker.walk(resolutionStrategy); + // If the call above didn't throw, we have a valid graph. Go ahead and produce a result! + ImmutableMap unprunedDepGraph = + ImmutableMap.copyOf( + Maps.transformValues( + depGraph, + module -> + module.withDepSpecsTransformed( + depSpec -> DepSpec.fromModuleKey(resolutionStrategy.apply(depSpec))))); + return Result.create(prunedDepGraph, unprunedDepGraph); + } catch (ExternalDepsException e) { + if (firstFailure == null) { + firstFailure = e; + } + } + } + // firstFailure cannot be null, since enumerateStrategies(...) cannot be empty, since no + // element of possibleResolutionResults is empty. + throw firstFailure; } /** @@ -237,27 +376,27 @@ public static BazelModuleResolutionValue run( */ static class DepGraphWalker { private static final Joiner JOINER = Joiner.on(", "); - private final ImmutableMap oldDepGraph; + private final ImmutableMap oldDepGraph; private final ImmutableMap overrides; private final ImmutableMap selectionGroups; - private final HashMap moduleByName; DepGraphWalker( - ImmutableMap oldDepGraph, + ImmutableMap oldDepGraph, ImmutableMap overrides, ImmutableMap selectionGroups) { this.oldDepGraph = oldDepGraph; this.overrides = overrides; this.selectionGroups = selectionGroups; - this.moduleByName = new HashMap<>(); } /** * Walks the old dep graph and builds a new dep graph containing only deps reachable from the * root module. The returned map has a guaranteed breadth-first iteration order. */ - ImmutableMap walk() throws ExternalDepsException { - ImmutableMap.Builder newDepGraph = ImmutableMap.builder(); + ImmutableMap walk(Function resolutionStrategy) + throws ExternalDepsException { + HashMap moduleByName = new HashMap<>(); + ImmutableMap.Builder newDepGraph = ImmutableMap.builder(); Set known = new HashSet<>(); Queue toVisit = new ArrayDeque<>(); toVisit.add(ModuleKeyAndDependent.create(ModuleKey.ROOT, null)); @@ -265,12 +404,16 @@ ImmutableMap walk() throws ExternalDepsException { while (!toVisit.isEmpty()) { ModuleKeyAndDependent moduleKeyAndDependent = toVisit.remove(); ModuleKey key = moduleKeyAndDependent.getModuleKey(); - Module module = oldDepGraph.get(key); - visit(key, module, moduleKeyAndDependent.getDependent()); - - for (ModuleKey depKey : module.getDeps().values()) { - if (known.add(depKey)) { - toVisit.add(ModuleKeyAndDependent.create(depKey, key)); + InterimModule module = + oldDepGraph + .get(key) + .withDepSpecsTransformed( + depSpec -> DepSpec.fromModuleKey(resolutionStrategy.apply(depSpec))); + visit(key, module, moduleKeyAndDependent.getDependent(), moduleByName); + + for (DepSpec depSpec : module.getDeps().values()) { + if (known.add(depSpec.toModuleKey())) { + toVisit.add(ModuleKeyAndDependent.create(depSpec.toModuleKey(), key)); } } newDepGraph.put(key, module); @@ -278,7 +421,11 @@ ImmutableMap walk() throws ExternalDepsException { return newDepGraph.buildOrThrow(); } - void visit(ModuleKey key, Module module, @Nullable ModuleKey from) + void visit( + ModuleKey key, + InterimModule module, + @Nullable ModuleKey from, + HashMap moduleByName) throws ExternalDepsException { ModuleOverride override = overrides.get(key.getName()); if (override instanceof MultipleVersionOverride) { @@ -321,10 +468,10 @@ void visit(ModuleKey key, Module module, @Nullable ModuleKey from) // Make sure that we don't have `module` depending on the same dependency version twice. HashMap depKeyToRepoName = new HashMap<>(); - for (Map.Entry depEntry : module.getDeps().entrySet()) { + for (Map.Entry depEntry : module.getDeps().entrySet()) { String repoName = depEntry.getKey(); - ModuleKey depKey = depEntry.getValue(); - String previousRepoName = depKeyToRepoName.put(depKey, repoName); + DepSpec depSpec = depEntry.getValue(); + String previousRepoName = depKeyToRepoName.put(depSpec.toModuleKey(), repoName); if (previousRepoName != null) { throw ExternalDepsException.withMessage( Code.VERSION_RESOLUTION_ERROR, @@ -332,7 +479,7 @@ void visit(ModuleKey key, Module module, @Nullable ModuleKey from) + " multiple_version_override if you want to depend on multiple versions of" + " %s simultaneously", key, - depKey, + depSpec.toModuleKey(), repoName, previousRepoName, key.getName()); diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java index e4942e3efadb7d..a7c5c48e0357b4 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BzlmodRepoRuleFunction.java @@ -14,7 +14,6 @@ package com.google.devtools.build.lib.skyframe; -import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -163,9 +162,7 @@ private Optional checkRepoFromBazelModules( if (moduleKey == null) { return Optional.empty(); } - com.google.devtools.build.lib.bazel.bzlmod.Module module = - bazelDepGraphValue.getDepGraph().get(moduleKey); - return Optional.of(checkNotNull(module.getRepoSpec())); + return Optional.of(bazelDepGraphValue.getDepGraph().get(moduleKey).getRepoSpec()); } @Nullable diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunctionTest.java index b1979e9a6515ef..3e10c004b73f03 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelDepGraphFunctionTest.java @@ -17,6 +17,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.buildModule; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createRepositoryMapping; import static org.junit.Assert.fail; @@ -162,9 +163,7 @@ public void createValue_basic() throws Exception { ImmutableMap.builder() .put( ModuleKey.ROOT, - Module.builder() - .setName("my_root") - .setVersion(Version.parse("1.0")) + buildModule("my_root", "1.0") .setKey(ModuleKey.ROOT) .addDep("my_dep_1", createModuleKey("dep", "1.0")) .addDep("my_dep_2", createModuleKey("dep", "2.0")) @@ -172,33 +171,14 @@ public void createValue_basic() throws Exception { .build()) .put( createModuleKey("dep", "1.0"), - Module.builder() - .setName("dep") - .setVersion(Version.parse("1.0")) - .setKey(createModuleKey("dep", "1.0")) + buildModule("dep", "1.0") .addDep("rules_java", createModuleKey("rules_java", "")) .build()) - .put( - createModuleKey("dep", "2.0"), - Module.builder() - .setName("dep") - .setVersion(Version.parse("2.0")) - .setKey(createModuleKey("dep", "2.0")) - .build()) - .put( - createModuleKey("rules_cc", "1.0"), - Module.builder() - .setName("rules_cc") - .setVersion(Version.parse("1.0")) - .setKey(createModuleKey("rules_cc", "1.0")) - .build()) + .put(createModuleKey("dep", "2.0"), buildModule("dep", "2.0").build()) + .put(createModuleKey("rules_cc", "1.0"), buildModule("rules_cc", "1.0").build()) .put( createModuleKey("rules_java", ""), - Module.builder() - .setName("rules_java") - .setVersion(Version.parse("1.0")) - .setKey(createModuleKey("rules_java", "")) - .build()) + buildModule("rules_java", "1.0").setKey(createModuleKey("rules_java", "")).build()) .buildOrThrow(); resolutionFunctionMock.setDepGraph(depGraph); @@ -248,9 +228,7 @@ public void createValue_moduleExtensions() throws Exception { "module(name='my_root', version='1.0')"); Module root = - Module.builder() - .setName("root") - .setVersion(Version.parse("1.0")) + buildModule("root", "1.0") .setKey(ModuleKey.ROOT) .addDep("rje", createModuleKey("rules_jvm_external", "1.0")) .addDep("rpy", createModuleKey("rules_python", "2.0")) @@ -261,9 +239,7 @@ public void createValue_moduleExtensions() throws Exception { .build(); ModuleKey depKey = createModuleKey("dep", "2.0"); Module dep = - Module.builder() - .setName("dep") - .setVersion(Version.parse("2.0")) + buildModule("dep", "2.0") .setKey(depKey) .addDep("rules_python", createModuleKey("rules_python", "2.0")) .addExtensionUsage( @@ -352,7 +328,7 @@ public void useExtensionBadLabelFails() throws Exception { "module(name='module', version='1.0')"); Module root = - Module.builder() + buildModule("module", "1.0") .addExtensionUsage(createModuleExtensionUsage("@foo//:defs.bzl", "bar")) .build(); ImmutableMap depGraph = ImmutableMap.of(ModuleKey.ROOT, root); diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunctionTest.java index 9a20ae0f24a551..e10d52d15924fb 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelLockFileFunctionTest.java @@ -67,7 +67,6 @@ import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; -import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import javax.annotation.Nullable; @@ -221,9 +220,10 @@ public void simpleModule() throws Exception { RootModuleFileValue rootValue = rootResult.get(ModuleFileValue.KEY_FOR_ROOT_MODULE); ImmutableMap depGraph = - ImmutableMap.builder() - .put(ModuleKey.ROOT, rootValue.getModule()) - .buildOrThrow(); + ImmutableMap.of( + ModuleKey.ROOT, + BazelModuleResolutionFunction.moduleFromInterimModule( + rootValue.getModule(), null, null)); UpdateLockFileKey key = UpdateLockFileKey.create("moduleHash", depGraph, rootValue.getOverrides()); @@ -259,9 +259,10 @@ public void moduleWithFlags() throws Exception { RootModuleFileValue rootValue = rootResult.get(ModuleFileValue.KEY_FOR_ROOT_MODULE); ImmutableMap depGraph = - ImmutableMap.builder() - .put(ModuleKey.ROOT, rootValue.getModule()) - .buildOrThrow(); + ImmutableMap.of( + ModuleKey.ROOT, + BazelModuleResolutionFunction.moduleFromInterimModule( + rootValue.getModule(), null, null)); ImmutableList yankedVersions = ImmutableList.of("2.4", "2.3"); LocalPathOverride override = LocalPathOverride.create("override_path"); @@ -300,7 +301,7 @@ public void moduleWithFlags() throws Exception { } @Test - public void moduleWithLocalOverrides() throws IOException, InterruptedException { + public void moduleWithLocalOverrides() throws Exception { scratch.file( rootDirectory.getRelative("MODULE.bazel").getPathString(), "module(name='root',version='0.1')", @@ -319,9 +320,10 @@ public void moduleWithLocalOverrides() throws IOException, InterruptedException RootModuleFileValue rootValue = rootResult.get(ModuleFileValue.KEY_FOR_ROOT_MODULE); ImmutableMap depGraph = - ImmutableMap.builder() - .put(ModuleKey.ROOT, rootValue.getModule()) - .buildOrThrow(); + ImmutableMap.of( + ModuleKey.ROOT, + BazelModuleResolutionFunction.moduleFromInterimModule( + rootValue.getModule(), null, null)); UpdateLockFileKey key = UpdateLockFileKey.create("moduleHash", depGraph, rootValue.getOverrides()); @@ -363,9 +365,10 @@ public void fullModule() throws Exception { RootModuleFileValue rootValue = rootResult.get(ModuleFileValue.KEY_FOR_ROOT_MODULE); ImmutableMap depGraph = - ImmutableMap.builder() - .put(ModuleKey.ROOT, rootValue.getModule()) - .buildOrThrow(); + ImmutableMap.of( + ModuleKey.ROOT, + BazelModuleResolutionFunction.moduleFromInterimModule( + rootValue.getModule(), null, null)); UpdateLockFileKey key = UpdateLockFileKey.create("moduleHash", depGraph, rootValue.getOverrides()); diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunctionTest.java index ce2027c7b6c27c..1fb7765c802bbc 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleInspectorFunctionTest.java @@ -24,7 +24,7 @@ import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleInspectorValue.AugmentedModule; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleInspectorValue.AugmentedModule.ResolutionReason; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.ModuleBuilder; +import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.InterimModuleBuilder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -35,25 +35,25 @@ public class BazelModuleInspectorFunctionTest { @Test public void testDiamond_simple() throws Exception { - ImmutableMap unprunedDepGraph = - ImmutableMap.builder() + ImmutableMap unprunedDepGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ddd", "2.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) .buildOrThrow(); ImmutableSet usedModules = @@ -91,29 +91,29 @@ public void testDiamond_simple() throws Exception { @Test public void testDiamond_withFurtherRemoval() throws Exception { - ImmutableMap unprunedDepGraph = - ImmutableMap.builder() + ImmutableMap unprunedDepGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd", createModuleKey("ddd", "2.0")) .addOriginalDep("ddd", createModuleKey("ddd", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd", createModuleKey("ddd", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "2.0").buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0").buildEntry()) .put( - ModuleBuilder.create("ddd", "1.0") + InterimModuleBuilder.create("ddd", "1.0") .addDep("eee", createModuleKey("eee", "1.0")) .buildEntry()) - .put(ModuleBuilder.create("eee", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("eee", "1.0").buildEntry()) .buildOrThrow(); ImmutableSet usedModules = @@ -154,27 +154,27 @@ public void testDiamond_withFurtherRemoval() throws Exception { @Test public void testCircularDependencyDueToSelection() throws Exception { - ImmutableMap unprunedDepGraph = - ImmutableMap.builder() + ImmutableMap unprunedDepGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("bbb", createModuleKey("bbb", "1.0")) .addOriginalDep("bbb", createModuleKey("bbb", "1.0-pre")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0-pre") + InterimModuleBuilder.create("bbb", "1.0-pre") .addDep("ddd", createModuleKey("ddd", "1.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0").buildEntry()) .buildOrThrow(); ImmutableSet usedModules = @@ -210,23 +210,23 @@ public void testSingleVersionOverride_withRemoval() throws Exception { // single_version_override (ccc, 2.0) // aaa -> bbb 1.0 -> ccc 1.0 -> ddd 1.0 // ccc 2.0 -> ddd 2.0 - ImmutableMap unprunedDepGraph = - ImmutableMap.builder() + ImmutableMap unprunedDepGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd", createModuleKey("ddd", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "2.0").buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0").buildEntry()) .buildOrThrow(); ImmutableMap overrides = @@ -271,20 +271,20 @@ public void testNonRegistryOverride_withRemoval() throws Exception { // archive_override "file://users/user/bbb.zip" // aaa -> bbb 1.0 -> ccc 1.0 (not loaded) // (local) bbb 1.0-hotfix -> ccc 1.1 - ImmutableMap unprunedDepGraph = - ImmutableMap.builder() + ImmutableMap unprunedDepGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "")) .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .setKey(createModuleKey("bbb", "")) .addDep("ccc", createModuleKey("ccc", "1.1")) .buildEntry()) - .put(ModuleBuilder.create("ccc", "1.1").buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.1").buildEntry()) .buildOrThrow(); ImmutableMap overrides = @@ -328,27 +328,27 @@ public void testMultipleVersionOverride_simpleSnapToHigher() throws Exception { // \-> ccc 2.0 // multiple_version_override ccc: [1.5, 2.0] // multiple_version_override bbb: [1.0, 2.0] - ImmutableMap unprunedDepGraph = - ImmutableMap.builder() + ImmutableMap unprunedDepGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb", "1.0")) .addDep("bbb2", createModuleKey("bbb", "2.0")) .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "1.5")) .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "2.0") + InterimModuleBuilder.create("bbb", "2.0") .addDep("ccc", createModuleKey("ccc", "1.5")) .buildEntry()) - .put(ModuleBuilder.create("ccc", "1.0").buildEntry()) - .put(ModuleBuilder.create("ccc", "1.5").buildEntry()) - .put(ModuleBuilder.create("ccc", "2.0").buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.5").buildEntry()) + .put(InterimModuleBuilder.create("ccc", "2.0").buildEntry()) .buildOrThrow(); ImmutableMap overrides = @@ -412,10 +412,10 @@ public void testMultipleVersionOverride_badDepsUnreferenced() throws Exception { // \ \-> bbb4@1.1 // \-> bbb4@1.1 // ccc@1.5 and ccc@3.0, the versions violating the allowlist, are gone. - ImmutableMap unprunedDepGraph = - ImmutableMap.builder() + ImmutableMap unprunedDepGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.1")) @@ -425,29 +425,29 @@ public void testMultipleVersionOverride_badDepsUnreferenced() throws Exception { .addOriginalDep("bbb4", createModuleKey("bbb4", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.1")) .buildEntry()) .put( - ModuleBuilder.create("bbb2", "1.0") + InterimModuleBuilder.create("bbb2", "1.0") .addDep("ccc", createModuleKey("ccc", "1.5")) .buildEntry()) - .put(ModuleBuilder.create("bbb2", "1.1").buildEntry()) + .put(InterimModuleBuilder.create("bbb2", "1.1").buildEntry()) .put( - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .addDep("bbb4", createModuleKey("bbb4", "1.1")) .buildEntry()) .put( - ModuleBuilder.create("bbb4", "1.0") + InterimModuleBuilder.create("bbb4", "1.0") .addDep("ccc", createModuleKey("ccc", "3.0")) .buildEntry()) - .put(ModuleBuilder.create("bbb4", "1.1").buildEntry()) - .put(ModuleBuilder.create("ccc", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "1.5", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "2.0", 2).buildEntry()) - .put(ModuleBuilder.create("ccc", "3.0", 3).buildEntry()) + .put(InterimModuleBuilder.create("bbb4", "1.1").buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "3.0", 3).buildEntry()) .buildOrThrow(); ImmutableMap overrides = diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodTestUtil.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodTestUtil.java index 484e40e0dce23e..fcd4913153e4d9 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodTestUtil.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodTestUtil.java @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleInspectorValue.AugmentedModule; import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleInspectorValue.AugmentedModule.ResolutionReason; +import com.google.devtools.build.lib.bazel.bzlmod.InterimModule.DepSpec; import com.google.devtools.build.lib.bazel.bzlmod.Version.ParseException; import com.google.devtools.build.lib.cmdline.RepositoryMapping; import com.google.devtools.build.lib.cmdline.RepositoryName; @@ -43,21 +44,41 @@ public static ModuleKey createModuleKey(String name, String version) { } } + public static DepSpec createDepSpec(String name, String version, int maxCompatibilityLevel) { + try { + return DepSpec.create(name, Version.parse(version), maxCompatibilityLevel); + } catch (Version.ParseException e) { + throw new IllegalArgumentException(e); + } + } + + public static Module.Builder buildModule(String name, String version) throws Exception { + return Module.builder() + .setName(name) + .setVersion(Version.parse(version)) + .setRepoName(name) + .setKey(createModuleKey(name, version)) + .setExtensionUsages(ImmutableList.of()) + .setExecutionPlatformsToRegister(ImmutableList.of()) + .setToolchainsToRegister(ImmutableList.of()); + } + /** Builder class to create a {@code Entry} entry faster inside UnitTests */ - static final class ModuleBuilder { - Module.Builder builder; + static final class InterimModuleBuilder { + InterimModule.Builder builder; ModuleKey key; - ImmutableMap.Builder deps = new ImmutableMap.Builder<>(); - ImmutableMap.Builder originalDeps = new ImmutableMap.Builder<>(); + ImmutableMap.Builder deps = new ImmutableMap.Builder<>(); + ImmutableMap.Builder originalDeps = new ImmutableMap.Builder<>(); - private ModuleBuilder() {} + private InterimModuleBuilder() {} - public static ModuleBuilder create(String name, Version version, int compatibilityLevel) { - ModuleBuilder moduleBuilder = new ModuleBuilder(); + public static InterimModuleBuilder create( + String name, Version version, int compatibilityLevel) { + InterimModuleBuilder moduleBuilder = new InterimModuleBuilder(); ModuleKey key = ModuleKey.create(name, version); moduleBuilder.key = key; moduleBuilder.builder = - Module.builder() + InterimModule.builder() .setName(name) .setVersion(version) .setKey(key) @@ -65,84 +86,96 @@ public static ModuleBuilder create(String name, Version version, int compatibili return moduleBuilder; } - public static ModuleBuilder create(String name, String version, int compatibilityLevel) + public static InterimModuleBuilder create(String name, String version, int compatibilityLevel) throws ParseException { return create(name, Version.parse(version), compatibilityLevel); } - public static ModuleBuilder create(String name, String version) throws ParseException { + public static InterimModuleBuilder create(String name, String version) throws ParseException { return create(name, Version.parse(version), 0); } - public static ModuleBuilder create(String name, Version version) throws ParseException { + public static InterimModuleBuilder create(String name, Version version) throws ParseException { return create(name, version, 0); } @CanIgnoreReturnValue - public ModuleBuilder addDep(String depRepoName, ModuleKey key) { - deps.put(depRepoName, key); + public InterimModuleBuilder addDep(String depRepoName, ModuleKey key) { + deps.put(depRepoName, DepSpec.fromModuleKey(key)); + return this; + } + + @CanIgnoreReturnValue + public InterimModuleBuilder addDep(String depRepoName, DepSpec depSpec) { + deps.put(depRepoName, depSpec); + return this; + } + + @CanIgnoreReturnValue + public InterimModuleBuilder addOriginalDep(String depRepoName, ModuleKey key) { + originalDeps.put(depRepoName, DepSpec.fromModuleKey(key)); return this; } @CanIgnoreReturnValue - public ModuleBuilder addOriginalDep(String depRepoName, ModuleKey key) { - originalDeps.put(depRepoName, key); + public InterimModuleBuilder addOriginalDep(String depRepoName, DepSpec depSpec) { + originalDeps.put(depRepoName, depSpec); return this; } @CanIgnoreReturnValue - public ModuleBuilder setKey(ModuleKey value) { + public InterimModuleBuilder setKey(ModuleKey value) { this.key = value; this.builder.setKey(value); return this; } @CanIgnoreReturnValue - public ModuleBuilder setRepoName(String value) { + public InterimModuleBuilder setRepoName(String value) { this.builder.setRepoName(value); return this; } @CanIgnoreReturnValue - public ModuleBuilder setRegistry(FakeRegistry value) { + public InterimModuleBuilder setRegistry(FakeRegistry value) { this.builder.setRegistry(value); return this; } @CanIgnoreReturnValue - public ModuleBuilder addExecutionPlatformsToRegister(ImmutableList value) { + public InterimModuleBuilder addExecutionPlatformsToRegister(ImmutableList value) { this.builder.addExecutionPlatformsToRegister(value); return this; } @CanIgnoreReturnValue - public ModuleBuilder addToolchainsToRegister(ImmutableList value) { + public InterimModuleBuilder addToolchainsToRegister(ImmutableList value) { this.builder.addToolchainsToRegister(value); return this; } @CanIgnoreReturnValue - public ModuleBuilder addExtensionUsage(ModuleExtensionUsage value) { + public InterimModuleBuilder addExtensionUsage(ModuleExtensionUsage value) { this.builder.addExtensionUsage(value); return this; } - public Map.Entry buildEntry() { - Module module = this.build(); + public Map.Entry buildEntry() { + InterimModule module = this.build(); return new SimpleEntry<>(this.key, module); } - public Module build() { - ImmutableMap builtDeps = this.deps.buildOrThrow(); + public InterimModule build() { + ImmutableMap builtDeps = this.deps.buildOrThrow(); /* Copy dep entries that have not been changed to original deps */ - ImmutableMap initOriginalDeps = this.originalDeps.buildOrThrow(); - for (Entry e : builtDeps.entrySet()) { + ImmutableMap initOriginalDeps = this.originalDeps.buildOrThrow(); + for (Entry e : builtDeps.entrySet()) { if (!initOriginalDeps.containsKey(e.getKey())) { originalDeps.put(e); } } - ImmutableMap builtOriginalDeps = this.originalDeps.buildOrThrow(); + ImmutableMap builtOriginalDeps = this.originalDeps.buildOrThrow(); return this.builder.setDeps(builtDeps).setOriginalDeps(builtOriginalDeps).build(); } diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/DiscoveryTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/DiscoveryTest.java index 94fa9f1dae216f..de1f2794c2c6e5 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/DiscoveryTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/DiscoveryTest.java @@ -29,7 +29,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ServerDirectories; import com.google.devtools.build.lib.analysis.util.AnalysisMock; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.ModuleBuilder; +import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.InterimModuleBuilder; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue; import com.google.devtools.build.lib.bazel.repository.starlark.StarlarkRepositoryModule; import com.google.devtools.build.lib.clock.BlazeClock; @@ -91,11 +91,11 @@ abstract static class DiscoveryValue implements SkyValue { static final SkyFunctionName FUNCTION_NAME = SkyFunctionName.createHermetic("test_discovery"); static final SkyKey KEY = () -> FUNCTION_NAME; - static DiscoveryValue create(ImmutableMap depGraph) { + static DiscoveryValue create(ImmutableMap depGraph) { return new AutoValue_DiscoveryTest_DiscoveryValue(depGraph); } - abstract ImmutableMap getDepGraph(); + abstract ImmutableMap getDepGraph(); } static class DiscoveryFunction implements SkyFunction { @@ -107,7 +107,7 @@ public SkyValue compute(SkyKey skyKey, Environment env) if (root == null) { return null; } - ImmutableMap depGraph = Discovery.run(env, root); + ImmutableMap depGraph = Discovery.run(env, root); return depGraph == null ? null : DiscoveryValue.create(depGraph); } } @@ -226,20 +226,20 @@ public void testSimpleDiamond() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "0.1") + InterimModuleBuilder.create("aaa", "0.1") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd", createModuleKey("ddd", "3.0")) .setRegistry(registry) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd", createModuleKey("ddd", "3.0")) .setRegistry(registry) .buildEntry(), - ModuleBuilder.create("ddd", "3.0").setRegistry(registry).buildEntry()); + InterimModuleBuilder.create("ddd", "3.0").setRegistry(registry).buildEntry()); } @Test @@ -268,13 +268,13 @@ public void testDevDependency() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "0.1") + InterimModuleBuilder.create("aaa", "0.1") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .addDep("ccc", createModuleKey("ccc", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0").setRegistry(registry).buildEntry(), - ModuleBuilder.create("ccc", "1.0").setRegistry(registry).buildEntry()); + InterimModuleBuilder.create("bbb", "1.0").setRegistry(registry).buildEntry(), + InterimModuleBuilder.create("ccc", "1.0").setRegistry(registry).buildEntry()); } @Test @@ -304,11 +304,11 @@ public void testIgnoreDevDependency() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "0.1") + InterimModuleBuilder.create("aaa", "0.1") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0").setRegistry(registry).buildEntry()); + InterimModuleBuilder.create("bbb", "1.0").setRegistry(registry).buildEntry()); } @Test @@ -336,15 +336,15 @@ public void testCircularDependency() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "0.1") + InterimModuleBuilder.create("aaa", "0.1") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .setRegistry(registry) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("bbb", createModuleKey("bbb", "1.0")) .setRegistry(registry) .buildEntry()); @@ -373,11 +373,11 @@ public void testCircularDependencyOnRootModule() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "0.1") + InterimModuleBuilder.create("aaa", "0.1") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("aaa", ModuleKey.ROOT) .addOriginalDep("aaa", createModuleKey("aaa", "2.0")) .setRegistry(registry) @@ -409,16 +409,16 @@ public void testSingleVersionOverride() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "0.1") + InterimModuleBuilder.create("aaa", "0.1") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "0.1")) .buildEntry(), - ModuleBuilder.create("bbb", "0.1") + InterimModuleBuilder.create("bbb", "0.1") .addDep("ccc", createModuleKey("ccc", "2.0")) .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) .setRegistry(registry) .buildEntry(), - ModuleBuilder.create("ccc", "2.0").setRegistry(registry).buildEntry()); + InterimModuleBuilder.create("ccc", "2.0").setRegistry(registry).buildEntry()); } @Test @@ -451,15 +451,15 @@ public void testRegistryOverride() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "0.1") + InterimModuleBuilder.create("aaa", "0.1") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "0.1")) .buildEntry(), - ModuleBuilder.create("bbb", "0.1") + InterimModuleBuilder.create("bbb", "0.1") .addDep("ccc", createModuleKey("ccc", "1.0")) .setRegistry(registry1) .buildEntry(), - ModuleBuilder.create("ccc", "1.0") + InterimModuleBuilder.create("ccc", "1.0") .addDep("bbb", createModuleKey("bbb", "0.1")) .setRegistry(registry2) .buildEntry()); @@ -493,16 +493,18 @@ public void testLocalPathOverride() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "0.1") + InterimModuleBuilder.create("aaa", "0.1") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "0.1")) .buildEntry(), - ModuleBuilder.create("bbb", "0.1") + InterimModuleBuilder.create("bbb", "0.1") .addDep("ccc", createModuleKey("ccc", "")) .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) .setRegistry(registry) .buildEntry(), - ModuleBuilder.create("ccc", "2.0").setKey(createModuleKey("ccc", "")).buildEntry()); + InterimModuleBuilder.create("ccc", "2.0") + .setKey(createModuleKey("ccc", "")) + .buildEntry()); } @Test @@ -541,26 +543,26 @@ public void testBuiltinModules_forRoot() throws Exception { DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY); assertThat(discoveryValue.getDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("", "") + InterimModuleBuilder.create("", "") .addDep("bazel_tools", createModuleKey("bazel_tools", "")) .addDep("local_config_platform", createModuleKey("local_config_platform", "")) .addDep("foo", createModuleKey("foo", "2.0")) .buildEntry(), - ModuleBuilder.create("bazel_tools", "1.0") + InterimModuleBuilder.create("bazel_tools", "1.0") .setKey(createModuleKey("bazel_tools", "")) .addDep("local_config_platform", createModuleKey("local_config_platform", "")) .addDep("foo", createModuleKey("foo", "1.0")) .buildEntry(), - ModuleBuilder.create("local_config_platform", "") + InterimModuleBuilder.create("local_config_platform", "") .setKey(createModuleKey("local_config_platform", "")) .addDep("bazel_tools", createModuleKey("bazel_tools", "")) .buildEntry(), - ModuleBuilder.create("foo", "1.0") + InterimModuleBuilder.create("foo", "1.0") .addDep("bazel_tools", createModuleKey("bazel_tools", "")) .addDep("local_config_platform", createModuleKey("local_config_platform", "")) .setRegistry(registry) .buildEntry(), - ModuleBuilder.create("foo", "2.0") + InterimModuleBuilder.create("foo", "2.0") .addDep("bazel_tools", createModuleKey("bazel_tools", "")) .addDep("local_config_platform", createModuleKey("local_config_platform", "")) .setRegistry(registry) diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModuleTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModuleTest.java new file mode 100644 index 00000000000000..dd65628c9bac18 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/InterimModuleTest.java @@ -0,0 +1,51 @@ +// Copyright 2023 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 static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; + +import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.InterimModuleBuilder; +import com.google.devtools.build.lib.bazel.bzlmod.InterimModule.DepSpec; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link InterimModule}. */ +@RunWith(JUnit4.class) +public class InterimModuleTest { + + @Test + public void withDepSpecsTransformed() throws Exception { + assertThat( + InterimModuleBuilder.create("", "") + .addDep("dep_foo", createModuleKey("foo", "1.0")) + .addDep("dep_bar", createModuleKey("bar", "2.0")) + .build() + .withDepSpecsTransformed( + depSpec -> + DepSpec.fromModuleKey( + createModuleKey( + depSpec.getName() + "_new", + depSpec.getVersion().getOriginal() + ".1")))) + .isEqualTo( + InterimModuleBuilder.create("", "") + .addDep("dep_foo", createModuleKey("foo_new", "1.0.1")) + .addOriginalDep("dep_foo", createModuleKey("foo", "1.0")) + .addDep("dep_bar", createModuleKey("bar_new", "2.0.1")) + .addOriginalDep("dep_bar", createModuleKey("bar", "2.0")) + .build()); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java index d55e990a487364..d654cd8427b83a 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java @@ -30,7 +30,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ServerDirectories; import com.google.devtools.build.lib.analysis.util.AnalysisMock; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.ModuleBuilder; +import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.InterimModuleBuilder; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue; import com.google.devtools.build.lib.bazel.repository.starlark.StarlarkRepositoryModule; import com.google.devtools.build.lib.clock.BlazeClock; @@ -202,7 +202,7 @@ public void testRootModule() throws Exception { RootModuleFileValue rootModuleFileValue = result.get(ModuleFileValue.KEY_FOR_ROOT_MODULE); assertThat(rootModuleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("aaa", "0.1", 4) + InterimModuleBuilder.create("aaa", "0.1", 4) .setKey(ModuleKey.ROOT) .addExecutionPlatformsToRegister( ImmutableList.of("//my:platform", "//my:platform2")) @@ -250,7 +250,7 @@ public void testRootModule_noModuleFunctionIsOkay() throws Exception { RootModuleFileValue rootModuleFileValue = result.get(ModuleFileValue.KEY_FOR_ROOT_MODULE); assertThat(rootModuleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("", "") + InterimModuleBuilder.create("", "") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .build()); @@ -303,7 +303,7 @@ public void testRegistriesCascade() throws Exception { ModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .setRegistry(registry2) .build()); @@ -341,7 +341,7 @@ public void testLocalPathOverride() throws Exception { ModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .setKey(createModuleKey("bbb", "")) .addDep("ccc", createModuleKey("ccc", "2.0")) .build()); @@ -392,7 +392,7 @@ public void testCommandLineModuleOverrides() throws Exception { ModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .setKey(createModuleKey("bbb", "")) .addDep("ccc", createModuleKey("ccc", "2.0")) .build()); @@ -430,7 +430,7 @@ public void testRegistryOverride() throws Exception { ModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("bbb", "1.0", 6) + InterimModuleBuilder.create("bbb", "1.0", 6) .addDep("ccc", createModuleKey("ccc", "3.0")) .setRegistry(registry2) .build()); @@ -469,7 +469,7 @@ public void testModuleExtensions_good() throws Exception { ModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("mymod", "1.0") + InterimModuleBuilder.create("mymod", "1.0") .addDep("rules_jvm_external", createModuleKey("rules_jvm_external", "2.0")) .setRegistry(registry) .addExtensionUsage( @@ -590,7 +590,7 @@ public void testModuleExtensions_duplicateProxy_asRoot() throws Exception { ModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("", "") + InterimModuleBuilder.create("", "") .setKey(ModuleKey.ROOT) .addExtensionUsage( ModuleExtensionUsage.builder() @@ -687,7 +687,7 @@ public void testModuleExtensions_duplicateProxy_asDep() throws Exception { ModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("mymod", "1.0") + InterimModuleBuilder.create("mymod", "1.0") .setRegistry(registry) .addExtensionUsage( ModuleExtensionUsage.builder() @@ -901,7 +901,7 @@ public void testBuiltinModules_forRoot() throws Exception { RootModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("", "") + InterimModuleBuilder.create("", "") .addDep("bazel_tools", createModuleKey("bazel_tools", "")) .addDep("local_config_platform", createModuleKey("local_config_platform", "")) .addDep("foo", createModuleKey("foo", "1.0")) @@ -938,7 +938,7 @@ public void testBuiltinModules_forBuiltinModules() throws Exception { ModuleFileValue moduleFileValue = result.get(skyKey); assertThat(moduleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("bazel_tools", "1.0") + InterimModuleBuilder.create("bazel_tools", "1.0") .setKey(createModuleKey("bazel_tools", "")) .addDep("local_config_platform", createModuleKey("local_config_platform", "")) .addDep("foo", createModuleKey("foo", "2.0")) @@ -962,7 +962,10 @@ public void moduleRepoName() throws Exception { RootModuleFileValue rootModuleFileValue = result.get(ModuleFileValue.KEY_FOR_ROOT_MODULE); assertThat(rootModuleFileValue.getModule()) .isEqualTo( - ModuleBuilder.create("aaa", "0.1").setKey(ModuleKey.ROOT).setRepoName("bbb").build()); + InterimModuleBuilder.create("aaa", "0.1") + .setKey(ModuleKey.ROOT) + .setRepoName("bbb") + .build()); } @Test diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java index 2428755a9ab1b1..d0a5b62ce9bb05 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java @@ -15,10 +15,10 @@ package com.google.devtools.build.lib.bazel.bzlmod; import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.buildModule; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createRepositoryMapping; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.ModuleBuilder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -27,31 +27,11 @@ @RunWith(JUnit4.class) public class ModuleTest { - @Test - public void withDepKeysTransformed() throws Exception { - assertThat( - ModuleBuilder.create("", "") - .addDep("dep_foo", createModuleKey("foo", "1.0")) - .addDep("dep_bar", createModuleKey("bar", "2.0")) - .build() - .withDepKeysTransformed( - key -> - createModuleKey( - key.getName() + "_new", key.getVersion().getOriginal() + ".1"))) - .isEqualTo( - ModuleBuilder.create("", "") - .addDep("dep_foo", createModuleKey("foo_new", "1.0.1")) - .addOriginalDep("dep_foo", createModuleKey("foo", "1.0")) - .addDep("dep_bar", createModuleKey("bar_new", "2.0.1")) - .addOriginalDep("dep_bar", createModuleKey("bar", "2.0")) - .build()); - } - @Test public void getRepoMapping() throws Exception { ModuleKey key = createModuleKey("test_module", "1.0"); Module module = - ModuleBuilder.create(key.getName(), key.getVersion()) + buildModule("test_module", "1.0") .addDep("my_foo", createModuleKey("foo", "1.0")) .addDep("my_bar", createModuleKey("bar", "2.0")) .addDep("my_root", ModuleKey.ROOT) @@ -73,7 +53,7 @@ public void getRepoMapping() throws Exception { @Test public void getRepoMapping_asMainModule() throws Exception { Module module = - ModuleBuilder.create("test_module", "1.0") + buildModule("test_module", "1.0") .setKey(ModuleKey.ROOT) .addDep("my_foo", createModuleKey("foo", "1.0")) .addDep("my_bar", createModuleKey("bar", "2.0")) diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/SelectionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/SelectionTest.java index 2aed3463828d41..5cc7c3b0b46db5 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/SelectionTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/SelectionTest.java @@ -16,12 +16,13 @@ package com.google.devtools.build.lib.bazel.bzlmod; import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createDepSpec; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.ModuleBuilder; +import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.InterimModuleBuilder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -32,167 +33,282 @@ public class SelectionTest { @Test public void diamond_simple() throws Exception { - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ddd", "2.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) .buildOrThrow(); - BazelModuleResolutionValue selectionResult = - Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry(), - ModuleBuilder.create("ddd", "2.0", 1).buildEntry()) + InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) .inOrder(); assertThat(selectionResult.getUnprunedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry(), - ModuleBuilder.create("ddd", "1.0", 1).buildEntry(), - ModuleBuilder.create("ddd", "2.0", 1).buildEntry()); + InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()); + } + + @Test + public void diamond_withIgnoredNonAffectingMaxCompatibilityLevel() throws Exception { + ImmutableMap depGraph = + ImmutableMap.builder() + .put( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 3)) + .buildEntry()) + .put( + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) + .buildOrThrow(); + + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + assertThat(selectionResult.getResolvedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 3)) + .buildEntry(), + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) + .inOrder(); + + assertThat(selectionResult.getUnprunedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 3)) + .buildEntry(), + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()); + } + + @Test + public void diamond_withSelectedNonAffectingMaxCompatibilityLevel() throws Exception { + ImmutableMap depGraph = + ImmutableMap.builder() + .put( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createDepSpec("ddd", "2.0", 4)) + .buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) + .buildOrThrow(); + + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + assertThat(selectionResult.getResolvedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) + .buildEntry(), + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_ccc", createDepSpec("ddd", "2.0", 4)) + .buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) + .inOrder(); + + assertThat(selectionResult.getUnprunedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) + .buildEntry(), + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_ccc", createDepSpec("ddd", "2.0", 4)) + .buildEntry(), + InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()); } @Test public void diamond_withFurtherRemoval() throws Exception { - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd", createModuleKey("ddd", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd", createModuleKey("ddd", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("ddd", "1.0") + InterimModuleBuilder.create("ddd", "1.0") .addDep("eee", createModuleKey("eee", "1.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "2.0").buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0").buildEntry()) // Only D@1.0 needs E. When D@1.0 is removed, E should be gone as well (even though // E@1.0 is selected for E). - .put(ModuleBuilder.create("eee", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("eee", "1.0").buildEntry()) .build(); - BazelModuleResolutionValue selectionResult = - Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd", createModuleKey("ddd", "2.0")) .addOriginalDep("ddd", createModuleKey("ddd", "1.0")) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd", createModuleKey("ddd", "2.0")) .buildEntry(), - ModuleBuilder.create("ddd", "2.0").buildEntry()) + InterimModuleBuilder.create("ddd", "2.0").buildEntry()) .inOrder(); assertThat(selectionResult.getUnprunedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd", createModuleKey("ddd", "2.0")) .addOriginalDep("ddd", createModuleKey("ddd", "1.0")) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd", createModuleKey("ddd", "2.0")) .buildEntry(), - ModuleBuilder.create("ddd", "2.0").buildEntry(), - ModuleBuilder.create("ddd", "1.0") + InterimModuleBuilder.create("ddd", "2.0").buildEntry(), + InterimModuleBuilder.create("ddd", "1.0") .addDep("eee", createModuleKey("eee", "1.0")) .buildEntry(), - ModuleBuilder.create("eee", "1.0").buildEntry()); + InterimModuleBuilder.create("eee", "1.0").buildEntry()); } @Test public void circularDependencyDueToSelection() throws Exception { - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("bbb", createModuleKey("bbb", "1.0-pre")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0-pre") + InterimModuleBuilder.create("bbb", "1.0-pre") .addDep("ddd", createModuleKey("ddd", "1.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0").buildEntry()) .buildOrThrow(); - BazelModuleResolutionValue selectionResult = - Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("bbb", createModuleKey("bbb", "1.0")) .addOriginalDep("bbb", createModuleKey("bbb", "1.0-pre")) .buildEntry()) @@ -201,65 +317,331 @@ public void circularDependencyDueToSelection() throws Exception { assertThat(selectionResult.getUnprunedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("bbb", createModuleKey("bbb", "1.0")) .addOriginalDep("bbb", createModuleKey("bbb", "1.0-pre")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0-pre") + InterimModuleBuilder.create("bbb", "1.0-pre") .addDep("ddd", createModuleKey("ddd", "1.0")) .buildEntry(), - ModuleBuilder.create("ddd", "1.0").buildEntry()); + InterimModuleBuilder.create("ddd", "1.0").buildEntry()); } @Test public void differentCompatibilityLevelIsRejected() throws Exception { - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ddd", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) + .buildOrThrow(); + + ExternalDepsException e = + assertThrows( + ExternalDepsException.class, + () -> Selection.run(depGraph, /* overrides= */ ImmutableMap.of())); + String error = e.getMessage(); + assertThat(error).contains("bbb@1.0 depends on ddd@1.0 with compatibility level 1"); + assertThat(error).contains("ccc@2.0 depends on ddd@2.0 with compatibility level 2"); + assertThat(error).contains("which is different"); + } + + @Test + public void differentCompatibilityLevelWithMaxCompatibilityLevelIsRejected() throws Exception { + ImmutableMap depGraph = + ImmutableMap.builder() + .put( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createDepSpec("ddd", "2.0", 3)) + .buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) .buildOrThrow(); ExternalDepsException e = assertThrows( ExternalDepsException.class, - () -> Selection.run(depGraph, /*overrides=*/ ImmutableMap.of())); + () -> Selection.run(depGraph, /* overrides= */ ImmutableMap.of())); String error = e.getMessage(); assertThat(error).contains("bbb@1.0 depends on ddd@1.0 with compatibility level 1"); assertThat(error).contains("ccc@2.0 depends on ddd@2.0 with compatibility level 2"); assertThat(error).contains("which is different"); } + @Test + public void maxCompatibilityBasedSelection() throws Exception { + ImmutableMap depGraph = + ImmutableMap.builder() + .put( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 2)) + .buildEntry()) + .put( + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) + .buildOrThrow(); + + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + assertThat(selectionResult.getResolvedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 2)) + .buildEntry(), + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) + .inOrder(); + + assertThat(selectionResult.getUnprunedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 2)) + .buildEntry(), + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()); + } + + @Test + public void maxCompatibilityBasedSelection_sameVersion() throws Exception { + ImmutableMap depGraph = + ImmutableMap.builder() + .put( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createDepSpec("ddd", "2.0", 3)) + .buildEntry()) + .put( + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) + .buildOrThrow(); + + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + assertThat(selectionResult.getResolvedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "2.0", 3)) + .buildEntry(), + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) + .inOrder(); + + assertThat(selectionResult.getUnprunedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) + .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "2.0", 3)) + .buildEntry(), + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()); + } + + @Test + public void maxCompatibilityBasedSelection_limitedToMax() throws Exception { + ImmutableMap depGraph = + ImmutableMap.builder() + .put( + InterimModuleBuilder.create("aaa", Version.EMPTY) + .setKey(ModuleKey.ROOT) + .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) + .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 2)) + .buildEntry()) + .put( + InterimModuleBuilder.create("ccc", "2.0") + .addDep("ddd_from_ccc", createModuleKey("ddd", "3.0")) + .buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "3.0", 3).buildEntry()) + .buildOrThrow(); + + ExternalDepsException e = + assertThrows( + ExternalDepsException.class, + () -> Selection.run(depGraph, /* overrides= */ ImmutableMap.of())); + String error = e.getMessage(); + assertThat(error).contains("bbb@1.0 depends on ddd@1.0 with compatibility level 1"); + assertThat(error).contains("ccc@2.0 depends on ddd@3.0 with compatibility level 3"); + assertThat(error).contains("which is different"); + } + + @Test + public void maxCompatibilityBasedSelection_unreferencedNotSelected() throws Exception { + // aaa 1.0 -> bbb 1.0 -> ccc 2.0 + // \-> ccc 1.0 (max_compatibility_level=2) + // \-> ddd 1.0 -> bbb 1.1 + // \-> eee 1.0 -> ccc 1.1 + ImmutableMap depGraph = + ImmutableMap.builder() + .put( + InterimModuleBuilder.create("aaa", "1.0") + .setKey(ModuleKey.ROOT) + .addDep("bbb", createModuleKey("bbb", "1.0")) + .addDep("ccc", createDepSpec("ccc", "1.0", 2)) + .addDep("ddd", createModuleKey("ddd", "1.0")) + .addDep("eee", createModuleKey("eee", "1.0")) + .buildEntry()) + .put( + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ccc", createModuleKey("ccc", "2.0")) + .buildEntry()) + .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) + .put( + InterimModuleBuilder.create("ddd", "1.0") + .addDep("bbb", createModuleKey("bbb", "1.1")) + .buildEntry()) + .put(InterimModuleBuilder.create("bbb", "1.1").buildEntry()) + .put( + InterimModuleBuilder.create("eee", "1.0") + .addDep("ccc", createModuleKey("ccc", "1.1")) + .buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry()) + .buildOrThrow(); + + // After selection, ccc 2.0 is gone, so ccc 1.0 (max_compatibility_level=2) doesn't upgrade to + // ccc 2.0, and only upgrades to ccc 1.1 + // aaa 1.0 -> bbb 1.1 + // \-> ccc 1.1 + // \-> ddd 1.0 -> bbb 1.1 + // \-> eee 1.0 -> ccc 1.1 + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + assertThat(selectionResult.getResolvedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", "1.0") + .setKey(ModuleKey.ROOT) + .addDep("bbb", createModuleKey("bbb", "1.1")) + .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) + .addDep("ccc", createModuleKey("ccc", "1.1")) + .addOriginalDep("ccc", createDepSpec("ccc", "1.0", 2)) + .addDep("ddd", createModuleKey("ddd", "1.0")) + .addDep("eee", createModuleKey("eee", "1.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.1").buildEntry(), + InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry(), + InterimModuleBuilder.create("ddd", "1.0") + .addDep("bbb", createModuleKey("bbb", "1.1")) + .buildEntry(), + InterimModuleBuilder.create("eee", "1.0") + .addDep("ccc", createModuleKey("ccc", "1.1")) + .buildEntry()) + .inOrder(); + + assertThat(selectionResult.getUnprunedDepGraph().entrySet()) + .containsExactly( + InterimModuleBuilder.create("aaa", "1.0") + .setKey(ModuleKey.ROOT) + .addDep("bbb", createModuleKey("bbb", "1.1")) + .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) + .addDep("ccc", createModuleKey("ccc", "1.1")) + .addOriginalDep("ccc", createDepSpec("ccc", "1.0", 2)) + .addDep("ddd", createModuleKey("ddd", "1.0")) + .addDep("eee", createModuleKey("eee", "1.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.0") + .addDep("ccc", createModuleKey("ccc", "2.0")) + .buildEntry(), + InterimModuleBuilder.create("bbb", "1.1").buildEntry(), + InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry(), + InterimModuleBuilder.create("ddd", "1.0") + .addDep("bbb", createModuleKey("bbb", "1.1")) + .buildEntry(), + InterimModuleBuilder.create("eee", "1.0") + .addDep("ccc", createModuleKey("ccc", "1.1")) + .buildEntry()); + } + @Test public void differentCompatibilityLevelIsOkIfUnreferenced() throws Exception { // aaa 1.0 -> bbb 1.0 -> ccc 2.0 // \-> ccc 1.0 // \-> ddd 1.0 -> bbb 1.1 // \-> eee 1.0 -> ccc 1.1 - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", "1.0") + InterimModuleBuilder.create("aaa", "1.0") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.0")) .addDep("ccc", createModuleKey("ccc", "1.0")) @@ -267,21 +649,21 @@ public void differentCompatibilityLevelIsOkIfUnreferenced() throws Exception { .addDep("eee", createModuleKey("eee", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ccc", "2.0", 2).buildEntry()) - .put(ModuleBuilder.create("ccc", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) .put( - ModuleBuilder.create("ddd", "1.0") + InterimModuleBuilder.create("ddd", "1.0") .addDep("bbb", createModuleKey("bbb", "1.1")) .buildEntry()) - .put(ModuleBuilder.create("bbb", "1.1").buildEntry()) + .put(InterimModuleBuilder.create("bbb", "1.1").buildEntry()) .put( - ModuleBuilder.create("eee", "1.0") + InterimModuleBuilder.create("eee", "1.0") .addDep("ccc", createModuleKey("ccc", "1.1")) .buildEntry()) - .put(ModuleBuilder.create("ccc", "1.1", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry()) .buildOrThrow(); // After selection, ccc 2.0 is gone, so we're okay. @@ -289,11 +671,10 @@ public void differentCompatibilityLevelIsOkIfUnreferenced() throws Exception { // \-> ccc 1.1 // \-> ddd 1.0 -> bbb 1.1 // \-> eee 1.0 -> ccc 1.1 - BazelModuleResolutionValue selectionResult = - Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); + Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "1.0") + InterimModuleBuilder.create("aaa", "1.0") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.1")) .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) @@ -302,19 +683,19 @@ public void differentCompatibilityLevelIsOkIfUnreferenced() throws Exception { .addDep("ddd", createModuleKey("ddd", "1.0")) .addDep("eee", createModuleKey("eee", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.1").buildEntry(), - ModuleBuilder.create("ccc", "1.1", 1).buildEntry(), - ModuleBuilder.create("ddd", "1.0") + InterimModuleBuilder.create("bbb", "1.1").buildEntry(), + InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry(), + InterimModuleBuilder.create("ddd", "1.0") .addDep("bbb", createModuleKey("bbb", "1.1")) .buildEntry(), - ModuleBuilder.create("eee", "1.0") + InterimModuleBuilder.create("eee", "1.0") .addDep("ccc", createModuleKey("ccc", "1.1")) .buildEntry()) .inOrder(); assertThat(selectionResult.getUnprunedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", "1.0") + InterimModuleBuilder.create("aaa", "1.0") .setKey(ModuleKey.ROOT) .addDep("bbb", createModuleKey("bbb", "1.1")) .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) @@ -323,33 +704,33 @@ public void differentCompatibilityLevelIsOkIfUnreferenced() throws Exception { .addDep("ddd", createModuleKey("ddd", "1.0")) .addDep("eee", createModuleKey("eee", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.1").buildEntry(), - ModuleBuilder.create("ccc", "1.0", 1).buildEntry(), - ModuleBuilder.create("ccc", "1.1", 1).buildEntry(), - ModuleBuilder.create("ccc", "2.0", 2).buildEntry(), - ModuleBuilder.create("ddd", "1.0") + InterimModuleBuilder.create("bbb", "1.1").buildEntry(), + InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry(), + InterimModuleBuilder.create("ddd", "1.0") .addDep("bbb", createModuleKey("bbb", "1.1")) .buildEntry(), - ModuleBuilder.create("eee", "1.0") + InterimModuleBuilder.create("eee", "1.0") .addDep("ccc", createModuleKey("ccc", "1.1")) .buildEntry()); } @Test public void multipleVersionOverride_fork_allowedVersionMissingInDepGraph() throws Exception { - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb", "1.0")) .addDep("bbb2", createModuleKey("bbb", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("bbb", "1.0").buildEntry()) - .put(ModuleBuilder.create("bbb", "2.0").buildEntry()) + .put(InterimModuleBuilder.create("bbb", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("bbb", "2.0").buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -370,16 +751,16 @@ public void multipleVersionOverride_fork_allowedVersionMissingInDepGraph() throw @Test public void multipleVersionOverride_fork_goodCase() throws Exception { // For more complex good cases, see the "diamond" test cases below. - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb", "1.0")) .addDep("bbb2", createModuleKey("bbb", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("bbb", "1.0").buildEntry()) - .put(ModuleBuilder.create("bbb", "2.0").buildEntry()) + .put(InterimModuleBuilder.create("bbb", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("bbb", "2.0").buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -387,16 +768,16 @@ public void multipleVersionOverride_fork_goodCase() throws Exception { MultipleVersionOverride.create( ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); - BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); + Selection.Result selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb", "1.0")) .addDep("bbb2", createModuleKey("bbb", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0").buildEntry(), - ModuleBuilder.create("bbb", "2.0").buildEntry()) + InterimModuleBuilder.create("bbb", "1.0").buildEntry(), + InterimModuleBuilder.create("bbb", "2.0").buildEntry()) .inOrder(); assertThat(selectionResult.getUnprunedDepGraph()) @@ -405,18 +786,18 @@ public void multipleVersionOverride_fork_goodCase() throws Exception { @Test public void multipleVersionOverride_fork_sameVersionUsedTwice() throws Exception { - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb", "1.0")) .addDep("bbb2", createModuleKey("bbb", "1.3")) .addDep("bbb3", createModuleKey("bbb", "1.5")) .buildEntry()) - .put(ModuleBuilder.create("bbb", "1.0").buildEntry()) - .put(ModuleBuilder.create("bbb", "1.3").buildEntry()) - .put(ModuleBuilder.create("bbb", "1.5").buildEntry()) + .put(InterimModuleBuilder.create("bbb", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("bbb", "1.3").buildEntry()) + .put(InterimModuleBuilder.create("bbb", "1.5").buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -435,24 +816,24 @@ public void multipleVersionOverride_fork_sameVersionUsedTwice() throws Exception @Test public void multipleVersionOverride_diamond_differentCompatibilityLevels() throws Exception { - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ddd", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -460,22 +841,22 @@ public void multipleVersionOverride_diamond_differentCompatibilityLevels() throw MultipleVersionOverride.create( ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); - BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); + Selection.Result selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry(), - ModuleBuilder.create("ddd", "1.0", 1).buildEntry(), - ModuleBuilder.create("ddd", "2.0", 2).buildEntry()) + InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) .inOrder(); assertThat(selectionResult.getUnprunedDepGraph()) @@ -484,24 +865,24 @@ public void multipleVersionOverride_diamond_differentCompatibilityLevels() throw @Test public void multipleVersionOverride_diamond_sameCompatibilityLevel() throws Exception { - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ddd", "1.0").buildEntry()) - .put(ModuleBuilder.create("ddd", "2.0").buildEntry()) + .put(InterimModuleBuilder.create("ddd", "1.0").buildEntry()) + .put(InterimModuleBuilder.create("ddd", "2.0").buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -509,22 +890,22 @@ public void multipleVersionOverride_diamond_sameCompatibilityLevel() throws Exce MultipleVersionOverride.create( ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); - BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); + Selection.Result selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("bbb", "1.0") + InterimModuleBuilder.create("bbb", "1.0") .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) .buildEntry(), - ModuleBuilder.create("ccc", "2.0") + InterimModuleBuilder.create("ccc", "2.0") .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) .buildEntry(), - ModuleBuilder.create("ddd", "1.0").buildEntry(), - ModuleBuilder.create("ddd", "2.0").buildEntry()) + InterimModuleBuilder.create("ddd", "1.0").buildEntry(), + InterimModuleBuilder.create("ddd", "2.0").buildEntry()) .inOrder(); assertThat(selectionResult.getUnprunedDepGraph()) @@ -538,10 +919,10 @@ public void multipleVersionOverride_diamond_snappingToNextHighestVersion() throw // \-> bbb3@1.0 -> ccc@1.5 // \-> bbb4@1.0 -> ccc@1.7 [allowed] // \-> bbb5@1.0 -> ccc@2.0 [allowed] - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.0")) @@ -550,30 +931,30 @@ public void multipleVersionOverride_diamond_snappingToNextHighestVersion() throw .addDep("bbb5", createModuleKey("bbb5", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb2", "1.0") + InterimModuleBuilder.create("bbb2", "1.0") .addDep("ccc", createModuleKey("ccc", "1.3")) .buildEntry()) .put( - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "1.5")) .buildEntry()) .put( - ModuleBuilder.create("bbb4", "1.0") + InterimModuleBuilder.create("bbb4", "1.0") .addDep("ccc", createModuleKey("ccc", "1.7")) .buildEntry()) .put( - ModuleBuilder.create("bbb5", "1.0") + InterimModuleBuilder.create("bbb5", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ccc", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "1.3", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "1.5", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "1.7", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.3", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.7", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -587,10 +968,10 @@ public void multipleVersionOverride_diamond_snappingToNextHighestVersion() throw // \-> bbb3@1.0 -> ccc@1.7 [originally ccc@1.5] // \-> bbb4@1.0 -> ccc@1.7 [allowed] // \-> bbb5@1.0 -> ccc@2.0 [allowed] - BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); + Selection.Result selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.0")) @@ -598,31 +979,31 @@ public void multipleVersionOverride_diamond_snappingToNextHighestVersion() throw .addDep("bbb4", createModuleKey("bbb4", "1.0")) .addDep("bbb5", createModuleKey("bbb5", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.3")) .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb2", "1.0") + InterimModuleBuilder.create("bbb2", "1.0") .addDep("ccc", createModuleKey("ccc", "1.3")) .buildEntry(), - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "1.7")) .addOriginalDep("ccc", createModuleKey("ccc", "1.5")) .buildEntry(), - ModuleBuilder.create("bbb4", "1.0") + InterimModuleBuilder.create("bbb4", "1.0") .addDep("ccc", createModuleKey("ccc", "1.7")) .buildEntry(), - ModuleBuilder.create("bbb5", "1.0") + InterimModuleBuilder.create("bbb5", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("ccc", "1.3", 1).buildEntry(), - ModuleBuilder.create("ccc", "1.7", 1).buildEntry(), - ModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + InterimModuleBuilder.create("ccc", "1.3", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "1.7", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) .inOrder(); assertThat(selectionResult.getUnprunedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.0")) @@ -630,28 +1011,28 @@ public void multipleVersionOverride_diamond_snappingToNextHighestVersion() throw .addDep("bbb4", createModuleKey("bbb4", "1.0")) .addDep("bbb5", createModuleKey("bbb5", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.3")) .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb2", "1.0") + InterimModuleBuilder.create("bbb2", "1.0") .addDep("ccc", createModuleKey("ccc", "1.3")) .buildEntry(), - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "1.7")) .addOriginalDep("ccc", createModuleKey("ccc", "1.5")) .buildEntry(), - ModuleBuilder.create("bbb4", "1.0") + InterimModuleBuilder.create("bbb4", "1.0") .addDep("ccc", createModuleKey("ccc", "1.7")) .buildEntry(), - ModuleBuilder.create("bbb5", "1.0") + InterimModuleBuilder.create("bbb5", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry(), - ModuleBuilder.create("ccc", "1.0", 1).buildEntry(), - ModuleBuilder.create("ccc", "1.3", 1).buildEntry(), - ModuleBuilder.create("ccc", "1.5", 1).buildEntry(), - ModuleBuilder.create("ccc", "1.7", 1).buildEntry(), - ModuleBuilder.create("ccc", "2.0", 2).buildEntry()); + InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "1.3", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "1.7", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()); } @Test @@ -659,30 +1040,30 @@ public void multipleVersionOverride_diamond_dontSnapToDifferentCompatibility() t // aaa --> bbb1@1.0 -> ccc@1.0 [allowed] // \-> bbb2@1.0 -> ccc@1.7 // \-> bbb3@1.0 -> ccc@2.0 [allowed] - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.0")) .addDep("bbb3", createModuleKey("bbb3", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb2", "1.0") + InterimModuleBuilder.create("bbb2", "1.0") .addDep("ccc", createModuleKey("ccc", "1.7")) .buildEntry()) .put( - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) - .put(ModuleBuilder.create("ccc", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "1.7", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.7", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -704,30 +1085,30 @@ public void multipleVersionOverride_diamond_unknownCompatibility() throws Except // aaa --> bbb1@1.0 -> ccc@1.0 [allowed] // \-> bbb2@1.0 -> ccc@2.0 [allowed] // \-> bbb3@1.0 -> ccc@3.0 - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.0")) .addDep("bbb3", createModuleKey("bbb3", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb2", "1.0") + InterimModuleBuilder.create("bbb2", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "3.0")) .buildEntry()) - .put(ModuleBuilder.create("ccc", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "2.0", 2).buildEntry()) - .put(ModuleBuilder.create("ccc", "3.0", 3).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "3.0", 3).buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -752,10 +1133,10 @@ public void multipleVersionOverride_diamond_badVersionsAreOkayIfUnreferenced() t // \-> bbb3@1.0 --> ccc@2.0 [allowed] // \ \-> bbb4@1.1 // \-> bbb4@1.0 --> ccc@3.0 - ImmutableMap depGraph = - ImmutableMap.builder() + ImmutableMap depGraph = + ImmutableMap.builder() .put( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.0")) @@ -763,29 +1144,29 @@ public void multipleVersionOverride_diamond_badVersionsAreOkayIfUnreferenced() t .addDep("bbb4", createModuleKey("bbb4", "1.0")) .buildEntry()) .put( - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.1")) .buildEntry()) .put( - ModuleBuilder.create("bbb2", "1.0") + InterimModuleBuilder.create("bbb2", "1.0") .addDep("ccc", createModuleKey("ccc", "1.5")) .buildEntry()) - .put(ModuleBuilder.create("bbb2", "1.1").buildEntry()) + .put(InterimModuleBuilder.create("bbb2", "1.1").buildEntry()) .put( - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .addDep("bbb4", createModuleKey("bbb4", "1.1")) .buildEntry()) .put( - ModuleBuilder.create("bbb4", "1.0") + InterimModuleBuilder.create("bbb4", "1.0") .addDep("ccc", createModuleKey("ccc", "3.0")) .buildEntry()) - .put(ModuleBuilder.create("bbb4", "1.1").buildEntry()) - .put(ModuleBuilder.create("ccc", "1.0", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "1.5", 1).buildEntry()) - .put(ModuleBuilder.create("ccc", "2.0", 2).buildEntry()) - .put(ModuleBuilder.create("ccc", "3.0", 3).buildEntry()) + .put(InterimModuleBuilder.create("bbb4", "1.1").buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + .put(InterimModuleBuilder.create("ccc", "3.0", 3).buildEntry()) .buildOrThrow(); ImmutableMap overrides = ImmutableMap.of( @@ -800,10 +1181,10 @@ public void multipleVersionOverride_diamond_badVersionsAreOkayIfUnreferenced() t // \ \-> bbb4@1.1 // \-> bbb4@1.1 // ccc@1.5 and ccc@3.0, the versions violating the allowlist, are gone. - BazelModuleResolutionValue selectionResult = Selection.run(depGraph, overrides); + Selection.Result selectionResult = Selection.run(depGraph, overrides); assertThat(selectionResult.getResolvedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.1")) @@ -812,23 +1193,23 @@ public void multipleVersionOverride_diamond_badVersionsAreOkayIfUnreferenced() t .addDep("bbb4", createModuleKey("bbb4", "1.1")) .addOriginalDep("bbb4", createModuleKey("bbb4", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.1")) .buildEntry(), - ModuleBuilder.create("bbb2", "1.1").buildEntry(), - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb2", "1.1").buildEntry(), + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .addDep("bbb4", createModuleKey("bbb4", "1.1")) .buildEntry(), - ModuleBuilder.create("bbb4", "1.1").buildEntry(), - ModuleBuilder.create("ccc", "1.0", 1).buildEntry(), - ModuleBuilder.create("ccc", "2.0", 2).buildEntry()) + InterimModuleBuilder.create("bbb4", "1.1").buildEntry(), + InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) .inOrder(); assertThat(selectionResult.getUnprunedDepGraph().entrySet()) .containsExactly( - ModuleBuilder.create("aaa", Version.EMPTY) + InterimModuleBuilder.create("aaa", Version.EMPTY) .setKey(ModuleKey.ROOT) .addDep("bbb1", createModuleKey("bbb1", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.1")) @@ -837,25 +1218,25 @@ public void multipleVersionOverride_diamond_badVersionsAreOkayIfUnreferenced() t .addDep("bbb4", createModuleKey("bbb4", "1.1")) .addOriginalDep("bbb4", createModuleKey("bbb4", "1.0")) .buildEntry(), - ModuleBuilder.create("bbb1", "1.0") + InterimModuleBuilder.create("bbb1", "1.0") .addDep("ccc", createModuleKey("ccc", "1.0")) .addDep("bbb2", createModuleKey("bbb2", "1.1")) .buildEntry(), - ModuleBuilder.create("bbb2", "1.0") + InterimModuleBuilder.create("bbb2", "1.0") .addDep("ccc", createModuleKey("ccc", "1.5")) .buildEntry(), - ModuleBuilder.create("bbb2", "1.1").buildEntry(), - ModuleBuilder.create("bbb3", "1.0") + InterimModuleBuilder.create("bbb2", "1.1").buildEntry(), + InterimModuleBuilder.create("bbb3", "1.0") .addDep("ccc", createModuleKey("ccc", "2.0")) .addDep("bbb4", createModuleKey("bbb4", "1.1")) .buildEntry(), - ModuleBuilder.create("bbb4", "1.0") + InterimModuleBuilder.create("bbb4", "1.0") .addDep("ccc", createModuleKey("ccc", "3.0")) .buildEntry(), - ModuleBuilder.create("bbb4", "1.1").buildEntry(), - ModuleBuilder.create("ccc", "1.0", 1).buildEntry(), - ModuleBuilder.create("ccc", "1.5", 1).buildEntry(), - ModuleBuilder.create("ccc", "2.0", 2).buildEntry(), - ModuleBuilder.create("ccc", "3.0", 3).buildEntry()); + InterimModuleBuilder.create("bbb4", "1.1").buildEntry(), + InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry(), + InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry(), + InterimModuleBuilder.create("ccc", "3.0", 3).buildEntry()); } } diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java index 3f655551f24383..9dbb6904cba911 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java @@ -16,6 +16,7 @@ package com.google.devtools.build.lib.bazel.bzlmod; import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.buildModule; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.buildTag; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createTagClass; @@ -84,9 +85,7 @@ public void basic() throws Exception { .build()))) .build(); Module module = - Module.builder() - .setName("foo") - .setVersion(Version.parse("1.0")) + buildModule("foo", "1.0") .setKey(createModuleKey("foo", "")) .addDep("bar", createModuleKey("bar", "2.0")) .build(); @@ -128,12 +127,7 @@ public void unknownTagClass() throws Exception { ModuleExtensionUsage usage = getBaseUsageBuilder().addTag(buildTag("blep").build()).build(); ModuleExtension extension = getBaseExtensionBuilder().setTagClasses(ImmutableMap.of("dep", createTagClass())).build(); - Module module = - Module.builder() - .setName("foo") - .setVersion(Version.parse("1.0")) - .setKey(createModuleKey("foo", "")) - .build(); + Module module = buildModule("foo", "1.0").setKey(createModuleKey("foo", "")).build(); AbridgedModule abridgedModule = AbridgedModule.from(module); ExternalDepsException e =