blob: cd3eff788a8962eef7ec943547363728d69ebe35 [file] [log] [blame]
// 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();
}
}