| # pylint: disable=g-bad-file-header |
| # Copyright 2017 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. |
| |
| import http.server |
| import os |
| import socketserver |
| import threading |
| from absl.testing import absltest |
| from src.test.py.bazel import test_base |
| |
| |
| class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): |
| """A helper class to launcher a threaded http server.""" |
| pass |
| |
| |
| class BazelExternalRepositoryTest(test_base.TestBase): |
| |
| _http_server = None |
| |
| def StartHttpServer(self): |
| """Runs a simple http server to serve files under current directory.""" |
| # Port 0 means to select an arbitrary unused port |
| host, port = 'localhost', 0 |
| http_handler = http.server.SimpleHTTPRequestHandler |
| server = ThreadedTCPServer((host, port), http_handler) |
| server_thread = threading.Thread(target=server.serve_forever) |
| server_thread.daemon = True |
| server_thread.start() |
| self._http_server = server |
| |
| def StopHttpServer(self): |
| """Shutdown and clean up the http server.""" |
| if self._http_server: |
| self._http_server.shutdown() |
| self._http_server.server_close() |
| |
| def setUp(self): |
| test_base.TestBase.setUp(self) |
| for f in [ |
| 'hello-1.0.0.tar.gz', |
| 'archive_with_symlink.zip', |
| 'archive_with_symlink.tar.gz', |
| 'sparse_archive.tar', |
| ]: |
| self.CopyFile(self.Rlocation('io_bazel/src/test/py/bazel/testdata/' |
| 'bazel_external_repository_test/' + f), f) |
| self.StartHttpServer() |
| |
| def tearDown(self): |
| test_base.TestBase.tearDown(self) |
| self.StopHttpServer() |
| |
| def testNewHttpArchive(self): |
| ip, port = self._http_server.server_address |
| rule_definition = [ |
| 'bazel_dep(name = "rules_python", version = "0.40.0")', |
| 'http_archive = use_repo_rule(', |
| ' "@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")', |
| 'http_archive(', |
| ' name = "hello_archive",', |
| ' urls = ["http://%s:%s/hello-1.0.0.tar.gz"],' % (ip, port), |
| ' sha256 = ', |
| ' "154740b327bcfee5669ef2ce0a04bf0904227a3bfe0fee08a5aaca96ea5a601a",', |
| ' strip_prefix = "hello-1.0.0",', |
| ' build_file = "@//third_party:hello.BUILD",', |
| ')', |
| ] |
| build_file = [ |
| 'load("@rules_python//python:py_library.bzl", "py_library")', |
| 'py_library(', |
| ' name = "hello",', |
| ' srcs = ["hello.py"],', |
| ')', |
| ] |
| self.ScratchFile('MODULE.bazel', rule_definition) |
| self.ScratchFile('BUILD') |
| self.ScratchFile('third_party/BUILD') |
| self.ScratchFile('third_party/hello.BUILD', build_file) |
| |
| self.RunBazel(['build', '@hello_archive//...']) |
| |
| fetching_disabled_msg = 'fetching is disabled' |
| |
| # Changing the mtime of the BUILD file shouldn't invalidate it. |
| os.utime(self.Path('third_party/hello.BUILD'), (100, 200)) |
| _, _, stderr = self.RunBazel(['build', '--nofetch', '@hello_archive//...']) |
| self.assertNotIn(fetching_disabled_msg, os.linesep.join(stderr)) |
| |
| # Check that --nofetch prints a warning if the BUILD file is changed. |
| self.ScratchFile( |
| 'third_party/hello.BUILD', build_file + ['"a noop string"'] |
| ) |
| _, _, stderr = self.RunBazel(['build', '--nofetch', '@hello_archive//...']) |
| self.assertIn(fetching_disabled_msg, os.linesep.join(stderr)) |
| |
| # Test repository reloading after BUILD file changes. |
| self.ScratchFile('third_party/hello.BUILD', build_file + ['foobar']) |
| exit_code, _, stderr = self.RunBazel( |
| ['build', '@hello_archive//...'], allow_failure=True |
| ) |
| self.assertEqual(exit_code, 1, os.linesep.join(stderr)) |
| self.assertIn('name \'foobar\' is not defined', os.linesep.join(stderr)) |
| |
| def testNewHttpZipArchiveWithSymlinks(self): |
| ip, port = self._http_server.server_address |
| rule_definition = [ |
| ( |
| 'http_archive =' |
| ' use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl",' |
| ' "http_archive")' |
| ), |
| 'http_archive(', |
| ' name = "archive_with_symlink",', |
| ' urls = ["http://%s:%s/archive_with_symlink.zip"],' % (ip, port), |
| ' build_file = "@//:archive_with_symlink.BUILD",', |
| ' sha256 = ', |
| ( |
| ' "c9c32a48ff65f6319885246b1bfc704e60dd72fb0405dfafdffe403421a4c83a",' |
| ')' |
| ), |
| ] |
| self.ScratchFile('MODULE.bazel', rule_definition) |
| # In the archive, A is a symlink pointing to B |
| self.ScratchFile('archive_with_symlink.BUILD', [ |
| 'filegroup(', |
| ' name = "file-A",', |
| ' srcs = ["A"],', |
| ')', |
| ]) |
| self.ScratchFile('BUILD') |
| self.RunBazel([ |
| 'build', |
| '@archive_with_symlink//:file-A', |
| ]) |
| |
| def testNewHttpTarArchiveWithSymlinks(self): |
| ip, port = self._http_server.server_address |
| rule_definition = [ |
| ( |
| 'http_archive =' |
| ' use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl",' |
| ' "http_archive")' |
| ), |
| 'http_archive(', |
| ' name = "archive_with_symlink",', |
| ' urls = ["http://%s:%s/archive_with_symlink.tar.gz"],' % (ip, port), |
| ' build_file = "@//:archive_with_symlink.BUILD",', |
| ' sha256 = ', |
| ( |
| ' "5ea20285db1b18134e4efe608e41215687f03cd3e3fdd7529860b175fc12fe76",' |
| ')' |
| ), |
| ] |
| self.ScratchFile('MODULE.bazel', rule_definition) |
| # In the archive, A is a symlink pointing to B |
| self.ScratchFile('archive_with_symlink.BUILD', [ |
| 'filegroup(', |
| ' name = "file-A",', |
| ' srcs = ["A"],', |
| ')', |
| ]) |
| self.ScratchFile('BUILD') |
| self.RunBazel([ |
| 'build', |
| '@archive_with_symlink//:file-A', |
| ]) |
| |
| def testNewHttpTarWithSparseFile(self): |
| # Test extraction of tar archives containing sparse files. |
| # The archive under test was produced using GNU tar on Linux: |
| # truncate -s 1M sparse_file |
| # tar -c --sparse --format posix -f sparse_archive.tar sparse_file |
| |
| ip, port = self._http_server.server_address |
| rule_definition = [ |
| 'bazel_dep(name = "rules_python", version = "0.40.0")', |
| 'http_archive = use_repo_rule(', |
| ' "@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")', |
| 'http_archive(', |
| ' name = "sparse_archive",', |
| ' urls = ["http://%s:%s/sparse_archive.tar"],' % (ip, port), |
| ' build_file = "@//:sparse_archive.BUILD",', |
| ' sha256 = ', |
| ' "a1a2b2ce4acd51a8cc1ab80adce6f134ac73e885219911a960a42000e312bb65",', |
| ')', |
| ] |
| self.ScratchFile('MODULE.bazel', rule_definition) |
| self.ScratchFile( |
| 'sparse_archive.BUILD', |
| [ |
| 'exports_files(["sparse_file"])', |
| ], |
| ) |
| self.ScratchFile( |
| 'test.py', |
| [ |
| 'import sys', |
| 'from tools.python.runfiles import runfiles', |
| 'path = runfiles.Create().Rlocation(sys.argv[1])', |
| 'if open(path, "rb").read() != b"\\0"*1024*1024:', |
| ' sys.exit(1)', |
| ], |
| ) |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@rules_python//python:py_test.bzl", "py_test")', |
| 'py_test(', |
| ' name = "test",', |
| ' srcs = ["test.py"],', |
| ' args = ["$(rlocationpath @sparse_archive//:sparse_file)"],', |
| ' data = [', |
| ' "@sparse_archive//:sparse_file",', |
| ' "@bazel_tools//tools/python/runfiles",', |
| ' ],)', |
| ], |
| ) |
| self.RunBazel([ |
| 'test', |
| '//:test', |
| ]) |
| |
| def _CreatePyWritingStarlarkRule(self, print_string): |
| self.ScratchFile('repo/foo.bzl', [ |
| 'def _impl(ctx):', |
| ' ctx.actions.write(', |
| ' output = ctx.outputs.out,', |
| ' content = """from __future__ import print_function', |
| 'print("%s")""",' % print_string, |
| ' )', |
| ' return [DefaultInfo(files = depset(direct = [ctx.outputs.out]))]', |
| '', |
| 'gen_py = rule(', |
| ' implementation = _impl,', |
| " outputs = {'out': '%{name}.py'},", |
| ')', |
| ]) |
| |
| def testNewLocalRepositoryNoticesFileChangeInRepoRoot(self): |
| """Regression test for https://github.com/bazelbuild/bazel/issues/7063.""" |
| rule_definition = [ |
| 'bazel_dep(name = "rules_python", version = "0.40.0")', |
| 'new_local_repository = use_repo_rule(', |
| ( |
| ' "@bazel_tools//tools/build_defs/repo:local.bzl",' |
| ' "new_local_repository")' |
| ), |
| 'new_local_repository(', |
| ' name = "r",', |
| ' path = "./repo",', |
| ' build_file_content = "exports_files([\'foo.bzl\'])",', |
| ')', |
| ] |
| self.ScratchFile('MODULE.bazel', rule_definition) |
| self._CreatePyWritingStarlarkRule('hello!') |
| self.ScratchFile( |
| 'BUILD', |
| [ |
| 'load("@r//:foo.bzl", "gen_py")', |
| 'load("@rules_python//python:py_binary.bzl", "py_binary")', |
| 'gen_py(name = "gen")', |
| 'py_binary(name = "bin", srcs = [":gen"], main = "gen.py")', |
| ], |
| ) |
| |
| _, stdout, _ = self.RunBazel(['run', '//:bin']) |
| self.assertIn('hello!', os.linesep.join(stdout)) |
| |
| # Modify the definition of the Starlark rule in the external repository. |
| # The py_binary rule should notice this and rebuild. |
| self._CreatePyWritingStarlarkRule('world') |
| _, stdout, _ = self.RunBazel(['run', '//:bin']) |
| self.assertNotIn('hello!', os.linesep.join(stdout)) |
| self.assertIn('world', os.linesep.join(stdout)) |
| |
| def setUpOtherRepoMyRepo(self): |
| self.ScratchFile('other_repo/REPO.bazel') |
| self.ScratchFile( |
| 'my_repo/MODULE.bazel', |
| [ |
| 'local_repository = use_repo_rule(', |
| ' "@bazel_tools//tools/build_defs/repo:local.bzl",', |
| ' "local_repository")', |
| 'local_repository(name = "other_repo", path="../other_repo")', |
| ], |
| ) |
| |
| def testDeletedPackagesOnExternalRepo(self): |
| self.setUpOtherRepoMyRepo() |
| self.ScratchFile('other_repo/pkg/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["ignore/file"],', |
| ')', |
| ]) |
| self.ScratchFile('other_repo/pkg/ignore/BUILD', [ |
| 'Bad BUILD file', |
| ]) |
| self.ScratchFile('other_repo/pkg/ignore/file') |
| work_dir = self.ScratchDir('my_repo') |
| |
| exit_code, _, stderr = self.RunBazel( |
| args=['build', '@other_repo//pkg:file'], |
| cwd=work_dir, |
| allow_failure=True, |
| ) |
| self.AssertExitCode(exit_code, 1, stderr) |
| self.assertIn( |
| "'@@+local_repository+other_repo//pkg/ignore' is a subpackage", |
| ''.join(stderr), |
| ) |
| |
| self.RunBazel( |
| args=[ |
| 'build', |
| '@other_repo//pkg:file', |
| # TODO(bzlmod): support apparent repo name for --deleted_packages |
| '--deleted_packages=@@+local_repository+other_repo//pkg/ignore', |
| ], |
| cwd=work_dir, |
| ) |
| |
| def testBazelignoreFileOnExternalRepo(self): |
| self.setUpOtherRepoMyRepo() |
| self.ScratchFile('other_repo/pkg/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["ignore/file.txt"],', |
| ')', |
| ]) |
| self.ScratchFile('other_repo/pkg/ignore/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["file.txt"],', |
| ')', |
| ]) |
| self.ScratchFile('other_repo/pkg/ignore/file.txt') |
| work_dir = self.ScratchDir('my_repo') |
| |
| exit_code, _, stderr = self.RunBazel( |
| args=['build', '@other_repo//pkg:file'], |
| cwd=work_dir, |
| allow_failure=True, |
| ) |
| self.AssertExitCode(exit_code, 1, stderr) |
| self.assertIn( |
| "'@@+local_repository+other_repo//pkg/ignore' is a subpackage", |
| ''.join(stderr), |
| ) |
| |
| self.ScratchFile('other_repo/.bazelignore', [ |
| 'pkg/ignore', |
| ]) |
| |
| self.RunBazel(args=['build', '@other_repo//pkg:file'], cwd=work_dir) |
| |
| self.ScratchFile('my_repo/BUILD', [ |
| 'filegroup(', |
| ' name = "all_files",', |
| ' srcs = ["@other_repo//pkg/ignore:file"],', |
| ')', |
| ]) |
| exit_code, _, stderr = self.RunBazel( |
| args=['build', '//:all_files'], cwd=work_dir, allow_failure=True |
| ) |
| self.AssertExitCode(exit_code, 1, stderr) |
| self.assertIn( |
| "no such package '@@+local_repository+other_repo//pkg/ignore'", |
| ''.join(stderr), |
| ) |
| |
| def testUniverseScopeWithBazelIgnoreInExternalRepo(self): |
| self.setUpOtherRepoMyRepo() |
| self.ScratchFile('other_repo/pkg/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["ignore/file.txt"],', |
| ')', |
| ]) |
| # This BUILD file should be ignored. |
| self.ScratchFile('other_repo/pkg/ignore/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["file.txt"],', |
| ')', |
| ]) |
| self.ScratchFile('other_repo/pkg/ignore/file.txt') |
| self.ScratchFile('other_repo/.bazelignore', [ |
| 'pkg/ignore', |
| ]) |
| |
| work_dir = self.ScratchDir('my_repo') |
| |
| _, stdout, _ = self.RunBazel( |
| args=[ |
| 'query', |
| '--universe_scope=@other_repo//...:*', |
| '--order_output=no', |
| 'deps(@other_repo//pkg:file)', |
| ], |
| cwd=work_dir, |
| ) |
| self.assertIn('@other_repo//pkg:ignore/file.txt', ''.join(stdout)) |
| |
| def testBazelignoreFileFromMainRepoDoesNotAffectExternalRepos(self): |
| # Regression test for https://github.com/bazelbuild/bazel/issues/10234 |
| self.setUpOtherRepoMyRepo() |
| self.ScratchFile('other_repo/foo/bar/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["file.txt"],', |
| ')', |
| ]) |
| self.ScratchFile('other_repo/foo/bar/file.txt') |
| |
| work_dir = self.ScratchDir('my_repo') |
| # This should not exclude @other_repo//foo/bar |
| self.ScratchFile('my_repo/.bazelignore', ['foo/bar']) |
| |
| _, stdout, _ = self.RunBazel( |
| args=['query', '@other_repo//foo/bar/...'], cwd=work_dir |
| ) |
| self.assertIn('@other_repo//foo/bar:file', ''.join(stdout)) |
| |
| def testBazelignoreFileFromExternalRepoDoesNotAffectMainRepo(self): |
| self.setUpOtherRepoMyRepo() |
| # This should not exclude //foo/bar in main repo |
| self.ScratchFile('other_repo/.bazelignore', ['foo/bar']) |
| self.ScratchFile('other_repo/BUILD',) |
| |
| work_dir = self.ScratchDir('my_repo') |
| self.ScratchFile('my_repo/foo/bar/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["file.txt"],', |
| ')', |
| ]) |
| self.ScratchFile('my_repo/foo/bar/file.txt') |
| |
| _, stdout, _ = self.RunBazel(args=['query', '//foo/bar/...'], cwd=work_dir) |
| self.assertIn('//foo/bar:file', ''.join(stdout)) |
| |
| def testMainBazelignoreContainingRepoName(self): |
| self.setUpOtherRepoMyRepo() |
| self.ScratchFile('other_repo/foo/bar/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["file.txt"],', |
| ')', |
| ]) |
| self.ScratchFile('other_repo/foo/bar/file.txt') |
| |
| work_dir = self.ScratchDir('my_repo') |
| |
| # This should not exclude @other_repo//foo/bar, because .bazelignore doesn't |
| # support having repository name in the path fragment. |
| self.ScratchFile('my_repo/.bazelignore', ['@other_repo//foo/bar']) |
| |
| self.RunBazel(args=['build', '@other_repo//foo/bar:file'], cwd=work_dir) |
| |
| def testExternalBazelignoreContainingRepoName(self): |
| self.ScratchFile('other_repo/REPO.bazel') |
| # This should not exclude @third_repo//foo/bar, because .bazelignore doesn't |
| # support having repository name in the path fragment. |
| self.ScratchFile('other_repo/.bazelignore', ['@third_repo//foo/bar']) |
| self.ScratchFile('other_repo/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["@third_repo//foo/bar:file"],', |
| ')', |
| ]) |
| |
| self.ScratchFile('third_repo/REPO.bazel') |
| self.ScratchFile('third_repo/foo/bar/BUILD', [ |
| 'filegroup(', |
| ' name = "file",', |
| ' srcs = ["file.txt"],', |
| ' visibility = ["//visibility:public"],', |
| ')', |
| ]) |
| self.ScratchFile('third_repo/foo/bar/file.txt') |
| |
| work_dir = self.ScratchDir('my_repo') |
| self.ScratchFile( |
| 'my_repo/MODULE.bazel', |
| [ |
| ( |
| 'local_repository =' |
| ' use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl",' |
| ' "local_repository")' |
| ), |
| 'local_repository(name = "other_repo", path="../other_repo")', |
| 'local_repository(name = "third_repo", path="../third_repo")', |
| ], |
| ) |
| |
| self.RunBazel(args=['build', '@other_repo//:file'], cwd=work_dir) |
| |
| def testRepoEnv(self): |
| # Testing fix for issue: https://github.com/bazelbuild/bazel/issues/15430 |
| |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'dump_env = use_repo_rule("//:main.bzl", "dump_env")', |
| 'dump_env(', |
| ' name = "debug"', |
| ')', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile('main.bzl', [ |
| 'def _dump_env(ctx):', ' val = ctx.os.environ.get("FOO", "nothing")', |
| ' print("FOO", val)', ' ctx.file("BUILD")', |
| 'dump_env = repository_rule(', ' implementation = _dump_env,', |
| ' local = True,', ')' |
| ]) |
| |
| _, _, stderr = self.RunBazel( |
| args=['build', '@debug//:all', '--repo_env=FOO'], env_add={'FOO': 'bar'} |
| ) |
| self.assertIn('FOO bar', os.linesep.join(stderr)) |
| self.assertNotIn('null value in entry: FOO=null', os.linesep.join(stderr)) |
| |
| def testRepoEnvUnset(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'dump_env = use_repo_rule("//:main.bzl", "dump_env")', |
| 'dump_env(', |
| ' name = "debug"', |
| ')', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'main.bzl', |
| [ |
| 'def _dump_env(ctx):', |
| ' val = ctx.os.environ.get("FOO", "nothing")', |
| ' print("FOO", val)', |
| ' ctx.file("BUILD")', |
| 'dump_env = repository_rule(', |
| ' implementation = _dump_env,', |
| ' local = True,', |
| ')', |
| ], |
| ) |
| |
| _, _, stderr = self.RunBazel( |
| args=[ |
| 'build', |
| '@debug//:all', |
| '--repo_env=FOO=bar1', |
| '--repo_env==FOO', |
| ], |
| env_add={'FOO': 'bar'}, |
| ) |
| self.assertIn('FOO nothing', os.linesep.join(stderr)) |
| |
| def testRepoEnvUnsetThenSet(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'dump_env = use_repo_rule("//:main.bzl", "dump_env")', |
| 'dump_env(', |
| ' name = "debug"', |
| ')', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'main.bzl', |
| [ |
| 'def _dump_env(ctx):', |
| ' val = ctx.os.environ.get("FOO", "nothing")', |
| ' print("FOO", val)', |
| ' ctx.file("BUILD")', |
| 'dump_env = repository_rule(', |
| ' implementation = _dump_env,', |
| ' local = True,', |
| ')', |
| ], |
| ) |
| |
| _, _, stderr = self.RunBazel( |
| args=[ |
| 'build', |
| '@debug//:all', |
| '--repo_env=FOO=bar1', |
| '--repo_env==FOO', |
| '--repo_env=FOO=bar2', |
| ], |
| env_add={'FOO': 'bar'}, |
| ) |
| self.assertIn('FOO bar2', os.linesep.join(stderr)) |
| |
| def testRepoEnvInherit(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'dump_env = use_repo_rule("//:main.bzl", "dump_env")', |
| 'dump_env(', |
| ' name = "debug"', |
| ')', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'main.bzl', |
| [ |
| 'def _dump_env(ctx):', |
| ' val = ctx.os.environ.get("FOO", "nothing")', |
| ' print("FOO", val)', |
| ' ctx.file("BUILD")', |
| 'dump_env = repository_rule(', |
| ' implementation = _dump_env,', |
| ' local = True,', |
| ')', |
| ], |
| ) |
| |
| _, _, stderr = self.RunBazel( |
| args=[ |
| 'build', |
| '@debug//:all', |
| '--repo_env=FOO=bar1', |
| '--repo_env==FOO', |
| '--repo_env=FOO', |
| ], |
| env_add={'FOO': 'bar2'}, |
| ) |
| self.assertIn('FOO bar2', os.linesep.join(stderr)) |
| |
| def testRepoEnvEmpty(self): |
| self.ScratchFile( |
| 'MODULE.bazel', |
| [ |
| 'dump_env = use_repo_rule("//:main.bzl", "dump_env")', |
| 'dump_env(', |
| ' name = "debug"', |
| ')', |
| ], |
| ) |
| self.ScratchFile('BUILD') |
| self.ScratchFile( |
| 'main.bzl', |
| [ |
| 'def _dump_env(ctx):', |
| ' val = ctx.os.environ.get("FOO", "nothing")', |
| ' print("FOO", val)', |
| ' ctx.file("BUILD")', |
| 'dump_env = repository_rule(', |
| ' implementation = _dump_env,', |
| ' local = True,', |
| ')', |
| ], |
| ) |
| |
| _, _, stderr = self.RunBazel( |
| args=[ |
| 'build', |
| '@debug//:all', |
| '--repo_env=FOO=bar1', |
| '--repo_env=FOO=', |
| ], |
| env_add={'FOO': 'bar2'}, |
| ) |
| self.assertIn('FOO' + os.linesep, os.linesep.join(stderr)) |
| |
| |
| if __name__ == '__main__': |
| absltest.main() |