diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ArchiveOverride.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ArchiveOverride.java index ad1a8cac3e43a6..8bb53d9926f2ad 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ArchiveOverride.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ArchiveOverride.java @@ -45,4 +45,17 @@ public static ArchiveOverride create( /** The number of path segments to strip from the paths in the supplied patches. */ public abstract int getPatchStrip(); + + /** Returns the {@link RepoSpec} that defines this repository. */ + @Override + public RepoSpec getRepoSpec(String repoName) { + return new ArchiveRepoSpecBuilder() + .setRepoName(repoName) + .setUrls(getUrls()) + .setIntegrity(getIntegrity()) + .setStripPrefix(getStripPrefix()) + .setPatches(getPatches()) + .setPatchStrip(getPatchStrip()) + .build(); + } } 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 89a6b060b89bdc..89261a5fbdc6ee 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 @@ -107,8 +107,12 @@ java_library( "BzlmodRepoRuleHelperImpl.java", ], deps = [ - "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:common", + ":common", + ":registry", + ":resolution", + "//src/main/java/com/google/devtools/build/lib/events", "//src/main/java/com/google/devtools/build/skyframe", + "//third_party:guava", ], ) diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelper.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelper.java index e51e07d267bd62..085f20de0bbfe8 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelper.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelper.java @@ -15,9 +15,11 @@ package com.google.devtools.build.lib.bazel.bzlmod; import com.google.devtools.build.skyframe.SkyFunction.Environment; +import java.io.IOException; import java.util.Optional; /** A helper to get {@link RepoSpec} for Bzlmod generated repositories. */ public interface BzlmodRepoRuleHelper { - Optional getRepoSpec(Environment env, String repositoryName); + Optional getRepoSpec(Environment env, String repositoryName) + throws InterruptedException, IOException; } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperImpl.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperImpl.java index 42d2ec8094b454..9065bf15c4c3d2 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperImpl.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperImpl.java @@ -14,15 +14,106 @@ package com.google.devtools.build.lib.bazel.bzlmod; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.skyframe.SkyFunction.Environment; +import java.io.IOException; import java.util.Optional; /** A helper class to get {@link RepoSpec} for Bzlmod generated repositories. */ public final class BzlmodRepoRuleHelperImpl implements BzlmodRepoRuleHelper { @Override - public Optional getRepoSpec(Environment env, String repositoryName) { - // TODO(pcloudy): Implement calculating RepoSpec. + public Optional getRepoSpec(Environment env, String repositoryName) + throws InterruptedException, IOException { + + ModuleFileValue root = (ModuleFileValue) env.getValue(ModuleFileValue.keyForRootModule()); + if (env.valuesMissing()) { + return null; + } + ImmutableMap overrides = root.getOverrides(); + + // Step 1: Look for repositories defined by non-registry overrides. + Optional repoSpec = checkRepoFromNonRegistryOverrides(overrides, repositoryName); + if (repoSpec.isPresent()) { + return repoSpec; + } + + // SelectionValue is affected by repos found in Step 1, therefore it should NOT be asked + // in Step 1 to avoid cycle dependency. + SelectionValue selectionValue = (SelectionValue) env.getValue(SelectionValue.KEY); + if (env.valuesMissing()) { + return null; + } + + // Step 2: Look for repositories derived from Bazel Modules. + repoSpec = + checkRepoFromBazelModules(selectionValue, overrides, env.getListener(), repositoryName); + if (repoSpec.isPresent()) { + return repoSpec; + } + + // Step 3: Look for repositories derived from module rules. + return checkRepoFromModuleRules(); + } + + private static Optional checkRepoFromNonRegistryOverrides( + ImmutableMap overrides, String repositoryName) { + if (overrides.containsKey(repositoryName)) { + ModuleOverride override = overrides.get(repositoryName); + if (override instanceof NonRegistryOverride) { + return Optional.of(((NonRegistryOverride) override).getRepoSpec(repositoryName)); + } + } + return Optional.empty(); + } + + private static Optional checkRepoFromBazelModules( + SelectionValue selectionValue, + ImmutableMap overrides, + ExtendedEventHandler eventlistener, + String repositoryName) + throws InterruptedException, IOException { + for (ModuleKey moduleKey : selectionValue.getDepGraph().keySet()) { + // TODO(pcloudy): Support multiple version override. + // Currently we assume there is only one version for each module, therefore the module name is + // the repository name, but that's not the case if multiple version of the same module are + // allowed. + if (moduleKey.getName().equals(repositoryName)) { + Module module = selectionValue.getDepGraph().get(moduleKey); + Registry registry = checkNotNull(module.getRegistry()); + RepoSpec repoSpec = registry.getRepoSpec(moduleKey, repositoryName, eventlistener); + repoSpec = maybeAppendAdditionalPatches(repoSpec, overrides.get(moduleKey.getName())); + return Optional.of(repoSpec); + } + } + return Optional.empty(); + } + + private static RepoSpec maybeAppendAdditionalPatches(RepoSpec repoSpec, ModuleOverride override) { + if (!(override instanceof SingleVersionOverride)) { + return repoSpec; + } + SingleVersionOverride singleVersion = (SingleVersionOverride) override; + if (singleVersion.getPatches().isEmpty()) { + return repoSpec; + } + ImmutableMap.Builder attrBuilder = ImmutableMap.builder(); + attrBuilder.putAll(repoSpec.attributes()); + attrBuilder.put("patches", singleVersion.getPatches()); + attrBuilder.put("patch_args", ImmutableList.of("-p" + singleVersion.getPatchStrip())); + return RepoSpec.builder() + .setBzlFile(repoSpec.bzlFile()) + .setRuleClassName(repoSpec.ruleClassName()) + .setAttributes(attrBuilder.build()) + .build(); + } + + private static Optional checkRepoFromModuleRules() { + // TODO(pcloudy): Implement calculating RepoSpec from module rules. return Optional.empty(); } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/GitOverride.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/GitOverride.java index 725c74d8cb5142..b8a50dbaaf25d5 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/GitOverride.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/GitOverride.java @@ -17,6 +17,7 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; /** Specifies that a module should be retrieved from a Git repository. */ @AutoValue @@ -37,4 +38,21 @@ public static GitOverride create( /** The number of path segments to strip from the paths in the supplied patches. */ public abstract int getPatchStrip(); + + /** Returns the {@link RepoSpec} that defines this repository. */ + @Override + public RepoSpec getRepoSpec(String repoName) { + ImmutableMap.Builder attrBuilder = ImmutableMap.builder(); + attrBuilder + .put("name", repoName) + .put("remote", getRemote()) + .put("commit", getCommit()) + .put("patches", getPatches()) + .put("patch_args", ImmutableList.of("-p" + getPatchStrip())); + return RepoSpec.builder() + .setBzlFile("@bazel_tools//tools/build_defs/repo:git.bzl") + .setRuleClassName("git_repository") + .setAttributes(attrBuilder.build()) + .build(); + } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/LocalPathOverride.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/LocalPathOverride.java index 9934f12f629c05..941aa7ce3a6b8e 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/LocalPathOverride.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/LocalPathOverride.java @@ -16,6 +16,7 @@ package com.google.devtools.build.lib.bazel.bzlmod; import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; /** Specifies that a module should be retrieved from a local directory. */ @AutoValue @@ -26,4 +27,13 @@ public static LocalPathOverride create(String path) { /** The path to the local directory where the module contents should be found. */ public abstract String getPath(); + + /** Returns the {@link RepoSpec} that defines this repository. */ + @Override + public RepoSpec getRepoSpec(String repoName) { + return RepoSpec.builder() + .setRuleClassName("local_repository") + .setAttributes(ImmutableMap.of("name", repoName, "path", getPath())) + .build(); + } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/NonRegistryOverride.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/NonRegistryOverride.java index 86b280037e61db..ca741be107dce9 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/NonRegistryOverride.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/NonRegistryOverride.java @@ -23,5 +23,6 @@ */ public interface NonRegistryOverride extends ModuleOverride { - // TODO(wyv): getRepoSpec + /** Returns the {@link RepoSpec} that defines this repository. */ + RepoSpec getRepoSpec(String repoName); } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/RepoSpec.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/RepoSpec.java index 844168ed22521a..71324a875cb169 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/RepoSpec.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/RepoSpec.java @@ -43,6 +43,8 @@ public static Builder builder() { public abstract static class Builder { public abstract Builder setBzlFile(String bzlFile); + public abstract Builder setBzlFile(Optional bzlFile); + public abstract Builder setRuleClassName(String name); public abstract Builder setAttributes(ImmutableMap attributes); 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 f01c3e48669001..2fff6e3659b84b 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 @@ -44,6 +44,7 @@ import com.google.devtools.build.skyframe.SkyFunctionException.Transience; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; +import java.io.IOException; import java.util.Optional; import javax.annotation.Nullable; import net.starlark.java.eval.Module; @@ -104,12 +105,16 @@ public SkyValue compute(SkyKey skyKey, Environment env) return createRuleFromSpec(repoSpec, starlarkSemantics, env); } - Optional result = bzlmodRepoRuleHelper.getRepoSpec(env, repositoryName); - if (env.valuesMissing()) { - return null; - } - if (result.isPresent()) { - return createRuleFromSpec(result.get(), starlarkSemantics, env); + try { + Optional result = bzlmodRepoRuleHelper.getRepoSpec(env, repositoryName); + if (env.valuesMissing()) { + return null; + } + if (result.isPresent()) { + return createRuleFromSpec(result.get(), starlarkSemantics, env); + } + } catch (IOException e) { + throw new BzlmodRepoRuleFunctionException(e, Transience.PERSISTENT); } return BzlmodRepoRuleValue.REPO_RULE_NOT_FOUND_VALUE; @@ -260,5 +265,9 @@ private static final class BzlmodRepoRuleFunctionException extends SkyFunctionEx BzlmodRepoRuleFunctionException(NoSuchPackageException e, Transience transience) { super(e, transience); } + + BzlmodRepoRuleFunctionException(IOException e, Transience transience) { + super(e, transience); + } } } diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD index d33041066023b8..fd8d2508d95c6e 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BUILD @@ -51,8 +51,10 @@ java_library( "//src/main/java/net/starlark/java/eval", "//src/test/java/com/google/devtools/build/lib/analysis/util", "//src/test/java/com/google/devtools/build/lib/testutil", + "//third_party:auto_value", "//third_party:caffeine", "//third_party:guava", + "//third_party:jsr305", "//third_party:junit4", "//third_party:truth", ], diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java new file mode 100644 index 00000000000000..f6f49c7f4ea281 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java @@ -0,0 +1,319 @@ +// Copyright 2021 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.Truth8.assertThat; +import static org.junit.Assert.fail; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.actions.FileStateValue; +import com.google.devtools.build.lib.actions.FileValue; +import com.google.devtools.build.lib.analysis.BlazeDirectories; +import com.google.devtools.build.lib.analysis.ServerDirectories; +import com.google.devtools.build.lib.analysis.util.AnalysisMock; +import com.google.devtools.build.lib.pkgcache.PathPackageLocator; +import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants; +import com.google.devtools.build.lib.skyframe.ExternalFilesHelper; +import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction; +import com.google.devtools.build.lib.skyframe.FileFunction; +import com.google.devtools.build.lib.skyframe.FileStateFunction; +import com.google.devtools.build.lib.skyframe.PrecomputedFunction; +import com.google.devtools.build.lib.skyframe.PrecomputedValue; +import com.google.devtools.build.lib.skyframe.SkyFunctions; +import com.google.devtools.build.lib.testutil.FoundationTestCase; +import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor; +import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.Root; +import com.google.devtools.build.lib.vfs.UnixGlob; +import com.google.devtools.build.skyframe.AbstractSkyKey; +import com.google.devtools.build.skyframe.EvaluationContext; +import com.google.devtools.build.skyframe.EvaluationResult; +import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator; +import com.google.devtools.build.skyframe.MemoizingEvaluator; +import com.google.devtools.build.skyframe.RecordingDifferencer; +import com.google.devtools.build.skyframe.SequencedRecordingDifferencer; +import com.google.devtools.build.skyframe.SequentialBuildDriver; +import com.google.devtools.build.skyframe.SkyFunction; +import com.google.devtools.build.skyframe.SkyFunctionException; +import com.google.devtools.build.skyframe.SkyFunctionException.Transience; +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.Optional; +import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.Nullable; +import net.starlark.java.eval.StarlarkSemantics; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link BzlmodRepoRuleHelperImpl}. */ +@RunWith(JUnit4.class) +public final class BzlmodRepoRuleHelperTest extends FoundationTestCase { + + private Path workspaceRoot; + private SequentialBuildDriver driver; + private RecordingDifferencer differencer; + private EvaluationContext evaluationContext; + private FakeRegistry.Factory registryFactory; + + @Before + public void setup() throws Exception { + workspaceRoot = scratch.dir("/ws"); + differencer = new SequencedRecordingDifferencer(); + evaluationContext = + EvaluationContext.newBuilder().setNumThreads(8).setEventHandler(reporter).build(); + registryFactory = new FakeRegistry.Factory(); + AtomicReference packageLocator = + new AtomicReference<>( + new PathPackageLocator( + outputBase, + ImmutableList.of(Root.fromPath(rootDirectory)), + BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)); + BlazeDirectories directories = + new BlazeDirectories( + new ServerDirectories(rootDirectory, outputBase, rootDirectory), + rootDirectory, + /* defaultSystemJavabase= */ null, + AnalysisMock.get().getProductName()); + ExternalFilesHelper externalFilesHelper = + ExternalFilesHelper.createForTesting( + packageLocator, + ExternalFileAction.DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS, + directories); + + MemoizingEvaluator evaluator = + new InMemoryMemoizingEvaluator( + ImmutableMap.builder() + .put(FileValue.FILE, new FileFunction(packageLocator)) + .put( + FileStateValue.FILE_STATE, + new FileStateFunction( + new AtomicReference(), + new AtomicReference<>(UnixGlob.DEFAULT_SYSCALLS), + externalFilesHelper)) + .put( + SkyFunctions.MODULE_FILE, + new ModuleFileFunction(registryFactory, workspaceRoot)) + .put(SkyFunctions.DISCOVERY, new DiscoveryFunction()) + .put(SkyFunctions.SELECTION, new SelectionFunction()) + .put( + GET_REPO_SPEC_BY_NAME_FUNCTION, + new GetRepoSpecByNameFunction(new BzlmodRepoRuleHelperImpl())) + .put(SkyFunctions.PRECOMPUTED, new PrecomputedFunction()) + .build(), + differencer); + driver = new SequentialBuildDriver(evaluator); + + PrecomputedValue.STARLARK_SEMANTICS.set(differencer, StarlarkSemantics.DEFAULT); + } + + @Test + public void getRepoSpec_bazelModule() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='A',version='0.1')", + "bazel_dep(name='B',version='1.0')"); + FakeRegistry registry = + registryFactory + .newFakeRegistry() + .addModule( + ModuleKey.create("B", "1.0"), + "module(name='B', version='1.0');bazel_dep(name='C',version='2.0')") + .addModule(ModuleKey.create("C", "2.0"), "module(name='C', version='2.0')"); + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + + EvaluationResult result = + driver.evaluate(ImmutableList.of(getRepoSpecByNameKey("C")), evaluationContext); + if (result.hasError()) { + fail(result.getError().toString()); + } + + Optional repoSpec = result.get(getRepoSpecByNameKey("C")).rule(); + assertThat(repoSpec) + .hasValue( + RepoSpec.builder() + .setRuleClassName("fake_http_archive_rule") + .setAttributes(ImmutableMap.of("repo_name", "C")) + .build()); + } + + @Test + public void getRepoSpec_nonRegistryOverride() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='A',version='0.1')", + "bazel_dep(name='B',version='1.0')", + "local_path_override(module_name='C',path='/foo/bar/C')"); + FakeRegistry registry = + registryFactory + .newFakeRegistry() + .addModule( + ModuleKey.create("B", "1.0"), + "module(name='B', version='1.0');bazel_dep(name='C',version='2.0')") + .addModule(ModuleKey.create("C", "2.0"), "module(name='C', version='2.0')"); + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + + EvaluationResult result = + driver.evaluate(ImmutableList.of(getRepoSpecByNameKey("C")), evaluationContext); + if (result.hasError()) { + fail(result.getError().toString()); + } + + Optional repoSpec = result.get(getRepoSpecByNameKey("C")).rule(); + assertThat(repoSpec) + .hasValue( + RepoSpec.builder() + .setRuleClassName("local_repository") + .setAttributes( + ImmutableMap.of( + "name", "C", + "path", "/foo/bar/C")) + .build()); + } + + @Test + public void getRepoSpec_singleVersionOverride() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='A',version='0.1')", + "bazel_dep(name='B',version='1.0')", + "single_version_override(", + " module_name='C',version='3.0',patches=['//:foo.patch'],patch_strip=1)"); + FakeRegistry registry = + registryFactory + .newFakeRegistry() + .addModule( + ModuleKey.create("B", "1.0"), + "module(name='B', version='1.0');bazel_dep(name='C',version='2.0')") + .addModule(ModuleKey.create("C", "2.0"), "module(name='C', version='2.0')") + .addModule(ModuleKey.create("C", "3.0"), "module(name='C', version='3.0')"); + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + + EvaluationResult result = + driver.evaluate(ImmutableList.of(getRepoSpecByNameKey("C")), evaluationContext); + if (result.hasError()) { + fail(result.getError().toString()); + } + + Optional repoSpec = result.get(getRepoSpecByNameKey("C")).rule(); + assertThat(repoSpec) + .hasValue( + RepoSpec.builder() + .setRuleClassName("fake_http_archive_rule") + .setAttributes( + ImmutableMap.of( + "repo_name", + "C", + "patches", + ImmutableList.of("//:foo.patch"), + "patch_args", + ImmutableList.of("-p1"))) + .build()); + } + + @Test + public void getRepoSpec_notFound() throws Exception { + scratch.file( + workspaceRoot.getRelative("MODULE.bazel").getPathString(), + "module(name='A',version='0.1')", + "bazel_dep(name='B',version='1.0')"); + FakeRegistry registry = + registryFactory + .newFakeRegistry() + .addModule(ModuleKey.create("B", "1.0"), "module(name='B', version='1.0')"); + ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl())); + + EvaluationResult result = + driver.evaluate(ImmutableList.of(getRepoSpecByNameKey("C")), evaluationContext); + if (result.hasError()) { + fail(result.getError().toString()); + } + + Optional repoSpec = result.get(getRepoSpecByNameKey("C")).rule(); + assertThat(repoSpec).isEmpty(); + } + + /** A helper SkyFunction to invoke BzlmodRepoRuleHelper */ + private static final SkyFunctionName GET_REPO_SPEC_BY_NAME_FUNCTION = + SkyFunctionName.createHermetic("GET_REPO_SPEC_BY_NAME_FUNCTION"); + + @AutoValue + abstract static class GetRepoSpecByNameValue implements SkyValue { + abstract Optional rule(); + + static GetRepoSpecByNameValue create(Optional rule) { + return new AutoValue_BzlmodRepoRuleHelperTest_GetRepoSpecByNameValue(rule); + } + } + + private static final class GetRepoSpecByNameFunction implements SkyFunction { + + private final BzlmodRepoRuleHelper bzlmodRepoRuleHelper; + + public GetRepoSpecByNameFunction(BzlmodRepoRuleHelper bzlmodRepoRuleHelper) { + this.bzlmodRepoRuleHelper = bzlmodRepoRuleHelper; + } + + @Nullable + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + String repositoryName = (String) skyKey.argument(); + Optional result; + try { + result = bzlmodRepoRuleHelper.getRepoSpec(env, repositoryName); + if (env.valuesMissing()) { + return null; + } + } catch (IOException e) { + throw new GetRepoSpecByNameFunctionException(e, Transience.PERSISTENT); + } + return GetRepoSpecByNameValue.create(result); + } + + @Nullable + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + } + + private static final class Key extends AbstractSkyKey { + private Key(String arg) { + super(arg); + } + + @Override + public SkyFunctionName functionName() { + return GET_REPO_SPEC_BY_NAME_FUNCTION; + } + } + + private static final class GetRepoSpecByNameFunctionException extends SkyFunctionException { + GetRepoSpecByNameFunctionException(IOException e, Transience transience) { + super(e, transience); + } + } + + private static SkyKey getRepoSpecByNameKey(String repositoryName) { + return new Key(repositoryName); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/FakeRegistry.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/FakeRegistry.java index 733480ff085062..9f40607a063f2a 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/FakeRegistry.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/FakeRegistry.java @@ -52,7 +52,7 @@ public Optional getModuleFile(ModuleKey key, ExtendedEventHandler eventH @Override public RepoSpec getRepoSpec(ModuleKey key, String repoName, ExtendedEventHandler eventHandler) { return RepoSpec.builder() - .setRuleClassName("fake_rule") + .setRuleClassName("fake_http_archive_rule") .setAttributes(ImmutableMap.of("repo_name", repoName)) .build(); }