| # pylint: disable=g-backslash-continuation |
| # 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. |
| # pylint: disable=g-long-ternary |
| |
| import os |
| import pathlib |
| import shutil |
| import subprocess |
| import sys |
| import tempfile |
| |
| from absl.testing import absltest |
| from src.test.py.bazel import test_base |
| from src.test.py.bazel.bzlmod.test_utils import BazelRegistry |
| from src.test.py.bazel.bzlmod.test_utils import integrity |
| from src.test.py.bazel.bzlmod.test_utils import read |
| from src.test.py.bazel.bzlmod.test_utils import scratchFile |
| |
| |
| class BazelModuleTest(test_base.TestBase): |
| |
| def setUp(self): |
| test_base.TestBase.setUp(self) |
| self.registries_work_dir = tempfile.mkdtemp(dir=self._test_cwd) |
| self.main_registry = BazelRegistry( |
| os.path.join(self.registries_work_dir, 'main')) |
| self.main_registry.start() |
| self.main_registry.createShModule('aaa', '1.0').createShModule( |
| 'aaa', '1.1' |
| ).createShModule( |
| 'bbb', '1.0', {'aaa': '1.0'}, {'aaa': 'com_foo_aaa'} |
| ).createShModule( |
| 'bbb', '1.1', {'aaa': '1.1'} |
| ).createShModule( |
| 'ccc', '1.1', {'aaa': '1.1', 'bbb': '1.1'} |
| ) |
| self.ScratchFile( |
| '.bazelrc', |
| [ |
| # In ipv6 only network, this has to be enabled. |
| # 'startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true', |
| 'build --registry=' + self.main_registry.getURL(), |
| # We need to have BCR here to make sure built-in modules like |
| # bazel_tools can work. |
| 'build --registry=https://bcr.bazel.build', |
| 'build --verbose_failures', |
| # Set an explicit Java language version |
| 'build --java_language_version=8', |
| 'build --tool_java_language_version=8', |
| 'build --lockfile_mode=update', |
| ( # fmt: skip pylint: disable=line-too-long |
| 'build' |
| ' --extra_toolchains=@bazel_tools//tools/python:autodetecting_toolchain' |
| ), |
| # TODO(bazel-team): Remove once rules_python exports runtime_env_toolchain_interpreter.sh |
| # See https://github.com/bazel-contrib/rules_python/pull/3471 |
| 'build --noincompatible_no_implicit_file_export', |
| ], |
| ) |
| |
| def tearDown(self): |
| self.main_registry.stop() |
| test_base.TestBase.tearDown(self) |
| |
| def writeMainProjectFiles(self): |
| self.ScratchFile( |
| 'aaa.patch', |
| [ |
| '--- a/aaa.sh', |
| '+++ b/aaa.sh', |
| '@@ -1,5 +1,5 @@', |
| ' function hello_aaa {', |
| ' caller_name="${1}"', |
| '- lib_name="aaa@1.0"', |
| '+ lib_name="aaa@1.0 (locally patched)"', |
| ' echo "${caller_name} => ${lib_name}"', |
| ' }', |
| ], |
| ) |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = [', |
| ' "@aaa//:lib_aaa",', |
| ' "@bbb//:lib_bbb",', |
| ' ],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation aaa/aaa.sh)', |
| 'source $(rlocation bbb/bbb.sh)', |
| 'hello_aaa "main function"', |
| 'hello_bbb "main function"', |
| ], |
| executable=True, |
| ) |
| |
| def testSimple(self): |
| self.ScratchFile('MODULE.bazel', [ |
| 'bazel_dep(name = "aaa", version = "1.0")', |
| ]) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@aaa//:lib_aaa"],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation aaa/aaa.sh)', |
| 'hello_aaa "main function"', |
| ], |
| executable=True, |
| ) |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => aaa@1.0', stdout) |
| |
| def testSimpleTransitive(self): |
| self.ScratchFile('MODULE.bazel', [ |
| 'bazel_dep(name = "bbb", version = "1.0")', |
| ]) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@bbb//:lib_bbb"],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation bbb/bbb.sh)', |
| 'hello_bbb "main function"', |
| ], |
| executable=True, |
| ) |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => bbb@1.0', stdout) |
| self.assertIn('bbb@1.0 => aaa@1.0', stdout) |
| |
| def testSimpleDiamond(self): |
| self.writeMainProjectFiles() |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name = "aaa", version = "1.1")', |
| # bbb@1.0 has to depend on aaa@1.1 after MVS. |
| 'bazel_dep(name = "bbb", version = "1.0")', |
| ]) |
| self.AddBazelDep('rules_shell') |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => aaa@1.1', stdout) |
| self.assertIn('main function => bbb@1.0', stdout) |
| self.assertIn('bbb@1.0 => aaa@1.1', stdout) |
| |
| def testRemotePatchForBazelDep(self): |
| patch_file = self.ScratchFile( |
| 'aaa.patch', |
| [ |
| '--- a/aaa.sh', |
| '+++ b/aaa.sh', |
| '@@ -1,5 +1,5 @@', |
| ' function hello_aaa {', |
| ' caller_name="${1}"', |
| '- lib_name="aaa@1.1-1"', |
| '+ lib_name="aaa@1.1-1 (remotely patched)"', |
| ' echo "${caller_name} => ${lib_name}"', |
| ' }', |
| ], |
| ) |
| self.main_registry.createShModule( |
| 'aaa', '1.1-1', patches=[patch_file], patch_strip=1 |
| ) |
| self.ScratchFile('MODULE.bazel', [ |
| 'bazel_dep(name = "aaa", version = "1.1-1")', |
| ]) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@aaa//:lib_aaa"],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation aaa/aaa.sh)', |
| 'hello_aaa "main function"', |
| ], |
| executable=True, |
| ) |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => aaa@1.1-1 (remotely patched)', stdout) |
| |
| def testArchiveOverrideWithMainRepoLabelPatch(self): |
| self.ScratchFile( |
| 'aaa.patch', |
| [ |
| '--- a/aaa.sh', |
| '+++ b/aaa.sh', |
| '@@ -1,5 +1,5 @@', |
| ' function hello_aaa {', |
| ' caller_name="${1}"', |
| '- lib_name="aaa@lol"', |
| '+ lib_name="aaa@lol (locally patched)"', |
| ' echo "${caller_name} => ${lib_name}"', |
| ' }', |
| ], |
| ) |
| self.main_registry.createShModule('aaa', 'lol') |
| integ = integrity(read(self.main_registry.archives.joinpath('aaa.lol.zip'))) |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'module(repo_name="foo")', |
| 'bazel_dep(name = "aaa")', |
| 'archive_override(', |
| ' module_name="aaa",', |
| ' urls=["%s/archives/aaa.lol.zip"],' % self.main_registry.getURL(), |
| ' integrity="%s",' % integ, |
| ' patches=["@foo//:aaa.patch"],', |
| ' patch_strip=1,', |
| ')', |
| ], |
| ) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@aaa//:lib_aaa"],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation aaa/aaa.sh)', |
| 'hello_aaa "main function"', |
| ], |
| executable=True, |
| ) |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => aaa@lol (locally patched)', stdout) |
| |
| def testArchiveOverrideWithBadLabelPatch(self): |
| self.main_registry.createShModule('aaa', '1') |
| self.main_registry.createShModule('bbb', '1') |
| integ = integrity(read(self.main_registry.archives.joinpath('aaa.1.zip'))) |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'module(repo_name="foo")', |
| 'bazel_dep(name = "aaa")', |
| 'bazel_dep(name = "bbb", version = "1")', |
| 'archive_override(', |
| ' module_name="aaa",', |
| ' urls=["%s/archives/aaa.1.zip"],' % self.main_registry.getURL(), |
| ' integrity="%s",' % integ, |
| ' patches=["@bbb//:aaa.patch"])', |
| ], |
| ) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@aaa//:lib_aaa"],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation aaa/aaa.sh)', |
| 'hello_aaa "main function"', |
| ], |
| executable=True, |
| ) |
| exit_code, _, stderr = self.RunBazel(['run', '//:main'], allow_failure=True) |
| self.AssertNotExitCode(exit_code, 0, stderr) |
| self.assertIn( |
| "Error in archive_override: invalid label in 'patches': only patches in" |
| " the main repository can be applied, not from '@bbb'", |
| '\n'.join(stderr), |
| ) |
| |
| def testRepoNameForBazelDep(self): |
| self.writeMainProjectFiles() |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name = "aaa", version = "1.0", repo_name = "my_repo_a_name")', |
| # bbb should still be able to access aaa as com_foo_aaa |
| 'bazel_dep(name = "bbb", version = "1.0")', |
| ]) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = [', |
| ' "@my_repo_a_name//:lib_aaa",', |
| ' "@bbb//:lib_bbb",', |
| ' ],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => aaa@1.0', stdout) |
| self.assertIn('main function => bbb@1.0', stdout) |
| self.assertIn('bbb@1.0 => aaa@1.0', stdout) |
| |
| def testCheckDirectDependencies(self): |
| self.writeMainProjectFiles() |
| self.ScratchFile('MODULE.bazel', [ |
| 'bazel_dep(name = "aaa", version = "1.0")', |
| 'bazel_dep(name = "bbb", version = "1.0")', |
| 'bazel_dep(name = "ccc", version = "1.1")', |
| ]) |
| self.AddBazelDep('rules_shell') |
| _, stdout, stderr = self.RunBazel( |
| ['run', '//:main', '--check_direct_dependencies=warning'] |
| ) |
| stderr = '\n'.join(stderr) |
| self.assertIn( |
| 'WARNING: For repository \'aaa\', the root module requires module version aaa@1.0, but got aaa@1.1 in the resolved dependency graph.', |
| stderr) |
| self.assertIn( |
| 'WARNING: For repository \'bbb\', the root module requires module version bbb@1.0, but got bbb@1.1 in the resolved dependency graph.', |
| stderr) |
| self.assertIn('main function => aaa@1.1', stdout) |
| self.assertIn('main function => bbb@1.1', stdout) |
| self.assertIn('bbb@1.1 => aaa@1.1', stdout) |
| |
| exit_code, _, stderr = self.RunBazel( |
| ['run', '//:main', '--check_direct_dependencies=error'], |
| allow_failure=True) |
| self.AssertExitCode(exit_code, 48, stderr) |
| stderr = '\n'.join(stderr) |
| self.assertIn( |
| 'ERROR: For repository \'aaa\', the root module requires module version aaa@1.0, but got aaa@1.1 in the resolved dependency graph.', |
| stderr) |
| self.assertIn( |
| 'ERROR: For repository \'bbb\', the root module requires module version bbb@1.0, but got bbb@1.1 in the resolved dependency graph.', |
| stderr) |
| |
| def testRepositoryRuleErrorInModuleExtensionFailsTheBuild(self): |
| self.ScratchFile('MODULE.bazel', [ |
| 'module_ext = use_extension("//pkg:extension.bzl", "module_ext")', |
| 'use_repo(module_ext, "foo")', |
| ]) |
| self.ScratchFile('pkg/BUILD.bazel') |
| self.ScratchFile( |
| 'pkg/rules.bzl', |
| [ |
| 'def impl(ctx):', |
| ' pass', |
| 'repo_rule = repository_rule(implementation = impl)', |
| ], |
| ) |
| self.ScratchFile('pkg/extension.bzl', [ |
| 'load(":rules.bzl", "repo_rule")', |
| 'def _module_ext_impl(ctx):', |
| ' repo_rule(name = "foo", invalid_attr = "value")', |
| 'module_ext = module_extension(implementation = _module_ext_impl)', |
| ]) |
| exit_code, _, stderr = self.RunBazel(['run', '@foo//...'], |
| allow_failure=True) |
| self.AssertExitCode(exit_code, 48, stderr) |
| stderr = '\n'.join(stderr) |
| self.assertIn( |
| "Error: in call to 'repo_rule' repo rule with name 'foo', unknown" |
| " attribute 'invalid_attr' provided", |
| stderr, |
| ) |
| self.assertIn( |
| '/pkg/extension.bzl", line 3, column 14, in _module_ext_impl', |
| stderr, |
| ) |
| |
| def testDownload(self): |
| data_path = self.ScratchFile('data.txt', ['some data']) |
| data_url = pathlib.Path(data_path).resolve().as_uri() |
| self.ScratchFile('MODULE.bazel', [ |
| 'data_ext = use_extension("//:ext.bzl", "data_ext")', |
| 'use_repo(data_ext, "no_op")', |
| ]) |
| self.ScratchFile('BUILD') |
| self.ScratchFile('ext.bzl', [ |
| 'def _no_op_impl(ctx):', |
| ' ctx.file("BUILD", "filegroup(name=\\"no_op\\")")', |
| 'no_op = repository_rule(_no_op_impl)', |
| 'def _data_ext_impl(ctx):', |
| ' if not ctx.download(url="%s", output="data.txt").success:' % |
| data_url, |
| ' fail("download failed")', |
| ' if ctx.read("data.txt").strip() != "some data":', |
| ' fail("unexpected downloaded content: %s" % ctx.read("data.txt").strip())', |
| ' no_op(name="no_op")', |
| 'data_ext = module_extension(_data_ext_impl)', |
| ]) |
| self.RunBazel(['build', '@no_op//:no_op']) |
| |
| def testNoRestart(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'data_ext = use_extension("//:ext.bzl", "data_ext")', |
| 'use_repo(data_ext, "no_op")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile('foo.txt', ['abc']) |
| self.ScratchFile( |
| 'ext.bzl', |
| [ |
| 'def _no_op_impl(ctx):', |
| ' ctx.file("BUILD", "filegroup(name=\\"no_op\\")")', |
| 'no_op = repository_rule(_no_op_impl)', |
| 'def _data_ext_impl(ctx):', |
| ' print("I AM HERE")', |
| ' ctx.watch(Label("//:foo.txt"))', |
| ' no_op(name="no_op")', |
| 'data_ext = module_extension(_data_ext_impl)', |
| ], |
| ) |
| _, _, stderr = self.RunBazel(['build', '@no_op//:no_op']) |
| stderr = '\n'.join(stderr) |
| self.assertIn('I AM HERE', stderr) |
| self.assertEqual( |
| stderr.count('I AM HERE'), |
| 1, |
| 'expected "I AM HERE" once, but got %s times:\n%s' |
| % (stderr.count('I AM HERE'), stderr), |
| ) |
| |
| def setUpProjectWithLocalRegistryModule(self, dep_name, dep_version): |
| self.main_registry.generateShSource(dep_name, dep_version) |
| self.main_registry.createLocalPathModule(dep_name, dep_version, |
| dep_name + '/' + dep_version) |
| self.writeShProjectFiles(dep_name, dep_version) |
| |
| def writeShProjectFiles(self, dep_name, dep_version): |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation %s/%s.sh)' % (dep_name, dep_name), |
| 'hello_%s "main function"' % dep_name, |
| ], |
| executable=True, |
| ) |
| self.ScratchFile('MODULE.bazel', [ |
| 'bazel_dep(name = "%s", version = "%s")' % (dep_name, dep_version), |
| ]) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@%s//:lib_%s"],' % (dep_name, dep_name), |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| |
| def setUpProjectWithGitRegistryModule(self, dep_name, dep_version): |
| src_dir = self.main_registry.generateShSource(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.writeShProjectFiles(dep_name, dep_version) |
| |
| def testLocalRepoInSourceJsonAbsoluteBasePath(self): |
| self.main_registry.setModuleBasePath(str(self.main_registry.projects)) |
| self.setUpProjectWithLocalRegistryModule('sss', '1.3') |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => sss@1.3', stdout) |
| |
| def testLocalRepoInSourceJsonRelativeBasePath(self): |
| self.main_registry.setModuleBasePath('projects') |
| self.setUpProjectWithLocalRegistryModule('sss', '1.3') |
| _, 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', |
| [ |
| 'module(name="foo")', |
| 'bazel_dep(name="bar")', |
| 'local_path_override(module_name="bar",path="bar")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'defs.bzl', |
| [ |
| 'def mac(name):', |
| ' native.filegroup(name=name)', |
| ' print("1st: " + str(native.package_relative_label(":bleb")))', |
| ' print("2nd: " + str(native.package_relative_label(' |
| + '"//bleb:bleb")))', |
| ' print("3rd: " + str(native.package_relative_label(' |
| + '"@bleb//bleb:bleb")))', |
| ' print("4th: " + str(native.package_relative_label("//bleb")))', |
| ' print("5th: " + str(native.package_relative_label(' |
| + '"@@bleb//bleb:bleb")))', |
| ' print("6th: " + str(native.package_relative_label(Label(' |
| + '"//bleb"))))', |
| ], |
| ) |
| |
| self.ScratchFile( |
| 'bar/MODULE.bazel', |
| [ |
| 'module(name="bar")', |
| 'bazel_dep(name="foo", repo_name="bleb")', |
| ], |
| ) |
| self.ScratchFile( |
| 'bar/quux/BUILD', |
| [ |
| 'load("@bleb//:defs.bzl", "mac")', |
| 'mac(name="book")', |
| ], |
| ) |
| |
| _, _, stderr = self.RunBazel(['build', '@bar//quux:book']) |
| stderr = '\n'.join(stderr) |
| self.assertIn('1st: @@bar+//quux:bleb', stderr) |
| self.assertIn('2nd: @@bar+//bleb:bleb', stderr) |
| self.assertIn('3rd: @@//bleb:bleb', stderr) |
| self.assertIn('4th: @@bar+//bleb:bleb', stderr) |
| self.assertIn('5th: @@bleb//bleb:bleb', stderr) |
| self.assertIn('6th: @@//bleb:bleb', stderr) |
| |
| def testCtxPackageRelativeLabel(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'module(name="foo")', |
| 'bazel_dep(name="bar")', |
| 'local_path_override(module_name="bar",path="bar")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'defs.bzl', |
| [ |
| 'def _my_rule_impl(ctx):', |
| ' print("1st: " + str(ctx.package_relative_label(":bleb")))', |
| ' print("2nd: " + str(ctx.package_relative_label(' |
| + '"//bleb:bleb")))', |
| ' print("3rd: " + str(ctx.package_relative_label(' |
| + '"@bleb//bleb:bleb")))', |
| ' print("4th: " + str(ctx.package_relative_label("//bleb")))', |
| ' print("5th: " + str(ctx.package_relative_label(' |
| + '"@@bleb//bleb:bleb")))', |
| ' print("6th: " + str(ctx.package_relative_label(Label(' |
| + '"//bleb"))))', |
| 'my_rule = rule(_my_rule_impl)', |
| ], |
| ) |
| |
| self.ScratchFile( |
| 'bar/MODULE.bazel', |
| [ |
| 'module(name="bar")', |
| 'bazel_dep(name="foo", repo_name="bleb")', |
| ], |
| ) |
| self.ScratchFile( |
| 'bar/quux/BUILD', |
| [ |
| 'load("@bleb//:defs.bzl", "my_rule")', |
| 'my_rule(name="book")', |
| ], |
| ) |
| |
| _, _, stderr = self.RunBazel(['build', '@bar//quux:book']) |
| stderr = '\n'.join(stderr) |
| self.assertIn('1st: @@bar+//quux:bleb', stderr) |
| self.assertIn('2nd: @@bar+//bleb:bleb', stderr) |
| self.assertIn('3rd: @@//bleb:bleb', stderr) |
| self.assertIn('4th: @@bar+//bleb:bleb', stderr) |
| self.assertIn('5th: @@bleb//bleb:bleb', stderr) |
| self.assertIn('6th: @@//bleb:bleb', stderr) |
| |
| def testArchiveWithArchiveType(self): |
| # make the archive without the .zip extension |
| self.main_registry.createShModule( |
| 'aaa', '1.2', archive_pattern='%s.%s', archive_type='zip' |
| ) |
| |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name = "aaa", version = "1.2")', |
| ], |
| ) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@aaa//:lib_aaa"],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation aaa/aaa.sh)', |
| 'hello_aaa "main function"', |
| ], |
| executable=True, |
| ) |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => aaa@1.2', stdout) |
| |
| def testNativeModuleNameAndVersion(self): |
| self.main_registry.setModuleBasePath('projects') |
| projects_dir = self.main_registry.projects |
| |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'module(name="root",version="0.1")', |
| 'bazel_dep(name="foo",version="1.0")', |
| 'report_ext = use_extension("@foo//:ext.bzl", "report_ext")', |
| 'use_repo(report_ext, "report_repo")', |
| 'bazel_dep(name="bar")', |
| 'local_path_override(module_name="bar",path="bar")', |
| ], |
| ) |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@foo//:report.bzl", "report")', |
| 'report()', |
| ], |
| ) |
| # foo: a repo defined by a normal Bazel module. Also hosts the extension |
| # `report_ext` which generates a repo `report_repo`. |
| self.main_registry.createLocalPathModule('foo', '1.0', 'foo') |
| projects_dir.joinpath('foo').mkdir(exist_ok=True) |
| scratchFile( |
| projects_dir.joinpath('foo', 'BUILD'), |
| [ |
| 'load(":report.bzl", "report")', |
| 'report()', |
| ], |
| ) |
| scratchFile( |
| projects_dir.joinpath('foo', 'report.bzl'), |
| [ |
| 'def report():', |
| ' repo = native.repository_name()', |
| ' name = str(native.module_name())', |
| ' version = str(native.module_version())', |
| ' print("@" + repo + " reporting in: " + name + "@" + version)', |
| ' native.filegroup(name="a")', |
| ], |
| ) |
| scratchFile( |
| projects_dir.joinpath('foo', 'ext.bzl'), |
| [ |
| 'def _report_repo(rctx):', |
| ' rctx.file("BUILD",', |
| ' "load(\\"@foo//:report.bzl\\", \\"report\\")\\n" +', |
| ' "report()")', |
| 'report_repo = repository_rule(_report_repo)', |
| 'report_ext = module_extension(', |
| ' lambda mctx: report_repo(name="report_repo"))', |
| ], |
| ) |
| # bar: a repo defined by a Bazel module with a non-registry override |
| self.ScratchFile( |
| 'bar/MODULE.bazel', |
| [ |
| 'module(name="bar", version="2.0")', |
| 'bazel_dep(name="foo",version="1.0")', |
| ], |
| ) |
| self.ScratchFile( |
| 'bar/BUILD', |
| [ |
| 'load("@foo//:report.bzl", "report")', |
| 'report()', |
| ], |
| ) |
| |
| _, _, stderr = self.RunBazel( |
| [ |
| 'build', |
| ':a', |
| '@foo//:a', |
| '@report_repo//:a', |
| '@bar//:a', |
| ], |
| ) |
| stderr = '\n'.join(stderr) |
| self.assertIn('@@ reporting in: root@0.1', stderr) |
| self.assertIn('@@foo+ reporting in: foo@1.0', stderr) |
| self.assertIn('@@foo++report_ext+report_repo reporting in: foo@1.0', stderr) |
| self.assertIn('@@bar+ reporting in: bar@2.0', stderr) |
| |
| def testModuleExtensionWithRuleError(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'ext = use_extension("extensions.bzl", "ext")', |
| 'use_repo(ext, "ext")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'extensions.bzl', |
| [ |
| 'def _rule_impl(ctx):', |
| ' print("RULE CALLED")', |
| 'init_rule = rule(_rule_impl)', |
| 'def ext_impl(module_ctx):', |
| ' init_rule()', |
| 'ext = module_extension(implementation = ext_impl,)', |
| ], |
| ) |
| exit_code, _, stderr = self.RunBazel( |
| ['build', '--nobuild', '@ext//:all'], |
| allow_failure=True, |
| ) |
| self.AssertExitCode(exit_code, 48, stderr) |
| self.assertIn( |
| 'Error in init_rule: a rule can only be instantiated while evaluating a' |
| ' BUILD file or a legacy or symbolic macro', |
| stderr, |
| ) |
| |
| def testLocationRoot(self): |
| """Tests that the reported location of the MODULE.bazel file of the root module is as expected.""" |
| self.ScratchFile('MODULE.bazel', ['wat']) |
| _, _, stderr = self.RunBazel(['build', '@what'], allow_failure=True) |
| self.assertIn( |
| 'ERROR: ' + self.Path('MODULE.bazel').replace('\\', '/'), |
| '\n'.join(stderr).replace('\\', '/'), |
| ) |
| |
| def testLocationRegistry(self): |
| """Tests that the reported location of the MODULE.bazel file of a module from a registry is as expected.""" |
| self.ScratchFile('MODULE.bazel', ['bazel_dep(name="hello",version="1.0")']) |
| self.main_registry.createShModule( |
| 'hello', '1.0', extra_module_file_contents=['wat'] |
| ) |
| _, _, stderr = self.RunBazel(['build', '@what'], allow_failure=True) |
| self.assertIn( |
| 'ERROR: ' |
| + self.main_registry.getURL() |
| + '/modules/hello/1.0/MODULE.bazel', |
| '\n'.join(stderr), |
| ) |
| |
| def testLocationNonRegistry(self): |
| """Tests that the reported location of the MODULE.bazel file of a module with a non-registry override is as expected.""" |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name="hello")', |
| 'local_path_override(module_name="hello",path="hello")', |
| ], |
| ) |
| self.ScratchFile('hello/MODULE.bazel', ['wat']) |
| _, _, stderr = self.RunBazel(['build', '@what'], allow_failure=True) |
| self.assertIn('ERROR: @@hello+//:MODULE.bazel', '\n'.join(stderr)) |
| |
| def testLoadRulesJavaSymbolThroughBazelTools(self): |
| """Tests that loads from @bazel_tools that delegate to other modules resolve.""" |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'ext = use_extension("//:ext.bzl", "ext")', |
| 'use_repo(ext, "data")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'ext.bzl', |
| [ |
| ( |
| "load('@bazel_tools//tools/jdk:toolchain_utils.bzl'," |
| " 'find_java_toolchain')" |
| ), |
| 'def _repo_impl(ctx):', |
| " ctx.file('BUILD', 'exports_files([\"data.txt\"])')", |
| " ctx.file('data.txt', 'hi')", |
| 'repo = repository_rule(implementation = _repo_impl)', |
| 'def _ext_impl(ctx):', |
| " repo(name='data')", |
| 'ext = module_extension(implementation = _ext_impl)', |
| ], |
| ) |
| |
| self.RunBazel(['build', '@data//:data.txt']) |
| |
| def testHttpJar(self): |
| """Tests that using http_jar works with a bazel_dep on rules_java.""" |
| |
| my_jar_path = self.ScratchFile('my_jar.jar') |
| my_jar_uri = pathlib.Path(my_jar_path).as_uri() |
| |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| ( |
| 'http_jar =' |
| ' use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl",' |
| ' "http_jar")' |
| ), |
| 'http_jar(', |
| ' name = "my_jar",', |
| ' url = "%s",' % my_jar_uri, |
| ( |
| ' sha256 =' |
| ' "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",' |
| ), |
| ')', |
| ], |
| ) |
| self.AddBazelDep('rules_java') |
| |
| self.RunBazel(['build', '@my_jar//jar']) |
| |
| def testInclude(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'module(name="foo")', |
| 'bazel_dep(name="bbb", version="1.0")', |
| 'include("//java:java.MODULE.bazel")', |
| ], |
| ) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile('java/BUILD') |
| self.ScratchFile( |
| 'java/java.MODULE.bazel', |
| [ |
| 'bazel_dep(name="aaa", version="1.0", repo_name="lol")', |
| ], |
| ) |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@lol//:lib_aaa"],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation aaa+/aaa.sh)', |
| 'hello_aaa "main function"', |
| ], |
| executable=True, |
| ) |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => aaa@1.0', stdout) |
| |
| def testNonRegistryOverrideModuleInclude(self): |
| """Tests that include() works in non-root modules with a non-registry override.""" |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'module(name="aaa", version="0.1")', |
| 'bazel_dep(name="bbb", version="1.0")', |
| 'local_path_override(module_name="bbb", path="code_for_b")', |
| ], |
| ) |
| self.AddBazelDep('rules_shell') |
| self.ScratchFile( |
| 'code_for_b/MODULE.bazel', |
| [ |
| 'module(name="bbb", version="1.0")', |
| 'include("//subdir:bbb.MODULE.bazel")', |
| ], |
| ) |
| self.AddBazelDep('rules_shell', path='code_for_b') |
| self.ScratchFile('code_for_b/subdir/BUILD') |
| self.ScratchFile( |
| 'code_for_b/subdir/bbb.MODULE.bazel', |
| [ |
| 'include("//subdir/nested:ccc.MODULE.bazel")', |
| ], |
| ) |
| self.ScratchFile('code_for_b/subdir/nested/BUILD') |
| self.ScratchFile( |
| 'code_for_b/subdir/nested/ccc.MODULE.bazel', |
| [ |
| 'bazel_dep(name="ccc", version="2.0")', |
| ], |
| ) |
| self.ScratchFile( |
| 'code_for_b/BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_library.bzl", "sh_library")', |
| 'sh_library(', |
| ' name = "lib_bbb",', |
| ' srcs = ["bbb.sh"],', |
| ' deps = ["@ccc//:lib_ccc"],', |
| ' visibility = ["//visibility:public"],', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'code_for_b/bbb.sh', |
| [ |
| 'source $(rlocation ccc+/ccc.sh)', |
| 'function hello_bbb {', |
| ' caller_name="${1}"', |
| ' lib_name="bbb@1.0"', |
| ' echo "${caller_name} => ${lib_name}"', |
| ' hello_ccc ${lib_name}', |
| '}', |
| ], |
| executable=True, |
| ) |
| self.main_registry.createShModule('ccc', '2.0', {'ddd': '3.0'}) |
| self.main_registry.createShModule('ddd', '3.0') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_shell//shell:sh_binary.bzl", "sh_binary")', |
| 'sh_binary(', |
| ' name = "main",', |
| ' srcs = ["main.sh"],', |
| ' deps = ["@bbb//:lib_bbb"],', |
| ' use_bash_launcher = True,', |
| ')', |
| ], |
| ) |
| self.ScratchFile( |
| 'main.sh', |
| [ |
| 'source $(rlocation bbb+/bbb.sh)', |
| 'hello_bbb "main function"', |
| ], |
| executable=True, |
| ) |
| _, stdout, _ = self.RunBazel(['run', '//:main']) |
| self.assertIn('main function => bbb@1.0', stdout) |
| self.assertIn('bbb@1.0 => ccc@2.0', stdout) |
| self.assertIn('ccc@2.0 => ddd@3.0', stdout) |
| |
| def testRegistryModuleInclude(self): |
| """Tests that include() is not allowed in registry modules.""" |
| self.main_registry.createShModule( |
| 'foo', |
| '1.0', |
| extra_module_file_contents=['include("//java:MODULE.bazel.segment")'], |
| ) |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name="foo", version="1.0")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| exit_code, _, stderr = self.RunBazel( |
| ['build', '--nobuild', '//:all'], allow_failure=True |
| ) |
| self.AssertNotExitCode(exit_code, 0, stderr) |
| self.assertIn( |
| 'include() directive found at ' |
| + self.main_registry.getURL() |
| + '/modules/foo/1.0/MODULE.bazel:5:1, but it can only be used in the ' |
| + 'root module or in modules with non-registry overrides', |
| '\n'.join(stderr), |
| ) |
| |
| def testLabelDebugPrint(self): |
| """Tests that print emits labels in display form.""" |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name="other_module", version="1.0")', |
| ( |
| 'local_path_override(module_name="other_module",' |
| ' path="other_module")' |
| ), |
| 'ext = use_extension("//:defs.bzl", "my_ext")', |
| 'use_repo(ext, "repo")', |
| ], |
| ) |
| |
| self.ScratchFile( |
| 'other_module/MODULE.bazel', |
| ['module(name="other_module", version="1.0")'], |
| ) |
| |
| self.ScratchFile( |
| 'defs.bzl', |
| [ |
| ( |
| 'print("toplevel", Label("//:foo"),' |
| ' Label("@other_module//:bar"),' |
| ' Label("@@canonical_name//:baz"))' |
| ), |
| 'def _repo_impl(ctx):', |
| ( |
| ' print("repo", Label("//:foo"), Label("@other_module//:bar"),' |
| ' Label("@@canonical_name//:baz"))' |
| ), |
| ' ctx.file("BUILD")', |
| ' ctx.file("data.bzl", "repo_data = \\"repo\\"")', |
| 'my_repo = repository_rule(implementation=_repo_impl)', |
| 'def _ext_impl(ctx):', |
| ( |
| ' print("ext", Label("//:foo"), Label("@other_module//:bar"),' |
| ' Label("@@canonical_name//:baz"))' |
| ), |
| ' my_repo(name = "repo")', |
| 'my_ext = module_extension(implementation=_ext_impl)', |
| 'def _rule_impl(ctx):', |
| ( |
| ' print("rule", Label("//:foo"), Label("@other_module//:bar"),' |
| ' Label("@@canonical_name//:baz"))' |
| ), |
| 'my_rule = rule(implementation=_rule_impl)', |
| ], |
| ) |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@repo//:data.bzl", "repo_data")', |
| 'load(":defs.bzl", "my_rule")', |
| 'my_rule(name = "my_rule")', |
| ], |
| ) |
| |
| _, _, stderr = self.RunBazel(['build', '//:my_rule']) |
| stderr = '\n'.join(stderr) |
| self.assertIn( |
| 'toplevel //:foo @other_module//:bar @@canonical_name//:baz', stderr |
| ) |
| self.assertIn( |
| 'repo //:foo @other_module//:bar @@canonical_name//:baz', stderr |
| ) |
| self.assertIn( |
| 'ext //:foo @other_module//:bar @@canonical_name//:baz', stderr |
| ) |
| self.assertIn( |
| 'rule //:foo @other_module//:bar @@canonical_name//:baz', stderr |
| ) |
| |
| def testPendingDownloadDetected(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'ext = use_extension("extensions.bzl", "ext")', |
| 'use_repo(ext, "ext")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'extensions.bzl', |
| [ |
| 'repo_rule = repository_rule(lambda _: None)', |
| 'def ext_impl(module_ctx):', |
| ' repo_rule(name = "ext")', |
| ( |
| ' module_ctx.download(url = "https://bcr.bazel.build", output' |
| ' = "download", block = False)' |
| ), |
| 'ext = module_extension(implementation = ext_impl)', |
| ], |
| ) |
| exit_code, _, stderr = self.RunBazel( |
| ['build', '--nobuild', '@ext//:all'], |
| allow_failure=True, |
| ) |
| self.AssertExitCode(exit_code, 48, stderr) |
| self.assertIn( |
| 'ERROR: Pending asynchronous work after module extension' |
| ' @@//:extensions.bzl%ext finished execution', |
| stderr, |
| ) |
| |
| def testRegression22754(self): |
| """Regression test for issue #22754.""" |
| self.ScratchFile('BUILD.bazel', ['print(glob(["testdata/**"]))']) |
| self.ScratchFile('testdata/WORKSPACE') |
| self.RunBazel(['build', ':all']) |
| |
| def testUnicodePaths(self): |
| if sys.getfilesystemencoding() != 'utf-8': |
| self.skipTest('Test requires UTF-8 by default (Python 3.7+)') |
| |
| unicode_dir = 'äöüÄÖÜß' |
| self.ScratchFile(unicode_dir + '/MODULE.bazel', ['module(name = "module")']) |
| self.ScratchFile( |
| unicode_dir + '/BUILD', |
| [ |
| 'filegroup(name = "choose_me")', |
| ], |
| ) |
| self.writeMainProjectFiles() |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name = "module")', |
| 'local_path_override(', |
| ' module_name = "module",', |
| ' path = "%s",' % unicode_dir, |
| ')', |
| ], |
| ) |
| self.AddBazelDep('rules_shell') |
| self.RunBazel(['build', '@module//:choose_me']) |
| |
| def testUnicodeTags(self): |
| unicode_str = 'äöüÄÖÜß' |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'ext = use_extension("extensions.bzl", "ext")', |
| 'ext.tag(attr = "%s")' % unicode_str, |
| 'use_repo(ext, "ext")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'extensions.bzl', |
| [ |
| 'def repo_rule_impl(ctx):', |
| ' ctx.file("BUILD")', |
| ' print("DATA: " + ctx.attr.tag)', |
| 'repo_rule = repository_rule(', |
| ' implementation = repo_rule_impl,', |
| ' attrs = {', |
| ' "tag": attr.string(),', |
| ' },', |
| ')', |
| 'def ext_impl(module_ctx):', |
| ' repo_rule(', |
| ' name = "ext",', |
| ' tag = module_ctx.modules[0].tags.tag[0].attr,', |
| ' )', |
| 'tag = tag_class(', |
| ' attrs = {', |
| ' "attr": attr.string(),', |
| ' },', |
| ')', |
| 'ext = module_extension( implementation = ext_impl,', |
| ' tag_classes = {', |
| ' "tag": tag,', |
| ' },', |
| ')', |
| ], |
| ) |
| _, _, stderr = self.RunBazel(['build', '@ext//:all']) |
| self.assertIn('DATA: ' + unicode_str, '\n'.join(stderr)) |
| |
| def testDefaultModuleMirrors(self): |
| """Tests that default module mirrors are applied to all registries.""" |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name = "aaa", version = "1.0")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| _, stdout, _ = self.RunBazel([ |
| 'mod', |
| 'show_repo', |
| '@@aaa+', |
| '--registry=' + self.main_registry.getURL(), |
| '--registry=https://bcr.bazel.build', |
| '--module_mirrors=https://default-mirror1.example.com,https://default-mirror2.example.com', |
| ]) |
| stdout = '\n'.join(stdout) |
| self.assertIn('https://default-mirror1.example.com', stdout) |
| self.assertIn('https://default-mirror2.example.com', stdout) |
| |
| def testPerRegistryModuleMirrors(self): |
| """Tests that per-registry module mirrors are applied only to the specified registry.""" |
| second_registry = BazelRegistry( |
| os.path.join(self.registries_work_dir, 'second') |
| ) |
| second_registry.start() |
| second_registry.createShModule('ddd', '2.0') |
| |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name = "aaa", version = "1.0")', |
| 'bazel_dep(name = "ddd", version = "2.0")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| |
| _, stdout, _ = self.RunBazel([ |
| 'mod', |
| 'show_repo', |
| '@@aaa+', |
| '--registry=' + self.main_registry.getURL(), |
| '--registry=' + second_registry.getURL(), |
| '--registry=https://bcr.bazel.build', |
| '--module_mirrors=%s=https://main-mirror.example.com' |
| % self.main_registry.getURL(), |
| '--module_mirrors=%s=https://second-mirror.example.com' |
| % second_registry.getURL(), |
| ]) |
| stdout = '\n'.join(stdout) |
| self.assertIn('https://main-mirror.example.com', stdout) |
| self.assertNotIn('https://second-mirror.example.com', stdout) |
| |
| second_registry.stop() |
| |
| def testPerRegistryModuleMirrorsWithDefault(self): |
| """Tests that per-registry mirrors override default mirrors for that registry.""" |
| second_registry = BazelRegistry( |
| os.path.join(self.registries_work_dir, 'second') |
| ) |
| second_registry.start() |
| second_registry.createShModule('ddd', '2.0') |
| |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name = "aaa", version = "1.0")', |
| 'bazel_dep(name = "ddd", version = "2.0")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| |
| _, stdout_aaa, _ = self.RunBazel([ |
| 'mod', |
| 'show_repo', |
| '@@aaa+', |
| '--registry=' + self.main_registry.getURL(), |
| '--registry=' + second_registry.getURL(), |
| '--registry=https://bcr.bazel.build', |
| '--module_mirrors=https://default-mirror.example.com', |
| '--module_mirrors=%s=https://main-specific-mirror.example.com' |
| % self.main_registry.getURL(), |
| ]) |
| stdout_aaa = '\n'.join(stdout_aaa) |
| self.assertIn('https://main-specific-mirror.example.com', stdout_aaa) |
| self.assertNotIn('https://default-mirror.example.com', stdout_aaa) |
| |
| _, stdout_ddd, _ = self.RunBazel([ |
| 'mod', |
| 'show_repo', |
| '@@ddd+', |
| '--registry=' + self.main_registry.getURL(), |
| '--registry=' + second_registry.getURL(), |
| '--registry=https://bcr.bazel.build', |
| '--module_mirrors=https://default-mirror.example.com', |
| '--module_mirrors=%s=https://main-specific-mirror.example.com' |
| % self.main_registry.getURL(), |
| ]) |
| stdout_ddd = '\n'.join(stdout_ddd) |
| self.assertIn('https://default-mirror.example.com', stdout_ddd) |
| self.assertNotIn('https://main-specific-mirror.example.com', stdout_ddd) |
| |
| second_registry.stop() |
| |
| def testUnknownRegistryInModuleMirrors(self): |
| """Tests that specifying an unknown registry in module_mirrors results in an error.""" |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'bazel_dep(name = "aaa", version = "1.0")', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| |
| exit_code, _, stderr = self.RunBazel( |
| [ |
| 'mod', |
| 'show_repo', |
| '@@aaa+', |
| '--registry=' + self.main_registry.getURL(), |
| '--registry=https://bcr.bazel.build', |
| '--module_mirrors=https://unknown-registry.example.com=https://mirror.example.com', |
| ], |
| allow_failure=True, |
| ) |
| self.AssertNotExitCode(exit_code, 0, stderr) |
| stderr = '\n'.join(stderr) |
| self.assertIn( |
| '--module_mirrors references registries not listed in --registries', |
| stderr, |
| ) |
| self.assertIn('https://unknown-registry.example.com', stderr) |
| |
| def testInvalidRepoRuleReferencedByTargetDoesNotCrash(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'repo = use_repo_rule("//:repo.bzl", "repo")', |
| 'repo(name = "my_repo")', |
| ], |
| ) |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'genrule(', |
| ' name = "gen",', |
| ' srcs = ["@my_repo//:a.txt"],', |
| ' outs = ["out.txt"],', |
| ' cmd = "cat $(SRCS) > $(OUTS)",', |
| ')', |
| ], |
| ) |
| self.ScratchFile('repo.bzl', ['nonsense']) |
| |
| exit_code, _, stderr = self.RunBazel( |
| ['build', '//:gen'], |
| allow_failure=True, |
| ) |
| self.AssertNotExitCode(exit_code, 0, stderr) |
| stderr = '\n'.join(stderr) |
| self.assertNotIn('FATAL', stderr) |
| self.assertIn("compilation of module 'repo.bzl' failed", stderr) |
| |
| def testReverseDependencyDirection(self): |
| # Set up two module extensions that retain their predeclared input hashes |
| # across two builds but still reverse their dependency direction. Depending |
| # on how repo cache candidates are checked, this could lead to a Skyframe |
| # cycle. |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'foo_ext = use_extension("//:repo.bzl", "foo_ext")', |
| 'use_repo(foo_ext, "foo")', |
| 'bar_ext = use_extension("//:repo.bzl", "bar_ext")', |
| 'use_repo(bar_ext, "bar")', |
| ], |
| ) |
| self.ScratchFile('BUILD.bazel') |
| self.ScratchFile( |
| 'repo.bzl', |
| [ |
| 'def _repo_impl(rctx):', |
| ' rctx.file("output.txt", rctx.attr.content)', |
| ' rctx.file("BUILD", "exports_files([\'output.txt\'])")', |
| ' print("JUST FETCHED: %s" % rctx.original_name)', |
| ' return rctx.repo_metadata(reproducible=True)', |
| 'repo = repository_rule(', |
| ' implementation = _repo_impl,', |
| ' attrs = {"content": attr.string()},', |
| ')', |
| 'def _foo_ext_impl(mctx):', |
| ' deps = mctx.read(Label("@//:foo_deps.txt")).splitlines()', |
| ' content = "foo"', |
| ' for dep in deps:', |
| ' if dep:', |
| ' content += " + " + mctx.read(Label(dep))', |
| ' repo(name = "foo", content = content)', |
| 'foo_ext = module_extension(implementation = _foo_ext_impl)', |
| 'def _bar_ext_impl(mctx):', |
| ' deps = mctx.read(Label("@//:bar_deps.txt")).splitlines()', |
| ' content = "bar"', |
| ' for dep in deps:', |
| ' if dep:', |
| ' content += " + " + mctx.read(Label(dep))', |
| ' repo(name = "bar", content = content)', |
| 'bar_ext = module_extension(implementation = _bar_ext_impl)', |
| ], |
| ) |
| |
| self.ScratchFile('foo_deps.txt', ['@bar//:output.txt']) |
| self.ScratchFile('bar_deps.txt') |
| |
| # First fetch: not cached |
| _, _, stderr = self.RunBazel(['build', '@foo//:output.txt']) |
| self.assertIn('JUST FETCHED: bar', '\n'.join(stderr)) |
| self.assertIn('JUST FETCHED: foo', '\n'.join(stderr)) |
| |
| # After expunging and reversing: cached |
| self.RunBazel(['clean', '--expunge']) |
| self.ScratchFile('foo_deps.txt') |
| self.ScratchFile('bar_deps.txt', ['@foo//:output.txt']) |
| self.RunBazel(['build', '@foo//:output.txt']) |
| |
| |
| if __name__ == '__main__': |
| absltest.main() |