From d0b4c3990c23ddd5bd8f1c300d0bbaebb2fc69f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?X=C3=B9d=C5=8Dng=20Y=C3=A1ng?= Date: Fri, 26 Jan 2024 20:25:17 +0100 Subject: [PATCH] [7.1.0] bzlmod: support git repos in source.json (#21036) bzlmod: support git repos in source.json Closes #20912. RELNOTES: Added `init_submodules` attribute to `git_override`. Registries now support the `git_repository` type in `source.json`. Change-Id: Ia267131e6d081572a642888ba34e285805bbbe9f PiperOrigin-RevId: 601268823 --------- Co-authored-by: Nachum Goldstein Co-authored-by: Keith Smiley --- site/en/external/registry.md | 10 ++ .../devtools/build/lib/bazel/bzlmod/BUILD | 1 + .../build/lib/bazel/bzlmod/GitOverride.java | 35 +++-- .../lib/bazel/bzlmod/GitRepoSpecBuilder.java | 132 ++++++++++++++++ .../build/lib/bazel/bzlmod/IndexRegistry.java | 143 +++++++++++++----- .../lib/bazel/bzlmod/ModuleFileGlobals.java | 12 +- .../lib/skyframe/BzlmodRepoRuleFunction.java | 4 +- src/test/py/bazel/bzlmod/bazel_module_test.py | 45 ++++++ src/test/py/bazel/bzlmod/test_utils.py | 24 +++ 9 files changed, 346 insertions(+), 60 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/bazel/bzlmod/GitRepoSpecBuilder.java diff --git a/site/en/external/registry.md b/site/en/external/registry.md index 0cdf9d64b8b13d..2a064df2740ba2 100644 --- a/site/en/external/registry.md +++ b/site/en/external/registry.md @@ -64,6 +64,16 @@ An index registry must follow the format below: By default, the archive type is determined from the file extension of the URL. If the file has no extension, you can explicitly specify one of the following: `"zip"`, `"jar"`, `"war"`, `"aar"`, `"tar"`, `"tar.gz"`, `"tgz"`, `"tar.xz"`, `"txz"`, `"tar.zst"`, `"tzst"`, `tar.bz2`, `"ar"`, or `"deb"`. + * The type can be changed to use a git repository, with these fields: + * `type`: `git_repository` + * The following fields as described at https://bazel.build/rules/lib/repo/git: + * `remote` + * `commit` + * `shallow_since` + * `tag` + * `init_submodules` + * `verbose` + * `strip_prefix` * The type can be changed to use a local path, representing a `local_repository` repo, with these fields: * `type`: `local_path` 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 0083f8057b24ad..18ce05e87cf197 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 @@ -18,6 +18,7 @@ java_library( srcs = [ "ArchiveRepoSpecBuilder.java", "AttributeValues.java", + "GitRepoSpecBuilder.java", "ModuleFile.java", "ModuleKey.java", "RepoSpec.java", 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 260f805f2d7f1b..586fafa97b5a6b 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,22 +17,21 @@ 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.bzlmod.BazelModuleInspectorValue.AugmentedModule.ResolutionReason; import com.google.devtools.build.lib.cmdline.RepositoryName; /** Specifies that a module should be retrieved from a Git repository. */ @AutoValue public abstract class GitOverride implements NonRegistryOverride { - public static final String GIT_REPOSITORY_PATH = "@bazel_tools//tools/build_defs/repo:git.bzl"; - public static GitOverride create( String remote, String commit, ImmutableList patches, ImmutableList patchCmds, - int patchStrip) { - return new AutoValue_GitOverride(remote, commit, patches, patchCmds, patchStrip); + int patchStrip, + boolean initSubmodules) { + return new AutoValue_GitOverride( + remote, commit, patches, patchCmds, patchStrip, initSubmodules); } /** The URL pointing to the git repository. */ @@ -50,22 +49,22 @@ public static GitOverride create( /** The number of path segments to strip from the paths in the supplied patches. */ public abstract int getPatchStrip(); + /** Whether submodules in the fetched repo should be recursively initialized. */ + public abstract boolean getInitSubmodules(); + /** Returns the {@link RepoSpec} that defines this repository. */ @Override public RepoSpec getRepoSpec(RepositoryName repoName) { - ImmutableMap.Builder attrBuilder = ImmutableMap.builder(); - attrBuilder - .put("name", repoName.getName()) - .put("remote", getRemote()) - .put("commit", getCommit()) - .put("patches", getPatches()) - .put("patch_cmds", getPatchCmds()) - .put("patch_args", ImmutableList.of("-p" + getPatchStrip())); - return RepoSpec.builder() - .setBzlFile(GIT_REPOSITORY_PATH) - .setRuleClassName("git_repository") - .setAttributes(AttributeValues.create(attrBuilder.buildOrThrow())) - .build(); + GitRepoSpecBuilder builder = new GitRepoSpecBuilder(); + builder + .setRepoName(repoName.getName()) + .setRemote(getRemote()) + .setCommit(getCommit()) + .setPatches(getPatches()) + .setPatchCmds(getPatchCmds()) + .setPatchArgs(ImmutableList.of("-p" + getPatchStrip())) + .setInitSubmodules(getInitSubmodules()); + return builder.build(); } @Override diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/GitRepoSpecBuilder.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/GitRepoSpecBuilder.java new file mode 100644 index 00000000000000..838ea37629b960 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/GitRepoSpecBuilder.java @@ -0,0 +1,132 @@ +// 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 com.google.common.collect.ImmutableMap; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import java.util.List; + +/** + * Builder for a {@link RepoSpec} object that indicates how to materialize a repo corresponding to a + * {@code git_repository} repo rule call. + */ +public class GitRepoSpecBuilder { + + public static final String GIT_REPO_PATH = "@bazel_tools//tools/build_defs/repo:git.bzl"; + + private final ImmutableMap.Builder attrBuilder; + + public GitRepoSpecBuilder() { + attrBuilder = new ImmutableMap.Builder<>(); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setRepoName(String repoName) { + return setAttr("name", repoName); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setRemote(String remoteRepoUrl) { + return setAttr("remote", remoteRepoUrl); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setCommit(String gitCommitHash) { + return setAttr("commit", gitCommitHash); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setShallowSince(String shallowSince) { + return setAttr("shallow_since", shallowSince); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setTag(String tag) { + return setAttr("tag", tag); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setInitSubmodules(boolean initSubmodules) { + setAttr("init_submodules", initSubmodules); + setAttr("recursive_init_submodules", initSubmodules); + return this; + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setVerbose(boolean verbose) { + return setAttr("verbose", verbose); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setStripPrefix(String stripPrefix) { + return setAttr("strip_prefix", stripPrefix); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setPatches(List patches) { + return setAttr("patches", patches); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setPatchTool(String patchTool) { + return setAttr("patch_tool", patchTool); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setPatchArgs(List patchArgs) { + return setAttr("patch_args", patchArgs); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setPatchCmds(List patchCmds) { + return setAttr("patch_cmds", patchCmds); + } + + @CanIgnoreReturnValue + public GitRepoSpecBuilder setPatchCmdsWin(List patchCmdsWin) { + return setAttr("patch_cmds_win", patchCmdsWin); + } + + public RepoSpec build() { + return RepoSpec.builder() + .setBzlFile(GIT_REPO_PATH) + .setRuleClassName("git_repository") + .setAttributes(AttributeValues.create(attrBuilder.buildOrThrow())) + .build(); + } + + @CanIgnoreReturnValue + private GitRepoSpecBuilder setAttr(String name, String value) { + if (value != null && !value.isEmpty()) { + attrBuilder.put(name, value); + } + return this; + } + + @CanIgnoreReturnValue + private GitRepoSpecBuilder setAttr(String name, boolean value) { + attrBuilder.put(name, value); + return this; + } + + @CanIgnoreReturnValue + private GitRepoSpecBuilder setAttr(String name, List value) { + if (value != null && !value.isEmpty()) { + attrBuilder.put(name, value); + } + return this; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/IndexRegistry.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/IndexRegistry.java index 057eb4890cb39f..3bfafe0374692d 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/IndexRegistry.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/IndexRegistry.java @@ -59,6 +59,8 @@ public class IndexRegistry implements Registry { private final Gson gson; private volatile Optional bazelRegistryJson; + private static final String SOURCE_JSON_FILENAME = "source.json"; + public IndexRegistry( URI uri, String unresolvedUri, @@ -117,34 +119,67 @@ private static class BazelRegistryJson { String moduleBasePath; } - /** Represents fields available in {@code source.json} for each version of a module. */ + /** Represents the type field in {@code source.json} for each version of a module. */ private static class SourceJson { String type = "archive"; + } + + /** Represents fields in {@code source.json} for each archive-type version of a module. */ + private static class ArchiveSourceJson { URL url; String integrity; String stripPrefix; Map patches; int patchStrip; - String path; String archiveType; } + /** Represents fields in {@code source.json} for each local_path-type version of a module. */ + private static class LocalPathSourceJson { + String path; + } + + /** Represents fields in {@code source.json} for each git_repository-type version of a module. */ + private static class GitRepoSourceJson { + String remote; + String commit; + String shallowSince; + String tag; + boolean initSubmodules; + boolean verbose; + String stripPrefix; + } + /** - * Grabs a JSON file from the given URL, and returns it as a parsed object with fields in {@code - * T}. Returns {@link Optional#empty} if the file doesn't exist. + * Grabs a JSON file from the given URL, and returns its content. Returns {@link Optional#empty} + * if the file doesn't exist. */ - private Optional grabJson(String url, Class klass, ExtendedEventHandler eventHandler) + private Optional grabJsonFile(String url, ExtendedEventHandler eventHandler) throws IOException, InterruptedException { Optional bytes = grabFile(url, eventHandler); if (bytes.isEmpty()) { return Optional.empty(); } - String jsonString = new String(bytes.get(), UTF_8); - if (jsonString.isBlank()) { + return Optional.of(new String(bytes.get(), UTF_8)); + } + + /** + * Grabs a JSON file from the given URL, and returns it as a parsed object with fields in {@code + * T}. Returns {@link Optional#empty} if the file doesn't exist. + */ + private Optional grabJson(String url, Class klass, ExtendedEventHandler eventHandler) + throws IOException, InterruptedException { + Optional jsonString = grabJsonFile(url, eventHandler); + if (jsonString.isEmpty() || jsonString.get().isBlank()) { return Optional.empty(); } + return Optional.of(parseJson(jsonString.get(), url, klass)); + } + + /** Parses the given JSON string and returns it as an object with fields in {@code T}. */ + private T parseJson(String jsonString, String url, Class klass) throws IOException { try { - return Optional.of(gson.fromJson(jsonString, klass)); + return gson.fromJson(jsonString, klass); } catch (JsonParseException e) { throw new IOException( String.format("Unable to parse json at url %s: %s", url, e.getMessage()), e); @@ -155,30 +190,44 @@ private Optional grabJson(String url, Class klass, ExtendedEventHandle public RepoSpec getRepoSpec( ModuleKey key, RepositoryName repoName, ExtendedEventHandler eventHandler) throws IOException, InterruptedException { - Optional sourceJson = - grabJson( - constructUrl( - uri.toString(), - "modules", - key.getName(), - key.getVersion().toString(), - "source.json"), - SourceJson.class, - eventHandler); - if (sourceJson.isEmpty()) { + String jsonUrl = + constructUrl( + uri.toString(), + "modules", + key.getName(), + key.getVersion().toString(), + SOURCE_JSON_FILENAME); + Optional jsonString = grabJsonFile(jsonUrl, eventHandler); + if (jsonString.isEmpty()) { throw new FileNotFoundException( - String.format("Module %s's source information not found in registry %s", key, uri)); + String.format("Module %s's %s not found in registry %s", key, SOURCE_JSON_FILENAME, uri)); } - - String type = sourceJson.get().type; - switch (type) { + SourceJson sourceJson = parseJson(jsonString.get(), jsonUrl, SourceJson.class); + switch (sourceJson.type) { case "archive": - return createArchiveRepoSpec(sourceJson, getBazelRegistryJson(eventHandler), key, repoName); + { + ArchiveSourceJson typedSourceJson = + parseJson(jsonString.get(), jsonUrl, ArchiveSourceJson.class); + return createArchiveRepoSpec( + typedSourceJson, getBazelRegistryJson(eventHandler), key, repoName); + } case "local_path": - return createLocalPathRepoSpec( - sourceJson, getBazelRegistryJson(eventHandler), key, repoName); + { + LocalPathSourceJson typedSourceJson = + parseJson(jsonString.get(), jsonUrl, LocalPathSourceJson.class); + return createLocalPathRepoSpec( + typedSourceJson, getBazelRegistryJson(eventHandler), key, repoName); + } + case "git_repository": + { + GitRepoSourceJson typedSourceJson = + parseJson(jsonString.get(), jsonUrl, GitRepoSourceJson.class); + return createGitRepoSpec( + typedSourceJson, getBazelRegistryJson(eventHandler), key, repoName); + } default: - throw new IOException(String.format("Invalid source type for module %s", key)); + throw new IOException( + String.format("Invalid source type \"%s\" for module %s", sourceJson.type, key)); } } @@ -200,12 +249,12 @@ private Optional getBazelRegistryJson(ExtendedEventHandler ev } private RepoSpec createLocalPathRepoSpec( - Optional sourceJson, + LocalPathSourceJson sourceJson, Optional bazelRegistryJson, ModuleKey key, RepositoryName repoName) throws IOException { - String path = sourceJson.get().path; + String path = sourceJson.path; if (!PathFragment.isAbsolute(path)) { String moduleBase = bazelRegistryJson.get().moduleBasePath; path = moduleBase + "/" + path; @@ -236,16 +285,16 @@ private RepoSpec createLocalPathRepoSpec( } private RepoSpec createArchiveRepoSpec( - Optional sourceJson, + ArchiveSourceJson sourceJson, Optional bazelRegistryJson, ModuleKey key, RepositoryName repoName) throws IOException { - URL sourceUrl = sourceJson.get().url; + URL sourceUrl = sourceJson.url; if (sourceUrl == null) { throw new IOException(String.format("Missing source URL for module %s", key)); } - if (sourceJson.get().integrity == null) { + if (sourceJson.integrity == null) { throw new IOException(String.format("Missing integrity for module %s", key)); } @@ -268,8 +317,8 @@ private RepoSpec createArchiveRepoSpec( // Build remote patches as key-value pairs of "url" => "integrity". ImmutableMap.Builder remotePatches = new ImmutableMap.Builder<>(); - if (sourceJson.get().patches != null) { - for (Map.Entry entry : sourceJson.get().patches.entrySet()) { + if (sourceJson.patches != null) { + for (Map.Entry entry : sourceJson.patches.entrySet()) { remotePatches.put( constructUrl( unresolvedUri, @@ -285,11 +334,29 @@ private RepoSpec createArchiveRepoSpec( return new ArchiveRepoSpecBuilder() .setRepoName(repoName.getName()) .setUrls(urls.build()) - .setIntegrity(sourceJson.get().integrity) - .setStripPrefix(Strings.nullToEmpty(sourceJson.get().stripPrefix)) + .setIntegrity(sourceJson.integrity) + .setStripPrefix(Strings.nullToEmpty(sourceJson.stripPrefix)) .setRemotePatches(remotePatches.buildOrThrow()) - .setRemotePatchStrip(sourceJson.get().patchStrip) - .setArchiveType(sourceJson.get().archiveType) + .setRemotePatchStrip(sourceJson.patchStrip) + .setArchiveType(sourceJson.archiveType) + .build(); + } + + private RepoSpec createGitRepoSpec( + GitRepoSourceJson sourceJson, + Optional bazelRegistryJson, + ModuleKey key, + RepositoryName repoName) + throws IOException { + return new GitRepoSpecBuilder() + .setRepoName(repoName.getName()) + .setRemote(sourceJson.remote) + .setCommit(sourceJson.commit) + .setShallowSince(sourceJson.shallowSince) + .setTag(sourceJson.tag) + .setInitSubmodules(sourceJson.initSubmodules) + .setVerbose(sourceJson.verbose) + .setStripPrefix(sourceJson.stripPrefix) .build(); } 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 92e3aa5b2f8a77..70502d4bbb00ec 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 @@ -1038,6 +1038,12 @@ public void archiveOverride( named = true, positional = false, defaultValue = "0"), + @Param( + name = "init_submodules", + doc = "Whether submodules in the fetched repo should be recursively initialized.", + named = true, + positional = false, + defaultValue = "False"), }) public void gitOverride( String moduleName, @@ -1045,7 +1051,8 @@ public void gitOverride( String commit, Iterable patches, Iterable patchCmds, - StarlarkInt patchStrip) + StarlarkInt patchStrip, + boolean initSubmodules) throws EvalException { hadNonModuleCall = true; addOverride( @@ -1055,7 +1062,8 @@ public void gitOverride( commit, Sequence.cast(patches, String.class, "patches").getImmutableList(), Sequence.cast(patchCmds, String.class, "patchCmds").getImmutableList(), - patchStrip.toInt("git_override.patch_strip"))); + patchStrip.toInt("git_override.patch_strip"), + initSubmodules)); } @StarlarkMethod( 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 c9076034e60a6c..eafa0ef09924a2 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 @@ -26,7 +26,7 @@ import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphValue; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleCreator; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleValue; -import com.google.devtools.build.lib.bazel.bzlmod.GitOverride; +import com.google.devtools.build.lib.bazel.bzlmod.GitRepoSpecBuilder; import com.google.devtools.build.lib.bazel.bzlmod.ModuleExtensionId; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue; import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileValue.RootModuleFileValue; @@ -246,7 +246,7 @@ private AttributeValues resolveRemotePatchesUrl(RepoSpec repoSpec) { private static final Set BOOTSTRAP_RULE_CLASSES = ImmutableSet.of( ArchiveRepoSpecBuilder.HTTP_ARCHIVE_PATH + "%http_archive", - GitOverride.GIT_REPOSITORY_PATH + "%git_repository"); + GitRepoSpecBuilder.GIT_REPO_PATH + "%git_repository"); /** Loads modules from the given bzl file. */ private ImmutableMap loadBzlModules( diff --git a/src/test/py/bazel/bzlmod/bazel_module_test.py b/src/test/py/bazel/bzlmod/bazel_module_test.py index d821e5764278cc..5038c3918aec84 100644 --- a/src/test/py/bazel/bzlmod/bazel_module_test.py +++ b/src/test/py/bazel/bzlmod/bazel_module_test.py @@ -16,6 +16,8 @@ import os import pathlib +import shutil +import subprocess import tempfile from absl.testing import absltest from src.test.py.bazel import test_base @@ -293,7 +295,9 @@ def setUpProjectWithLocalRegistryModule(self, dep_name, dep_version): self.main_registry.generateCcSource(dep_name, dep_version) self.main_registry.createLocalPathModule(dep_name, dep_version, dep_name + '/' + dep_version) + self.writeCcProjectFiles(dep_name, dep_version) + def writeCcProjectFiles(self, dep_name, dep_version): self.ScratchFile('main.cc', [ '#include "%s.h"' % dep_name, 'int main() {', @@ -311,6 +315,41 @@ def setUpProjectWithLocalRegistryModule(self, dep_name, dep_version): ')', ]) + def setUpProjectWithGitRegistryModule(self, dep_name, dep_version): + src_dir = self.main_registry.generateCcSource(dep_name, dep_version) + + # Move the src_dir to a temp dir and make that temp dir a git repo. + repo_dir = os.path.join(self.registries_work_dir, 'git_repo', dep_name) + os.makedirs(repo_dir) + shutil.move( + # Workaround https://bugs.python.org/issue32689 for Python < 3.9 + str(src_dir), + repo_dir, + ) + repo_dir = os.path.join(repo_dir, os.path.basename(src_dir)) + subprocess.check_output(['git', 'init'], cwd=repo_dir) + subprocess.check_output( + ['git', 'config', 'user.email', 'example@bazel-dev.org'], cwd=repo_dir + ) + subprocess.check_output( + ['git', 'config', 'user.name', 'example'], cwd=repo_dir + ) + subprocess.check_output(['git', 'add', '--all'], cwd=repo_dir) + subprocess.check_output(['git', 'commit', '-m', 'Initialize'], cwd=repo_dir) + commit = subprocess.check_output( + ['git', 'rev-parse', 'HEAD'], cwd=repo_dir, universal_newlines=True + ).strip() + + self.main_registry.createGitRepoModule( + dep_name, + dep_version, + repo_dir, + commit=commit, + verbose=True, + shallow_since='2000-01-02', + ) + self.writeCcProjectFiles(dep_name, dep_version) + def testLocalRepoInSourceJsonAbsoluteBasePath(self): self.main_registry.setModuleBasePath(str(self.main_registry.projects)) self.setUpProjectWithLocalRegistryModule('sss', '1.3') @@ -323,6 +362,12 @@ def testLocalRepoInSourceJsonRelativeBasePath(self): _, stdout, _ = self.RunBazel(['run', '//:main']) self.assertIn('main function => sss@1.3', stdout) + def testGitRepoAbsoluteBasePath(self): + self.main_registry.setModuleBasePath(str(self.main_registry.projects)) + self.setUpProjectWithGitRegistryModule('sss', '1.3') + _, stdout, _ = self.RunBazel(['run', '//:main']) + self.assertIn('main function => sss@1.3', stdout) + def testNativePackageRelativeLabel(self): self.ScratchFile( 'MODULE.bazel', diff --git a/src/test/py/bazel/bzlmod/test_utils.py b/src/test/py/bazel/bzlmod/test_utils.py index f93d41040eeb67..78102db66ecbac 100644 --- a/src/test/py/bazel/bzlmod/test_utils.py +++ b/src/test/py/bazel/bzlmod/test_utils.py @@ -326,6 +326,30 @@ def createLocalPathModule(self, name, version, path, deps=None): 'path': path, } + self._createModuleAndSourceJson( + module_dir, name, version, path, deps, source + ) + + def createGitRepoModule(self, name, version, path, deps=None, **kwargs): + """Add a git repo module into the registry.""" + module_dir = self.root.joinpath('modules', name, version) + module_dir.mkdir(parents=True, exist_ok=True) + + # Create source.json & copy patch files to the registry + source = { + 'type': 'git_repository', + 'remote': f'file://{path}', + } + source.update(**kwargs) + + self._createModuleAndSourceJson( + module_dir, name, version, path, deps, source + ) + + def _createModuleAndSourceJson( + self, module_dir, name, version, path, deps, source + ): + """Create the MODULE.bazel and source.json files for a module.""" if deps is None: deps = {}