| #!/bin/bash |
| # |
| # Copyright 2015 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. |
| # |
| # Test the local_repository binding |
| # |
| |
| # Load test environment |
| src_dir=$(cd "$(dirname ${BASH_SOURCE[0]})" && pwd) |
| source $(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/test-setup.sh \ |
| || { echo "test-setup.sh not found!" >&2; exit 1; } |
| source "$src_dir/remote_helpers.sh" \ |
| || { echo "remote_helpers.sh not found!" >&2; exit 1; } |
| |
| # Basic test. |
| function test_macro_local_repository() { |
| create_new_workspace |
| repo2=$new_workspace_dir |
| |
| mkdir -p carnivore |
| cat > carnivore/BUILD <<'EOF' |
| genrule( |
| name = "mongoose", |
| cmd = "echo 'Tra-la!' | tee $@", |
| outs = ["moogoose.txt"], |
| visibility = ["//visibility:public"], |
| ) |
| EOF |
| |
| cd ${WORKSPACE_DIR} |
| cat > WORKSPACE <<EOF |
| load('/test', 'macro') |
| |
| macro('$repo2') |
| EOF |
| |
| # Empty package for the .bzl file |
| echo -n >BUILD |
| |
| # Our macro |
| cat >test.bzl <<EOF |
| def macro(path): |
| print('bleh') |
| native.local_repository(name='endangered', path=path) |
| native.bind(name='mongoose', actual='@endangered//carnivore:mongoose') |
| EOF |
| mkdir -p zoo |
| cat > zoo/BUILD <<'EOF' |
| genrule( |
| name = "ball-pit1", |
| srcs = ["@endangered//carnivore:mongoose"], |
| outs = ["ball-pit1.txt"], |
| cmd = "cat $< >$@", |
| ) |
| |
| genrule( |
| name = "ball-pit2", |
| srcs = ["//external:mongoose"], |
| outs = ["ball-pit2.txt"], |
| cmd = "cat $< >$@", |
| ) |
| EOF |
| |
| bazel build //zoo:ball-pit1 >& $TEST_log || fail "Failed to build" |
| expect_log "bleh." |
| expect_log "Tra-la!" # Invalidation |
| cat bazel-genfiles/zoo/ball-pit1.txt >$TEST_log |
| expect_log "Tra-la!" |
| |
| bazel build //zoo:ball-pit1 >& $TEST_log || fail "Failed to build" |
| expect_not_log "Tra-la!" # No invalidation |
| |
| bazel build //zoo:ball-pit2 >& $TEST_log || fail "Failed to build" |
| expect_not_log "Tra-la!" # No invalidation |
| cat bazel-genfiles/zoo/ball-pit2.txt >$TEST_log |
| expect_log "Tra-la!" |
| |
| # Test invalidation of the WORKSPACE file |
| create_new_workspace |
| repo2=$new_workspace_dir |
| |
| mkdir -p carnivore |
| cat > carnivore/BUILD <<'EOF' |
| genrule( |
| name = "mongoose", |
| cmd = "echo 'Tra-la-la!' | tee $@", |
| outs = ["moogoose.txt"], |
| visibility = ["//visibility:public"], |
| ) |
| EOF |
| cd ${WORKSPACE_DIR} |
| cat >test.bzl <<EOF |
| def macro(path): |
| print('blah') |
| native.local_repository(name='endangered', path='$repo2') |
| native.bind(name='mongoose', actual='@endangered//carnivore:mongoose') |
| EOF |
| bazel build //zoo:ball-pit1 >& $TEST_log || fail "Failed to build" |
| expect_log "blah." |
| expect_log "Tra-la-la!" # Invalidation |
| cat bazel-genfiles/zoo/ball-pit1.txt >$TEST_log |
| expect_log "Tra-la-la!" |
| |
| bazel build //zoo:ball-pit1 >& $TEST_log || fail "Failed to build" |
| expect_not_log "Tra-la-la!" # No invalidation |
| |
| bazel build //zoo:ball-pit2 >& $TEST_log || fail "Failed to build" |
| expect_not_log "Tra-la-la!" # No invalidation |
| cat bazel-genfiles/zoo/ball-pit2.txt >$TEST_log |
| expect_log "Tra-la-la!" |
| } |
| |
| function test_load_from_symlink_to_outside_of_workspace() { |
| OTHER=$TEST_TMPDIR/other |
| |
| cat > WORKSPACE<<EOF |
| load("/a/b/c", "c") |
| EOF |
| |
| mkdir -p $OTHER/a/b |
| touch $OTHER/a/b/BUILD |
| cat > $OTHER/a/b/c.bzl <<EOF |
| def c(): |
| pass |
| EOF |
| |
| touch BUILD |
| ln -s $TEST_TMPDIR/other/a a |
| bazel build //:BUILD || fail "Failed to build" |
| rm -fr $TEST_TMPDIR/other |
| } |
| |
| # Test load from repository. |
| function test_external_load_from_workspace() { |
| create_new_workspace |
| repo2=$new_workspace_dir |
| |
| mkdir -p carnivore |
| cat > carnivore/BUILD <<'EOF' |
| genrule( |
| name = "mongoose", |
| cmd = "echo 'Tra-la-la!' | tee $@", |
| outs = ["moogoose.txt"], |
| visibility = ["//visibility:public"], |
| ) |
| EOF |
| |
| create_new_workspace |
| repo3=$new_workspace_dir |
| # Our macro |
| cat >WORKSPACE |
| cat >test.bzl <<EOF |
| def macro(path): |
| print('bleh') |
| native.local_repository(name='endangered', path=path) |
| EOF |
| cat >BUILD <<'EOF' |
| exports_files(["test.bzl"]) |
| EOF |
| |
| cd ${WORKSPACE_DIR} |
| cat > WORKSPACE <<EOF |
| local_repository(name='proxy', path='$repo3') |
| load('@proxy//:test.bzl', 'macro') |
| macro('$repo2') |
| EOF |
| |
| bazel build @endangered//carnivore:mongoose >& $TEST_log \ |
| || fail "Failed to build" |
| expect_log "bleh." |
| } |
| |
| # Test loading a repository with a load statement in the WORKSPACE file |
| function test_load_repository_with_load() { |
| create_new_workspace |
| repo2=$new_workspace_dir |
| |
| echo "Tra-la!" > data.txt |
| cat <<'EOF' >BUILD |
| exports_files(["data.txt"]) |
| EOF |
| |
| cat <<'EOF' >ext.bzl |
| def macro(): |
| print('bleh') |
| EOF |
| |
| cat <<'EOF' >WORKSPACE |
| workspace(name = "foo") |
| load("//:ext.bzl", "macro") |
| macro() |
| EOF |
| |
| cd ${WORKSPACE_DIR} |
| cat > WORKSPACE <<EOF |
| local_repository(name='foo', path='$repo2') |
| load("@foo//:ext.bzl", "macro") |
| macro() |
| EOF |
| |
| cat > BUILD <<'EOF' |
| genrule(name = "foo", srcs=["@foo//:data.txt"], outs=["foo.txt"], cmd = "cat $< | tee $@") |
| EOF |
| |
| bazel build //:foo >& $TEST_log || fail "Failed to build" |
| expect_log "bleh" |
| expect_log "Tra-la!" |
| } |
| |
| # Test cycle when loading a repository with a load statement in the WORKSPACE file that is not |
| # yet defined. |
| function test_cycle_load_repository() { |
| create_new_workspace |
| repo2=$new_workspace_dir |
| |
| echo "Tra-la!" > data.txt |
| cat <<'EOF' >BUILD |
| exports_files(["data.txt"]) |
| EOF |
| |
| cat <<'EOF' >ext.bzl |
| def macro(): |
| print('bleh') |
| EOF |
| |
| cat >WORKSPACE |
| |
| cd ${WORKSPACE_DIR} |
| cat > WORKSPACE <<EOF |
| load("@foo//:ext.bzl", "macro") |
| macro() |
| local_repository(name='foo', path='$repo2') |
| EOF |
| |
| local exitCode=0 |
| bazel build @foo//:data.txt >& $TEST_log || exitCode=$? |
| [ $exitCode != 0 ] || fail "building @foo//:data.txt succeed while expected failure" |
| |
| expect_not_log "PACKAGE" |
| expect_log "Failed to load Skylark extension '@foo//:ext.bzl'" |
| expect_log "Maybe repository 'foo' was defined later in your WORKSPACE file?" |
| } |
| |
| function test_skylark_local_repository() { |
| create_new_workspace |
| repo2=$new_workspace_dir |
| |
| cat > BUILD <<'EOF' |
| genrule(name='bar', cmd='echo foo | tee $@', outs=['bar.txt']) |
| EOF |
| |
| cd ${WORKSPACE_DIR} |
| cat > WORKSPACE <<EOF |
| load('/test', 'repo') |
| repo(name='foo', path='$repo2') |
| EOF |
| |
| # Our custom repository rule |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| repository_ctx.symlink(repository_ctx.path(repository_ctx.attr.path), repository_ctx.path("")) |
| |
| repo = repository_rule( |
| implementation=_impl, |
| local=True, |
| attrs={"path": attr.string(mandatory=True)}) |
| EOF |
| # Need to be in a package |
| cat > BUILD |
| |
| bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_log "foo" |
| cat bazel-genfiles/external/foo/bar.txt >$TEST_log |
| expect_log "foo" |
| } |
| |
| function setup_skylark_repository() { |
| create_new_workspace |
| repo2=$new_workspace_dir |
| |
| cat > bar.txt |
| echo "filegroup(name='bar', srcs=['bar.txt'])" > BUILD |
| |
| cd "${WORKSPACE_DIR}" |
| cat > WORKSPACE <<EOF |
| load('/test', 'repo') |
| repo(name = 'foo') |
| EOF |
| # Need to be in a package |
| cat > BUILD |
| } |
| |
| function test_skylark_repository_which_and_execute() { |
| setup_skylark_repository |
| |
| bazel info |
| |
| # Test we are using the client environment, not the server one |
| echo "#!/bin/bash" > bin.sh |
| echo "exit 0" >> bin.sh |
| chmod +x bin.sh |
| |
| # Our custom repository rule |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| bash = repository_ctx.which("bash") |
| if bash == None: |
| fail("Bash not found!") |
| bin = repository_ctx.which("bin.sh") |
| if bin == None: |
| fail("bin.sh not found!") |
| result = repository_ctx.execute([bash, "--version"]) |
| if result.return_code != 0: |
| fail("Non-zero return code from bash: " + result.return_code) |
| if result.stderr != "": |
| fail("Non-empty error output: " + result.stderr) |
| print(result.stdout) |
| # Symlink so a repository is created |
| repository_ctx.symlink(repository_ctx.path("$repo2"), repository_ctx.path("")) |
| repo = repository_rule(implementation=_impl, local=True) |
| EOF |
| |
| PATH="${PATH}:${PWD}" bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_log "version" |
| } |
| |
| function test_skylark_repository_execute_stderr() { |
| setup_skylark_repository |
| |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| result = repository_ctx.execute([str(repository_ctx.which("bash")), "-c", "echo erf >&2; exit 1"]) |
| if result.return_code != 1: |
| fail("Incorrect return code from bash (should be 1): " + result.return_code) |
| if result.stdout != "": |
| fail("Non-empty output: %s (stderr was %s)" % (result.stdout, result.stderr)) |
| print(result.stderr) |
| # Symlink so a repository is created |
| repository_ctx.symlink(repository_ctx.path("$repo2"), repository_ctx.path("")) |
| repo = repository_rule(implementation=_impl, local=True) |
| EOF |
| |
| bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_log "erf" |
| } |
| |
| function test_skylark_repository_environ() { |
| setup_skylark_repository |
| |
| # Our custom repository rule |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| print(repository_ctx.os.environ["FOO"]) |
| # Symlink so a repository is created |
| repository_ctx.symlink(repository_ctx.path("$repo2"), repository_ctx.path("")) |
| repo = repository_rule(implementation=_impl, local=False) |
| EOF |
| |
| # TODO(dmarting): We should seriously have something better to force a refetch... |
| bazel clean --expunge |
| FOO=BAR bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_log "BAR" |
| |
| FOO=BAR bazel clean --expunge >& $TEST_log |
| FOO=BAR bazel info >& $TEST_log |
| |
| FOO=BAZ bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_log "BAZ" |
| |
| # Test that we don't re-run on server restart. |
| FOO=BEZ bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_not_log "BEZ" |
| bazel shutdown >& $TEST_log |
| FOO=BEZ bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_not_log "BEZ" |
| |
| # Test modifying test.bzl invalidate the repository |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| print(repository_ctx.os.environ["BAR"]) |
| # Symlink so a repository is created |
| repository_ctx.symlink(repository_ctx.path("$repo2"), repository_ctx.path("")) |
| repo = repository_rule(implementation=_impl, local=True) |
| EOF |
| BAR=BEZ bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_log "BEZ" |
| |
| # Shutdown and modify again |
| bazel shutdown |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| print(repository_ctx.os.environ["BAZ"]) |
| # Symlink so a repository is created |
| repository_ctx.symlink(repository_ctx.path("$repo2"), repository_ctx.path("")) |
| repo = repository_rule(implementation=_impl, local=True) |
| EOF |
| BAZ=BOZ bazel build @foo//:bar >& $TEST_log || fail "Failed to build" |
| expect_log "BOZ" |
| } |
| |
| function test_skylark_repository_executable_flag() { |
| setup_skylark_repository |
| |
| # Our custom repository rule |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| repository_ctx.file("test.sh", "exit 0") |
| repository_ctx.file("BUILD", "sh_binary(name='bar',srcs=['test.sh'])", False) |
| repository_ctx.template("test2", Label("//:bar"), {}, False) |
| repository_ctx.template("test2.sh", Label("//:bar"), {}, True) |
| repo = repository_rule(implementation=_impl, local=True) |
| EOF |
| cat >bar |
| |
| bazel run @foo//:bar >& $TEST_log || fail "Execution of @foo//:bar failed" |
| output_base=$(bazel info output_base) |
| test -x "${output_base}/external/foo/test.sh" || fail "test.sh is not executable" |
| test -x "${output_base}/external/foo/test2.sh" || fail "test2.sh is not executable" |
| test ! -x "${output_base}/external/foo/BUILD" || fail "BUILD is executable" |
| test ! -x "${output_base}/external/foo/test2" || fail "test2 is executable" |
| } |
| |
| function test_skylark_repository_download() { |
| # Prepare HTTP server with Python |
| mkdir "server_dir" |
| echo "This is one file" > server_dir/download_no_sha256.txt |
| echo "This is another file" > server_dir/download_with_sha256.txt |
| file_sha256="$(sha256sum server_dir/download_with_sha256.txt | head -c 64)" |
| |
| # Start HTTP server with Python |
| startup_server "server_dir" |
| |
| setup_skylark_repository |
| # Our custom repository rule |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| repository_ctx.file("BUILD") |
| repository_ctx.download( |
| "http://localhost:${fileserver_port}/download_no_sha256.txt", |
| "download_no_sha256.txt") |
| repository_ctx.download( |
| "http://localhost:${fileserver_port}/download_with_sha256.txt", |
| "download_with_sha256.txt", "${file_sha256}") |
| repo = repository_rule(implementation=_impl, local=False) |
| EOF |
| |
| bazel build @foo//:all >& $TEST_log && shutdown_server \ |
| || fail "Execution of @foo//:all failed" |
| |
| output_base="$(bazel info output_base)" |
| # Test download |
| test -e "${output_base}/external/foo/download_no_sha256.txt" \ |
| || fail "download_no_sha256.txt is not downloaded" |
| test -e "${output_base}/external/foo/download_with_sha256.txt" \ |
| || fail "download_with_sha256.txt is not downloaded" |
| # Test download |
| diff "${output_base}/external/foo/download_no_sha256.txt" server_dir/download_no_sha256.txt >/dev/null \ |
| || fail "download_no_sha256.txt is not downloaded successfully" |
| diff "${output_base}/external/foo/download_with_sha256.txt" server_dir/download_with_sha256.txt >/dev/null \ |
| || fail "download_with_sha256.txt is not downloaded successfully" |
| |
| rm -rf "server_dir" |
| } |
| |
| function test_skylark_repository_download_and_extract() { |
| # Prepare HTTP server with Python |
| mkdir "server_dir" |
| echo "This is one file" > server_dir/download_and_extract1.txt |
| echo "This is another file" > server_dir/download_and_extract2.txt |
| echo "This is a third file" > server_dir/download_and_extract3.txt |
| tar -zcvf server_dir/download_and_extract1.tar.gz server_dir/download_and_extract1.txt |
| zip server_dir/download_and_extract2.zip server_dir/download_and_extract2.txt |
| zip server_dir/download_and_extract3.zip server_dir/download_and_extract3.txt |
| file_sha256="$(sha256sum server_dir/download_and_extract3.zip | head -c 64)" |
| |
| # Start HTTP server with Python |
| startup_server "server_dir" |
| |
| setup_skylark_repository |
| # Our custom repository rule |
| cat >test.bzl <<EOF |
| def _impl(repository_ctx): |
| repository_ctx.file("BUILD") |
| repository_ctx.download_and_extract( |
| "http://localhost:${fileserver_port}/download_and_extract1.tar.gz", "") |
| repository_ctx.download_and_extract( |
| "http://localhost:${fileserver_port}/download_and_extract2.zip", "", "") |
| repository_ctx.download_and_extract( |
| "http://localhost:${fileserver_port}/download_and_extract3.zip", ".", "${file_sha256}", "", "") |
| repo = repository_rule(implementation=_impl, local=False) |
| EOF |
| |
| bazel clean --expunge_async >& $TEST_log || fail "bazel clean failed" |
| bazel build @foo//:all >& $TEST_log && shutdown_server \ |
| || fail "Execution of @foo//:all failed" |
| |
| output_base="$(bazel info output_base)" |
| # Test cleanup |
| test -e "${output_base}/external/foo/server_dir/download_and_extract1.tar.gz" \ |
| && fail "temp file is not deleted successfully" || true |
| test -e "${output_base}/external/foo/server_dir/download_and_extract2.zip" \ |
| && fail "temp file is not deleted successfully" || true |
| test -e "${output_base}/external/foo/server_dir/download_and_extract3.zip" \ |
| && fail "temp file is not deleted successfully" || true |
| # Test download_and_extract |
| diff "${output_base}/external/foo/server_dir/download_and_extract1.txt" \ |
| server_dir/download_and_extract1.txt >/dev/null \ |
| || fail "download_and_extract1.tar.gz is not extracted successfully" |
| diff "${output_base}/external/foo/server_dir/download_and_extract2.txt" \ |
| server_dir/download_and_extract2.txt >/dev/null \ |
| || fail "download_and_extract2.zip is not extracted successfully" |
| diff "${output_base}/external/foo/server_dir/download_and_extract3.txt" \ |
| server_dir/download_and_extract3.txt >/dev/null \ |
| || fail "download_and_extract3.zip is not extracted successfully" |
| |
| rm -rf "server_dir" |
| } |
| |
| # Test native.bazel_version |
| function test_bazel_version() { |
| create_new_workspace |
| repo2=$new_workspace_dir |
| |
| cat > BUILD <<'EOF' |
| genrule( |
| name = "test", |
| cmd = "echo 'Tra-la!' | tee $@", |
| outs = ["test.txt"], |
| visibility = ["//visibility:public"], |
| ) |
| EOF |
| |
| cd ${WORKSPACE_DIR} |
| cat > WORKSPACE <<EOF |
| load('/test', 'macro') |
| |
| macro('$repo2') |
| EOF |
| |
| # Empty package for the .bzl file |
| echo -n >BUILD |
| |
| # Our macro |
| cat >test.bzl <<EOF |
| def macro(path): |
| print(native.bazel_version) |
| native.local_repository(name='test', path=path) |
| EOF |
| |
| local version="$(bazel info release)" |
| # On release, Bazel binary get stamped, else we might run with an unstamped version. |
| if [ "$version" == "development version" ]; then |
| version="" |
| else |
| version="${version#* }" |
| fi |
| bazel build @test//:test >& $TEST_log || fail "Failed to build" |
| expect_log ": ${version}." |
| } |
| |
| function tear_down() { |
| shutdown_server |
| true |
| } |
| |
| run_suite "local repository tests" |