#!/bin/bash # # Copyright 2018 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 legitimate path assumptions when working with external repositories. # # Load the test setup defined in the parent directory CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${CURRENT_DIR}/../integration_test_setup.sh" \ || { echo "integration_test_setup.sh not found!" >&2; exit 1; } source "${CURRENT_DIR}/remote_helpers.sh" \ || { echo "remote_helpers.sh not found!" >&2; exit 1; } repo_with_local_include() { # Generate a repository, in the current working directory, with a target # //src:hello that includes a file via a local path. touch WORKSPACE mkdir src cat > src/main.c <<'EOF' #include #include "src/consts/greeting.h" int main(int argc, char **argv) { printf("%s\n", GREETING); return 0; } EOF mkdir src/consts cat > src/consts/greeting.h <<'EOF' #define GREETING "Hello World" EOF cat > src/BUILD <<'EOF' cc_binary( name="hello", srcs=["main.c", "consts/greeting.h"], ) EOF } library_with_local_include() { # Generates a repository, in the current directory, where a target //lib:hello # is a library with headers that include via paths relative to the root of # that repository touch WORKSPACE mkdir lib cat > lib/lib.h <<'EOF' #include "lib/constants.h" int greet(char *); EOF cat > lib/constants.h <<'EOF' #define TARGET "World" EOF cat > lib/lib.c <<'EOF' int greet(char *s) { printf("Hello %s\n", s); return 0; } EOF cat > lib/BUILD < WORKSPACE < main.c <<'EOF' #include "lib/lib.h" int main(int argc, char **argv) { greet(TARGET); return 0; } EOF cat > BUILD <<'EOF' cc_binary( name="hello", srcs=["main.c"], deps=["//lib:lib"], ) EOF bazel build //:hello || fail "Expected build to succeed" bazel run //:hello | grep 'Hello World' \ || fail "Expected output 'Hello World'" } test_lib_paths_remote() { # Verify that libaries from an external repository can be used via include # path relative to their repository root and that they may refer to other # truely source files from the same libary via paths relative to their # repository root. WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir remote (cd remote && library_with_local_include) tar cvf remote.tar remote rm -rf remote mkdir main cd main cat > WORKSPACE < main.c <<'EOF' #include "lib/lib.h" int main(int argc, char **argv) { greet(TARGET); return 0; } EOF cat > BUILD <<'EOF' cc_binary( name="hello", srcs=["main.c"], deps=["@remote//lib:lib"], ) EOF bazel build //:hello || fail "Expected build to succeed" bazel run //:hello | grep 'Hello World' \ || fail "Expected output 'Hello World'" } test_lib_paths_all_remote() { # Verify that libaries from an external repository can be used by another # external repository via include path relative to their repository root and # that they may refer to other truely source files from the same libary via # paths relative to their repository root. WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir remotelib (cd remotelib && library_with_local_include) tar cvf remotelib.tar remotelib rm -rf remotelib mkdir remotemain (cd remotemain cat > main.c <<'EOF' #include "lib/lib.h" int main(int argc, char **argv) { greet(TARGET); return 0; } EOF cat > BUILD <<'EOF' cc_binary( name="hello", srcs=["main.c"], deps=["@remotelib//lib:lib"], ) EOF ) tar cvf remotemain.tar remotemain rm -rf remotemain mkdir main cd main cat > WORKSPACE < withpath/BUILD <<'EOF' genrule( name = "it", srcs = ["double.sh", "data.txt"], outs = ["it.txt"], cmd = "sh $(location double.sh) > $@", visibility = ["//visibility:public"], ) EOF cat > withpath/double.sh <<'EOF' #!/bin/sh cat withpath/data.txt withpath/data.txt EOF cat > withpath/data.txt <<'EOF' Hello world EOF } test_fixed_path_local() { # Verify that hard-coded path relative to the repository root can # be used in internal targets. WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir main cd main touch WORKSPACE repo_with_local_path_reference bazel build //withpath:it || fail "Expected success" } # TODO(aehlig): enable, once our execroot change is far enough # to make this (desirbale) property true. DISABLED_test_fixed_path_remote() { WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir remote (cd remote && repo_with_local_path_reference) tar cvf remote.tar remote rm -rf remote mkdir main cd main cat > WORKSPACE < rule/BUILD <<'EOF' exports_files(["to_upper.sh"]) EOF cat > rule/to_upper.sh <<'EOF' cat $1 | tr 'a-z' 'A-Z' > $2 EOF cat > rule/to_upper.bzl <<'EOF' def _to_upper_impl(ctx): output = ctx.new_file(ctx.label.name + ".txt") ctx.action( inputs = ctx.files.src + ctx.files._toupper_sh, outputs = [output], command = ["/bin/sh"] + [f.path for f in ctx.files._toupper_sh] \ + [f.path for f in ctx.files.src] + [output.path], use_default_shell_env = True, mnemonic = "ToUpper", progress_message = "Uppercasing %s" % ctx.label, ) to_upper = rule( implementation = _to_upper_impl, attrs = { "src" : attr.label(allow_files=True), "_toupper_sh" : attr.label(cfg="host", allow_files=True, default = Label("//rule:to_upper.sh")), }, outputs = {"upper": "%{name}.txt"}, ) EOF } test_local_rules() { WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir main cd main touch WORKSPACE repo_with_local_implicit_dependencies mkdir call echo hello world > call/hello.txt cat > call/BUILD <<'EOF' load("//rule:to_upper.bzl", "to_upper") to_upper( name = "upper_hello", src = "hello.txt" ) EOF bazel build -s //call:upper_hello || fail "Expected success" cat `bazel info bazel-bin`/call/upper_hello.txt | grep 'HELLO WORLD' \ || fail "not the expected output" } test_remote_rules() { WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir remote (cd remote && repo_with_local_implicit_dependencies) tar cvf remote.tar remote rm -rf remote mkdir main cd main cat > WORKSPACE < call/hello.txt cat > call/BUILD <<'EOF' load("@r//rule:to_upper.bzl", "to_upper") to_upper( name = "upper_hello", src = "hello.txt" ) EOF bazel build -s //call:upper_hello || fail "Expected success" cat `bazel info bazel-bin`/call/upper_hello.txt | grep 'HELLO WORLD' \ || fail "not the expected output" } test_remote_remote_rules() { WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir a (cd a && repo_with_local_implicit_dependencies) tar cvf a.tar a rm -rf a mkdir b (cd b mkdir call echo hello world > call/hello.txt cat > call/BUILD <<'EOF' load("@a//rule:to_upper.bzl", "to_upper") to_upper( name = "upper_hello", src = "hello.txt" ) EOF ) tar cvf b.tar b rm -rf b mkdir main cd main cat > WORKSPACE < rule/preamb.html <<'EOF'
EOF
  cat > rule/postamb.html <<'EOF'
EOF cat > rule/BUILD <<'EOF' exports_files(["preamb.html", "postamb.html"], visibility = ["//visibility:public"]) genrule( name = "to_html", outs = ["to_html.sh"], srcs = [":preamb.html", ":postamb.html"], # the output actually does not depend on those files cmd = "echo '#!/bin/sh' > $@; echo 'cat $(location :preamb.html) $$1 $(location :postamb.html) > $$2' >> $@", visibility = ["//visibility:public"], ) EOF cat > rule/to_html.bzl <<'EOF' def _to_html_impl(ctx): output = ctx.new_file(ctx.label.name + ".html") ctx.action( inputs = ctx.files.src + ctx.files._to_html + ctx.files._preamb + ctx.files._postamb, outputs = [output], command = ["/bin/sh"] + [f.path for f in ctx.files._to_html] \ + [f.path for f in ctx.files.src] + [output.path], use_default_shell_env = True, mnemonic = "ToHtml", progress_message = "htmlifying %s" % ctx.label, ) to_html = rule( implementation = _to_html_impl, attrs = { "src" : attr.label(allow_files=True), "_to_html" : attr.label(cfg="host", allow_files=True, default = Label("//rule:to_html")), # knowledge of which paths are embedded is duplicated here! "_preamb" : attr.label(cfg="host", allow_files=True, default = Label("//rule:preamb.html")), "_postamb" : attr.label(cfg="host", allow_files=True, default = Label("//rule:postamb.html")), }, outputs = {"upper": "%{name}.html"}, ) EOF } test_embedded_local() { # Verify that files with embedded paths can be used locally. WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir main touch WORKSPACE repo_with_embedded_paths mkdir call cat > call/plain.txt <<'EOF' Hello World! EOF cat > call/BUILD <<'EOF' load('//rule:to_html.bzl', 'to_html') to_html(name="hello", src="plain.txt") EOF bazel build -s //call:hello || fail 'Expected success' cat `bazel info bazel-bin`/call/hello.html | grep '' \ || fail "not the expected output" cat `bazel info bazel-bin`/call/hello.html | grep '' \ || fail "not the expected output" } test_embedded_remote() { # Verify that files with embedded paths can be used if coming # from an external repository. WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir remote (cd remote && repo_with_embedded_paths) tar cvf remote.tar remote rm -rf remote mkdir main cd main cat > WORKSPACE < call/plain.txt <<'EOF' Hello World! EOF cat > call/BUILD <<'EOF' load('@r//rule:to_html.bzl', 'to_html') to_html(name="hello", src="plain.txt") EOF bazel build -s //call:hello || fail 'Expected success' cat `bazel info bazel-bin`/call/hello.html | grep '' \ || fail "not the expected output" cat `bazel info bazel-bin`/call/hello.html | grep '' \ || fail "not the expected output" } test_embedded_remote_remote() { # Verify that files with embedded path can be used by a remote # repository if coming from an external repository. WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir r (cd r && repo_with_embedded_paths) tar cvf r.tar r rm -rf r mkdir b (cd b mkdir call cat > call/plain.txt <<'EOF' Hello World! EOF cat > call/BUILD <<'EOF' load('@r//rule:to_html.bzl', 'to_html') to_html(name="hello", src="plain.txt") EOF ) tar cvf b.tar b rm -rf b mkdir main cd main cat > WORKSPACE < rule/BUILD <<'EOF' genrule( name = "add_preamb", outs = ["add_preamb.sh"], srcs = ["@data//:file.txt"], # the output actually does not depend on the contents of those files cmd = " echo '#!/bin/sh' > $@; echo 'cat $(location @data//:file.txt) $$1 > $$2' >> $@", visibility = ["//visibility:public"], ) EOF cat > rule/add_preamb.bzl <<'EOF' def _add_preamb_impl(ctx): output = ctx.new_file(ctx.label.name + ".txt") ctx.action( inputs = ctx.files.src + ctx.files._add_preamb + ctx.files._preamb, outputs = [output], command = ["/bin/sh"] + [f.path for f in ctx.files._add_preamb] \ + [f.path for f in ctx.files.src] + [output.path], use_default_shell_env = True, mnemonic = "AddPreamb", progress_message = "Add preamble to %s" % ctx.label, ) add_preamb = rule( implementation = _add_preamb_impl, attrs = { "src" : attr.label(allow_files=True), "_add_preamb" : attr.label(cfg="host", allow_files=True, default = Label("//rule:add_preamb")), # knowledge of which paths are embedded is duplicated here! "_preamb" : attr.label(cfg="host", allow_files=True, default = Label("@data//:file.txt")), }, outputs = {"with_preamb": "%{name}.txt"}, ) EOF } repo_data_file() { # Create, in the current directory, an archive of a data repository containing # //:file.txt, and add a corresponding entry to ./main/WORKSPACE. mkdir data cat > data/file.txt <<'EOF' Copyright ... EOF cat > data/BUILD <<'EOF' exports_files(["file.txt"], visibility = ["//visibility:public"]) EOF tar cvf data.tar data rm -rf data cat >> main/WORKSPACE < foo.txt cat > BUILD <<'EOF' load('//rule:add_preamb.bzl', 'add_preamb') add_preamb(name='main', src='foo.txt') EOF bazel build -s //:main || fail 'Expected success' cat `bazel info bazel-bin`/main.txt | grep 'world' \ || fail "not the expected output" cat `bazel info bazel-bin`/main.txt | grep 'Copyright' \ || fail "not the expected output" } test_embedded_foreign_paths_remote() { # Verify that a rule in a local repository can embed a path to a foreigh # repository WRKDIR=$(mktemp -d "${TEST_TMPDIR}/testXXXXXX") cd "${WRKDIR}" mkdir main repo_data_file mkdir rule (cd rule && repo_with_embedded_foreign_path) tar cvf rule.tar rule rm -rf rule cat >> main/WORKSPACE < foo.txt cat > BUILD <<'EOF' load('@rule//rule:add_preamb.bzl', 'add_preamb') add_preamb(name='main', src='foo.txt') EOF bazel build -s //:main || fail 'Expected success' cat `bazel info bazel-bin`/main.txt | grep 'world' \ || fail "not the expected output" cat `bazel info bazel-bin`/main.txt | grep 'Copyright' \ || fail "not the expected output" } run_suite "path tests for multiple repositories"