|  | # 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', | 
|  | 'archive_with_symlink.tar.gz' | 
|  | ]: | 
|  | 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 testNewHttpZipArchiveWithSymlinks(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 testNewHttpTarArchiveWithSymlinks(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.tar.gz"],' % (ip, port), | 
|  | '    build_file = "@//:archive_with_symlink.BUILD",', | 
|  | '    sha256 = ', | 
|  | '  "5ea20285db1b18134e4efe608e41215687f03cd3e3fdd7529860b175fc12fe76",' | 
|  | ')', | 
|  | ] | 
|  | 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() |