| // 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.devtools.build.lib.bazel.bzlmod.InterimModule.toModule; |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.devtools.build.lib.bazel.repository.downloader.Checksum; |
| import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable; |
| import com.google.devtools.build.lib.skyframe.SkyFunctions; |
| import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; |
| import com.google.devtools.build.skyframe.SkyKey; |
| import com.google.devtools.build.skyframe.SkyValue; |
| import com.ryanharter.auto.value.gson.GenerateTypeAdapter; |
| import java.util.Map; |
| import java.util.Optional; |
| |
| /** |
| * The result of reading the lockfile. Contains the lockfile version, module hash, definitions of |
| * module repositories, post-resolution dependency graph and module extensions data (ID, hash, |
| * definition, usages) |
| */ |
| @AutoValue |
| @GenerateTypeAdapter |
| public abstract class BazelLockFileValue implements SkyValue, Postable { |
| |
| public static final int LOCK_FILE_VERSION = 8; |
| |
| @SerializationConstant public static final SkyKey KEY = () -> SkyFunctions.BAZEL_LOCK_FILE; |
| |
| static Builder builder() { |
| return new AutoValue_BazelLockFileValue.Builder() |
| .setLockFileVersion(LOCK_FILE_VERSION) |
| .setModuleExtensions(ImmutableMap.of()) |
| .setRegistryFileHashes(ImmutableMap.of()); |
| } |
| |
| /** Current version of the lock file */ |
| public abstract int getLockFileVersion(); |
| |
| /** Hash of the Module file */ |
| public abstract String getModuleFileHash(); |
| |
| /** Command line flags and environment variables that can affect the resolution */ |
| public abstract BzlmodFlagsAndEnvVars getFlags(); |
| |
| /** Module hash of each local path override in the root module file */ |
| public abstract ImmutableMap<String, String> getLocalOverrideHashes(); |
| |
| /** The post-selection dep graph retrieved from the lock file. */ |
| public abstract ImmutableMap<ModuleKey, Module> getModuleDepGraph(); |
| |
| /** Hashes of files retrieved from registries. */ |
| public abstract ImmutableMap<String, Optional<Checksum>> getRegistryFileHashes(); |
| |
| /** Mapping the extension id to the module extension data */ |
| public abstract ImmutableMap< |
| ModuleExtensionId, ImmutableMap<ModuleExtensionEvalFactors, LockFileModuleExtension>> |
| getModuleExtensions(); |
| |
| public abstract Builder toBuilder(); |
| |
| /** Builder type for {@link BazelLockFileValue}. */ |
| @AutoValue.Builder |
| public abstract static class Builder { |
| public abstract Builder setLockFileVersion(int value); |
| |
| public abstract Builder setModuleFileHash(String value); |
| |
| public abstract Builder setFlags(BzlmodFlagsAndEnvVars value); |
| |
| public abstract Builder setLocalOverrideHashes(ImmutableMap<String, String> value); |
| |
| public abstract Builder setModuleDepGraph(ImmutableMap<ModuleKey, Module> value); |
| |
| public abstract Builder setRegistryFileHashes(ImmutableMap<String, Optional<Checksum>> value); |
| |
| public abstract Builder setModuleExtensions( |
| ImmutableMap< |
| ModuleExtensionId, |
| ImmutableMap<ModuleExtensionEvalFactors, LockFileModuleExtension>> |
| value); |
| |
| public abstract BazelLockFileValue build(); |
| } |
| |
| /** Returns the difference between the lockfile and the current module & flags */ |
| public ImmutableList<String> getModuleAndFlagsDiff( |
| String moduleFileHash, |
| ImmutableMap<String, String> localOverrideHashes, |
| BzlmodFlagsAndEnvVars flags) { |
| ImmutableList.Builder<String> moduleDiff = new ImmutableList.Builder<>(); |
| if (getLockFileVersion() != BazelLockFileValue.LOCK_FILE_VERSION) { |
| return moduleDiff |
| .add("the version of the lockfile is not compatible with the current Bazel") |
| .build(); |
| } |
| if (!moduleFileHash.equals(getModuleFileHash())) { |
| moduleDiff.add("the root MODULE.bazel has been modified"); |
| } |
| moduleDiff.addAll(getFlags().getDiffFlags(flags)); |
| |
| for (Map.Entry<String, String> entry : localOverrideHashes.entrySet()) { |
| String currentValue = entry.getValue(); |
| String lockfileValue = getLocalOverrideHashes().get(entry.getKey()); |
| // If the lockfile value is null, the module hash would be different anyway |
| if (lockfileValue != null && !currentValue.equals(lockfileValue)) { |
| moduleDiff.add( |
| "The MODULE.bazel file has changed for the overriden module: " + entry.getKey()); |
| } |
| } |
| return moduleDiff.build(); |
| } |
| |
| /** |
| * Returns a new BazelLockFileValue in which all information about the root module has been |
| * replaced by the given value. |
| * |
| * <p>This operation is shallow: If the new root module has different dependencies, the dep graph |
| * will not be updated. |
| */ |
| public BazelLockFileValue withShallowlyReplacedRootModule( |
| ModuleFileValue.RootModuleFileValue value) { |
| ImmutableMap.Builder<ModuleKey, Module> newDepGraph = ImmutableMap.builder(); |
| newDepGraph.putAll(getModuleDepGraph()); |
| newDepGraph.put( |
| ModuleKey.ROOT, |
| toModule( |
| value |
| .getModule() |
| .withDepSpecsTransformed( |
| InterimModule.applyOverrides( |
| value.getOverrides(), value.getModule().getName())), |
| /* override= */ null, |
| /* remoteRepoSpec= */ null)); |
| return toBuilder() |
| .setModuleFileHash(value.getModuleFileHash()) |
| .setModuleDepGraph(newDepGraph.buildKeepingLast()) |
| .build(); |
| } |
| } |