| # 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 os | |
| import threading | |
| import unittest | |
| from six.moves import SimpleHTTPServer | |
| from six.moves import socketserver | |
| 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 = SimpleHTTPServer.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 ['six-1.10.0.tar.gz', 'archive_with_symlink.zip']: | |
| 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 = [ | |
| 'load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")', | |
| 'http_archive(', | |
| ' name = "six_archive",', | |
| ' urls = ["http://%s:%s/six-1.10.0.tar.gz"],' % (ip, port), | |
| ' sha256 = ' | |
| '"105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",', | |
| ' strip_prefix = "six-1.10.0",', | |
| ' build_file = "@//third_party:six.BUILD",', | |
| ')', | |
| ] | |
| build_file = [ | |
| 'py_library(', | |
| ' name = "six",', | |
| ' srcs = ["six.py"],', | |
| ')', | |
| ] | |
| rule_definition.extend(self.GetDefaultRepoRules()) | |
| self.ScratchFile('WORKSPACE', rule_definition) | |
| self.ScratchFile('BUILD') | |
| self.ScratchFile('third_party/BUILD') | |
| self.ScratchFile('third_party/six.BUILD', build_file) | |
| exit_code, _, stderr = self.RunBazel(['build', '@six_archive//...']) | |
| self.assertEqual(exit_code, 0, os.linesep.join(stderr)) | |
| fetching_disabled_msg = 'fetching is disabled' | |
| # Changing the mtime of the BUILD file shouldn't invalidate it. | |
| os.utime(self.Path('third_party/six.BUILD'), (100, 200)) | |
| exit_code, _, stderr = self.RunBazel( | |
| ['build', '--nofetch', '@six_archive//...']) | |
| self.assertEqual(exit_code, 0, os.linesep.join(stderr)) | |
| 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/six.BUILD', build_file + ['"a noop string"']) | |
| exit_code, _, stderr = self.RunBazel( | |
| ['build', '--nofetch', '@six_archive//...']) | |
| self.assertEqual(exit_code, 0, os.linesep.join(stderr)) | |
| self.assertIn(fetching_disabled_msg, os.linesep.join(stderr)) | |
| # Test repository reloading after BUILD file changes. | |
| self.ScratchFile('third_party/six.BUILD', build_file + ['foobar']) | |
| exit_code, _, stderr = self.RunBazel(['build', '@six_archive//...']) | |
| self.assertEqual(exit_code, 1, os.linesep.join(stderr)) | |
| self.assertIn('name \'foobar\' is not defined', os.linesep.join(stderr)) | |
| def testNewHttpArchiveWithSymlinks(self): | |
| ip, port = self._http_server.server_address | |
| rule_definition = [ | |
| 'load("@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",' | |
| ')', | |
| ] | |
| rule_definition.extend(self.GetDefaultRepoRules()) | |
| self.ScratchFile('WORKSPACE', 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') | |
| exit_code, _, stderr = self.RunBazel([ | |
| 'build', | |
| '@archive_with_symlink//:file-A', | |
| ]) | |
| self.assertEqual(exit_code, 0, os.linesep.join(stderr)) | |
| 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 = [ | |
| 'load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")', | |
| 'new_local_repository(', | |
| ' name = "r",', | |
| ' path = "./repo",', | |
| ' build_file_content = "exports_files([\'foo.bzl\'])",', | |
| ')', | |
| ] | |
| rule_definition.extend(self.GetDefaultRepoRules()) | |
| self.ScratchFile('WORKSPACE', rule_definition) | |
| self.CreateWorkspaceWithDefaultRepos('repo/WORKSPACE') | |
| self._CreatePyWritingStarlarkRule('hello!') | |
| self.ScratchFile('BUILD', [ | |
| 'load("@r//:foo.bzl", "gen_py")', | |
| 'gen_py(name = "gen")', | |
| 'py_binary(name = "bin", srcs = [":gen"], main = "gen.py")', | |
| ]) | |
| exit_code, stdout, stderr = self.RunBazel(['run', '//:bin']) | |
| self.assertEqual(exit_code, 0, os.linesep.join(stderr)) | |
| 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') | |
| exit_code, stdout, stderr = self.RunBazel(['run', '//:bin']) | |
| self.assertEqual(exit_code, 0, os.linesep.join(stderr)) | |
| self.assertNotIn('hello!', os.linesep.join(stdout)) | |
| self.assertIn('world', os.linesep.join(stdout)) | |
| def testDeletedPackagesOnExternalRepo(self): | |
| self.ScratchFile('other_repo/WORKSPACE') | |
| 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') | |
| self.ScratchFile('my_repo/WORKSPACE', [ | |
| "local_repository(name = 'other_repo', path='../other_repo')", | |
| ]) | |
| exit_code, _, stderr = self.RunBazel( | |
| args=['build', '@other_repo//pkg:file'], cwd=work_dir) | |
| self.AssertExitCode(exit_code, 1, stderr) | |
| self.assertIn('\'@other_repo//pkg/ignore\' is a subpackage', | |
| ''.join(stderr)) | |
| exit_code, _, stderr = self.RunBazel( | |
| args=[ | |
| 'build', '@other_repo//pkg:file', | |
| '--deleted_packages=@other_repo//pkg/ignore' | |
| ], | |
| cwd=work_dir) | |
| self.AssertExitCode(exit_code, 0, stderr) | |
| def testBazelignoreFileOnExternalRepo(self): | |
| self.ScratchFile('other_repo/WORKSPACE') | |
| 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') | |
| self.ScratchFile('my_repo/WORKSPACE', [ | |
| 'local_repository(name = "other_repo", path="../other_repo")', | |
| ]) | |
| exit_code, _, stderr = self.RunBazel( | |
| args=['build', '@other_repo//pkg:file'], cwd=work_dir) | |
| self.AssertExitCode(exit_code, 1, stderr) | |
| self.assertIn('\'@other_repo//pkg/ignore\' is a subpackage', | |
| ''.join(stderr)) | |
| self.ScratchFile('other_repo/.bazelignore', [ | |
| 'pkg/ignore', | |
| ]) | |
| exit_code, _, stderr = self.RunBazel( | |
| args=['build', '@other_repo//pkg:file'], cwd=work_dir) | |
| self.AssertExitCode(exit_code, 0, stderr) | |
| 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) | |
| self.AssertExitCode(exit_code, 1, stderr) | |
| self.assertIn('no such package \'@other_repo//pkg/ignore\'', | |
| ''.join(stderr)) | |
| def testUniverseScopeWithBazelIgnoreInExternalRepo(self): | |
| self.ScratchFile('other_repo/WORKSPACE') | |
| 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') | |
| self.ScratchFile('my_repo/WORKSPACE', [ | |
| 'local_repository(name = "other_repo", path="../other_repo")', | |
| ]) | |
| exit_code, stdout, stderr = self.RunBazel( | |
| args=[ | |
| 'query', | |
| '--universe_scope=@other_repo//...:*', | |
| '--order_output=no', | |
| 'deps(@other_repo//pkg:file)'], | |
| cwd=work_dir) | |
| self.AssertExitCode(exit_code, 0, stderr) | |
| self.assertIn('@other_repo//pkg:ignore/file.txt', ''.join(stdout)) | |
| def testBazelignoreFileFromMainRepoDoesNotAffectExternalRepos(self): | |
| # Regression test for https://github.com/bazelbuild/bazel/issues/10234 | |
| self.ScratchFile('other_repo/WORKSPACE') | |
| 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') | |
| self.ScratchFile('my_repo/WORKSPACE', [ | |
| 'local_repository(name = "other_repo", path="../other_repo")', | |
| ]) | |
| # This should not exclude @other_repo//foo/bar | |
| self.ScratchFile('my_repo/.bazelignore', ['foo/bar']) | |
| exit_code, stdout, stderr = self.RunBazel( | |
| args=['query', '@other_repo//foo/bar/...'], cwd=work_dir) | |
| self.AssertExitCode(exit_code, 0, stderr) | |
| self.assertIn('@other_repo//foo/bar:file', ''.join(stdout)) | |
| def testBazelignoreFileFromExternalRepoDoesNotAffectMainRepo(self): | |
| self.ScratchFile('other_repo/WORKSPACE') | |
| # 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') | |
| self.ScratchFile('my_repo/WORKSPACE', [ | |
| 'local_repository(name = "other_repo", path="../other_repo")', | |
| ]) | |
| exit_code, stdout, stderr = self.RunBazel( | |
| args=['query', '//foo/bar/...'], cwd=work_dir) | |
| self.AssertExitCode(exit_code, 0, stderr) | |
| self.assertIn('//foo/bar:file', ''.join(stdout)) | |
| def testMainBazelignoreContainingRepoName(self): | |
| self.ScratchFile('other_repo/WORKSPACE') | |
| 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') | |
| self.ScratchFile('my_repo/WORKSPACE', [ | |
| 'local_repository(name = "other_repo", path="../other_repo")', | |
| ]) | |
| # This should not exclude @other_repo//foo/bar, because .bazelignore doesn't | |
| # support having repository name in the path fragement. | |
| self.ScratchFile('my_repo/.bazelignore', ['@other_repo//foo/bar']) | |
| exit_code, _, stderr = self.RunBazel( | |
| args=['build', '@other_repo//foo/bar:file'], cwd=work_dir) | |
| self.AssertExitCode(exit_code, 0, stderr) | |
| def testExternalBazelignoreContainingRepoName(self): | |
| self.ScratchFile('other_repo/WORKSPACE') | |
| # This should not exclude @third_repo//foo/bar, because .bazelignore doesn't | |
| # support having repository name in the path fragement. | |
| 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/WORKSPACE') | |
| 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/WORKSPACE', [ | |
| 'local_repository(name = "other_repo", path="../other_repo")', | |
| 'local_repository(name = "third_repo", path="../third_repo")', | |
| ]) | |
| exit_code, _, stderr = self.RunBazel( | |
| args=['build', '@other_repo//:file'], cwd=work_dir) | |
| self.AssertExitCode(exit_code, 0, stderr) | |
| if __name__ == '__main__': | |
| unittest.main() |