aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/BUILD28
-rwxr-xr-xscripts/bash_completion_test.sh730
-rw-r--r--scripts/bazel-complete-template.bash469
-rwxr-xr-xscripts/testenv.sh33
-rw-r--r--src/BUILD5
5 files changed, 1264 insertions, 1 deletions
diff --git a/scripts/BUILD b/scripts/BUILD
new file mode 100644
index 0000000000..e3892a675f
--- /dev/null
+++ b/scripts/BUILD
@@ -0,0 +1,28 @@
+# Scripts for IDE / Environment support for Bazel
+package(default_visibility = ["//visibility:private"])
+
+# The master copy of the completion logic are bazel-complete-template.bash
+# and bazel-complete-header.bash.
+# This is where you should make edits.
+genrule(
+ name = "bash_completion",
+ srcs = ["bazel-complete-template.bash"],
+ outs = ["bazel-complete.bash"],
+ cmd = "set +x; cat $(SRCS) > $@\n" +
+ "touch WORKSPACE err.log\n" +
+ "trap \"rm WORKSPACE err.log\" EXIT\n" +
+ "$(location //src:bazel) help completion 2>err.log >>$@ || { cat err.log; exit 1; }",
+ output_to_bindir = 1,
+ tools = ["//src:bazel"],
+)
+
+sh_test(
+ name = "bash_completion_test",
+ size = "small",
+ srcs = ["bash_completion_test.sh"],
+ data = [
+ "bazel-complete.bash",
+ "testenv.sh",
+ "//src/test/shell:bashunit",
+ ],
+)
diff --git a/scripts/bash_completion_test.sh b/scripts/bash_completion_test.sh
new file mode 100755
index 0000000000..3d82dbefcc
--- /dev/null
+++ b/scripts/bash_completion_test.sh
@@ -0,0 +1,730 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. 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.
+#
+# bash_completion_test.sh: tests of bash command completion.
+
+: ${DIR:=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}
+source ${DIR}/testenv.sh || { echo "testenv.sh not found!" >&2; exit 1; }
+
+# List of command to test completion for
+: ${COMMAND_ALIASES:=bazel}
+
+# Completion script
+: ${COMPLETION:="$TEST_SRCDIR/scripts/bazel-complete.bash"}
+
+# Set this to test completion with package path (if enabled)
+: ${PACKAGE_PATH_PREFIX:=}
+
+#### UTILITIES #########################################################
+
+# Usage: array_join join_on array
+#
+# Joins all arguments using the first argument as separator
+function array_join {
+ local joiner="$1"
+ shift
+ echo -n "$1"
+ shift
+ for i in "$@"; do
+ echo -n "${joiner}${i}"
+ done
+}
+
+# Usage: expand <terminal-input> <flags> <stderr-file>
+#
+# Prints the string resulting from command expansion after the
+# specified terminal input is typed at the shell. The argument
+# is evaluated using 'echo -e', so \t can be used to invoke
+# command expansion. STDERR output from the call to bash is
+# sent to stderr-file so it can be inspected, if desired.
+#
+# This approach is rather gnarly, but guarantees good test fidelity,
+# unlike "unit test" approaches based on invoking the completion function
+# directly with COMP_WORDS etc defined.
+expand() {
+ local input="$1" flags="$2" stderr_file="$3"
+ {
+ # The flags for blaze autocomplete script.
+ echo "$flags"
+ # This script is already sourced in a normal bash shell, but we need it
+ # for the tests, too.
+ echo "source $COMPLETION"
+ # Tricky! We turn "bazel" into a self-quoting command
+ # that echoes its argument string exactly, spaces and all.
+ # We assume no single-quotes in the input, though.
+ #
+ # Alias expansion still inserts an extra space after 'blaze',
+ # though, hence the following sed. Not sure why.
+ for i in ${COMMAND_ALIASES[@]}; do
+ echo "alias $i=\"echo $i'\""
+ done
+ echo -en "$input'"
+ } | bash --norc -i 2>"$stderr_file" |
+ sed -e 's/^\('"$(array_join "\|" ${COMMAND_ALIASES[@]})"'\) /\1 /'
+}
+
+# Usage: assert_expansion <prefix> <expected-expansion> <optional-flags>
+#
+# For multiple flags separate with semicolon.
+# e.g. assert_expansion 'foo' 'foo_expand' 'flag1=bar;flag2=baz'
+assert_expansion() {
+ local prefix=$1 expected=$2 flags=${3:-}
+ for i in ${COMMAND_ALIASES[@]}; do
+ local nprefix="$i $prefix"
+ local nexpected="$i $expected"
+ assert_equals "$nexpected" "$(expand "$nprefix\t" "$flags" "/dev/null")"
+ done
+}
+
+
+# Usage: assert_expansion_error_not_contains <prefix> <unexpected-error>
+# <optional-flags>
+#
+# For multiple flags separate with semicolon.
+#
+# Asserts that tab-completing after typing the prefix will not result
+# in STDERR receiving a string containing regex unexpected-error.
+assert_expansion_error_not_contains() {
+ local prefix=$1 not_expected=$2 flags=${3:-}
+ local temp_file=$(mktemp -t tmp.stderr.XXXXXX)
+ for i in ${COMMAND_ALIASES[@]}; do
+ local nprefix="$i "
+ expand "$nprefix\t" "$flags" "$temp_file" > /dev/null
+ assert_not_contains "$not_expected" "$temp_file"
+ done
+}
+
+#### FIXTURES ##########################################################
+
+make_empty_packages() {
+ touch video/streamer2/testing/BUILD
+ touch ${PACKAGE_PATH_PREFIX:-}video/streamer2/stuff/BUILD
+ touch video/streamer2/names/BUILD
+}
+
+make_packages() {
+ mkdir -p video/streamer2/testing || fail "mkdir failed"
+ cat >video/streamer2/BUILD <<EOF
+cc_library(name='task_lib', ...)
+cc_library(name='token_bucket', ...)
+cc_library(name='with_special+_,=-.@~chars', ...)
+#cc_library(name='comment_build_target_1old', ...)
+#cc_library(name='comment_build_target_2old', ...)
+cc_library(name='comment_build_target_2new', ...)
+#cc_test(name='token_bucket_t_1old', ...)
+#cc_test(name='token_bucket_t_2old', ...)
+cc_test(name='token_bucket_test', ...)
+cc_binary(name='token_bucket_binary', ...)
+java_binary ( name = 'JavaBinary', ...)
+java_binary (
+ name = 'AnotherJavaBinary'
+ ...
+)
+cc_binary(other='thing', name='pybin', ...)
+genrule(name='checks/thingy', ...)
+#cc_binary(name='comment_run_target_1old', ...)
+#cc_binary(name='comment_run_target_2old', ...)
+cc_binary(name='comment_run_target_2new', ...)
+EOF
+
+ mkdir -p ${PACKAGE_PATH_PREFIX:-}video/streamer2/stuff || fail "mkdir failed"
+ cat >${PACKAGE_PATH_PREFIX:-}video/streamer2/stuff/BUILD <<EOF
+cc_library(name='stuff', ...)
+EOF
+
+ mkdir -p video/streamer2/names || fail "mkdir failed"
+ cat >video/streamer2/names/BUILD <<EOF
+genrule(
+ name = 'foo',
+ cmd = ('name=foo'),
+)
+EOF
+
+ mkdir -p dash || fail "mkdir failed"
+ cat >dash/BUILD <<EOF
+cc_library(
+ name = "mia-bid-multiplier-mixer-module",
+)
+EOF
+
+ mkdir -p video/notapackage
+}
+
+#### UNIT TESTS ########################################################
+
+source ${COMPLETION}
+
+assert_expansion_function() {
+ local ws=${PWD}
+ local function="$1" displacement="$2" type="$3" expected="$4" current="$5"
+ assert_equals "$(echo -e "${expected}")" \
+ "$(eval "_bazel__${function} \"${ws}\" \"${displacement}\" \"${current}\" \"${type}\"")"
+}
+
+test_expand_rules_in_package() {
+ make_packages
+
+ assert_expansion_function "expand_rules_in_package" "" label \
+ "stuff " "//video/streamer2/stuff:"
+ assert_expansion_function "expand_rules_in_package" "" label \
+ 'task_lib ' 'video/streamer2:ta'
+ assert_expansion_function "expand_rules_in_package" "" label \
+ 'with_special+_,=-.@~chars ' 'video/streamer2:with_s'
+
+ # From a different directory
+ assert_expansion_function "expand_rules_in_package" "video/" label \
+ 'task_lib ' 'streamer2:ta'
+ assert_expansion_function "expand_rules_in_package" "video/" label \
+ '' 'video/streamer2:ta'
+ assert_expansion_function "expand_rules_in_package" "video/" label \
+ 'with_special+_,=-.@~chars ' 'streamer2:with_s'
+
+ # label should match test and non-test rules
+ assert_expansion_function "expand_rules_in_package" "" label \
+ 'token_bucket_test \ntoken_bucket_binary ' \
+ 'video/streamer2:token_bucket_'
+ assert_expansion_function "expand_rules_in_package" "" label \
+ 'stuff ' 'video/streamer2/stuff:s'
+ # Test that label does not match commented-out rules.
+ assert_expansion_function "expand_rules_in_package" "" label \
+ '' 'video/streamer2:comment_build_target_1o'
+ assert_expansion_function "expand_rules_in_package" "" label \
+ 'comment_build_target_2new ' 'video/streamer2:comment_build_target_2'
+
+ # Test that 'label-test' expands only test rules.
+ assert_expansion_function "expand_rules_in_package" "" label-test \
+ 'token_bucket_test ' 'video/streamer2:to'
+
+ # Test that 'label-test' does not match commented-out rules.
+ assert_expansion_function "expand_rules_in_package" "" label-test \
+ '' 'video/streamer2:token_bucket_t_1o'
+ assert_expansion_function "expand_rules_in_package" "" label-test \
+ 'token_bucket_test ' 'video/streamer2:token_bucket_t'
+
+ # Test that :all wildcard is expanded when there is more than one
+ # match.
+ #
+ # One match => no :all.
+ assert_expansion_function "expand_rules_in_package" "" label-test \
+ 'token_bucket_test ' 'video/streamer2:'
+ # Multiple matches => :all.
+ assert_expansion_function "expand_rules_in_package" "" label-test \
+ 'all ' 'video/streamer2:a'
+
+ # Test that label-bin expands only non-test binary rules.
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ 'token_bucket_binary ' 'video/streamer2:to'
+
+ # Test that label-bin expands for binary and test rules, but not library
+ # with BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN set.
+ BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN=true \
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ 'token_bucket_test \ntoken_bucket_binary ' 'video/streamer2:to'
+
+ # Test the label-bin expands for test rules, with
+ # BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN set.
+ BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN=1 \
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ 'token_bucket_test ' 'video/streamer2:token_bucket_t'
+
+ # Test that 'label-bin' expands only non-test binary rules when the
+ # BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN is false.
+ BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN=false \
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ 'token_bucket_binary ' 'video/streamer2:to'
+
+ # Test that 'label-bin' does not match commented-out rules.
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ '' 'video/streamer2:comment_run_target_1o'
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ 'comment_run_target_2new ' 'video/streamer2:comment_run_target_2'
+
+ # Test that 'label-bin' expands binaries with spaces in the build rules
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ 'JavaBinary ' 'video/streamer2:J'
+
+ # Test that 'label-bin' expands targets when the name attribute is not first
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ 'pybin ' 'video/streamer2:py'
+
+ # Test that 'label-bin' expands binaries with newlines in the build rules
+ assert_expansion_function "expand_rules_in_package" "" label-bin \
+ 'AnotherJavaBinary ' 'video/streamer2:A'
+
+ # Test that the expansion of rules with 'name=...' strings isn't messed up.
+ assert_expansion_function "expand_rules_in_package" "" label \
+ 'foo ' 'video/streamer2/names:'
+}
+
+test_expand_package_name() {
+ make_packages
+ assert_expansion_function "expand_package_name" "" "" \
+ "//video/streamer2/stuff/\n//video/streamer2/stuff:" \
+ "//video/streamer2/stu"
+ assert_expansion_function "expand_package_name" "" "" \
+ "//video/notapackage/" \
+ "//video/nota"
+
+ assert_expansion_function "expand_package_name" "" "" \
+ "video/streamer2/stuff/\nvideo/streamer2/stuff:" \
+ "video/streamer2/stu"
+ assert_expansion_function "expand_package_name" "" "" \
+ "video/notapackage/" \
+ "video/nota"
+
+ # From another directory
+ assert_expansion_function "expand_package_name" "video/" "" \
+ "" \
+ "video/streamer2/stu"
+ assert_expansion_function "expand_package_name" "video/" "" \
+ "" \
+ "video/nota"
+ assert_expansion_function "expand_package_name" "video/" "" \
+ "streamer2/stuff/\nstreamer2/stuff:" \
+ "streamer2/stu"
+ assert_expansion_function "expand_package_name" "video/" "" \
+ "notapackage/" \
+ "nota"
+
+ # label-package
+ assert_expansion_function "expand_package_name" "" "label-package" \
+ "//video/streamer2/stuff/\n//video/streamer2/stuff " \
+ "//video/streamer2/stu"
+ assert_expansion_function "expand_package_name" "" "label-package" \
+ "//video/notapackage/" \
+ "//video/nota"
+}
+
+test_expand_target_pattern() {
+ make_packages
+ assert_expansion_function "expand_target_pattern" "" label \
+ "stuff " "//video/streamer2/stuff:"
+
+ assert_expansion_function "expand_target_pattern" "" label \
+ "//video/streamer2/stuff/\n//video/streamer2/stuff:" \
+ "//video/streamer2/stu"
+
+ assert_expansion_function "expand_target_pattern" "" label \
+ "stuff " "video/streamer2/stuff:"
+
+ assert_expansion_function "expand_target_pattern" "" label \
+ "video/streamer2/stuff/\nvideo/streamer2/stuff:" \
+ "video/streamer2/stu"
+
+ assert_expansion_function "expand_target_pattern" "video/" label \
+ "stuff " "streamer2/stuff:"
+
+ assert_expansion_function "expand_target_pattern" "video/" label \
+ "streamer2/stuff/\nstreamer2/stuff:" \
+ "streamer2/stu"
+
+ assert_expansion_function "expand_target_pattern" "video/" label \
+ "stuff " "//video/streamer2/stuff:"
+
+ assert_expansion_function "expand_target_pattern" "video/" label \
+ "//video/streamer2/stuff/\n//video/streamer2/stuff:" \
+ "//video/streamer2/stu"
+
+ assert_expansion_function "expand_target_pattern" "video/" label \
+ "" "video/streamer2/stuff:"
+
+ assert_expansion_function "expand_target_pattern" "video/" label \
+ "" "video/streamer2/stu"
+}
+
+test_complete_pattern() {
+ make_packages
+ assert_expansion_function "complete_pattern" "" label \
+ "stuff " "//video/streamer2/stuff:"
+
+ assert_expansion_function "complete_pattern" "" label \
+ "//video/streamer2/stuff/\n//video/streamer2/stuff:" \
+ "//video/streamer2/stu"
+
+ assert_expansion_function "complete_pattern" "" label-package \
+ "//video/streamer2/stuff/\n//video/streamer2/stuff " \
+ "//video/streamer2/stu"
+
+ assert_expansion_function "complete_pattern" "" command \
+ "clean " "clea"
+
+ assert_expansion_function "complete_pattern" "" info-key \
+ "install_base " "install_b"
+
+ assert_expansion_function "complete_pattern" "" '{clean,add}' \
+ "clean " "clea"
+
+ assert_expansion_function "complete_pattern" "" 'command|{abc,def}' \
+ "abc " "ab"
+
+ assert_expansion_function "complete_pattern" "" 'command|{abc,def}' \
+ "clean " "clea"
+
+ # Assert label expansion
+ assert_expansion_function "complete_pattern" "" label \
+ "stuff " "//video/streamer2/stuff:"
+ assert_expansion_function "complete_pattern" "" label \
+ 'task_lib ' 'video/streamer2:ta'
+ assert_expansion_function "complete_pattern" "" label \
+ 'with_special+_,=-.@~chars ' 'video/streamer2:with_s'
+
+ # From a different directory
+ assert_expansion_function "complete_pattern" "video/" label \
+ "stuff " "//video/streamer2/stuff:"
+ assert_expansion_function "complete_pattern" "video/" label \
+ 'task_lib ' 'streamer2:ta'
+ assert_expansion_function "complete_pattern" "video/" label \
+ '' 'video/streamer2:ta'
+ assert_expansion_function "complete_pattern" "video/" label \
+ 'with_special+_,=-.@~chars ' 'streamer2:with_s'
+}
+
+#### TESTS #############################################################
+
+test_basic_subcommand_expansion() {
+ # 'Test basic subcommand completion'
+ assert_expansion 'bui' \
+ 'build '
+ assert_expansion 'hel' \
+ 'help '
+ assert_expansion 'shut' \
+ 'shutdown '
+}
+
+test_common_options() {
+ # 'Test common option completion'
+ assert_expansion '--h' \
+ '--host_jvm_'
+ assert_expansion '--host_jvm_a' \
+ '--host_jvm_args='
+}
+
+test_build_options() {
+ # 'Test build option completion'
+ assert_expansion 'build --keep_g' \
+ 'build --keep_going '
+ assert_expansion 'build --expe' \
+ 'build --experimental_'
+ # ...but 'help' doesn't expand this option:
+ assert_expansion 'help --cros' \
+ 'help --cros'
+ assert_expansion 'build --test_stra' \
+ 'build --test_strategy='
+}
+
+test_query_options() {
+ assert_expansion 'query --out' \
+ 'query --output='
+
+ # Basic label expansion works for query, too.
+ make_packages
+ assert_expansion 'query video/streamer2:ta' \
+ 'query video/streamer2:task_lib '
+ assert_expansion 'query //video/streamer2:ta'\
+ 'query //video/streamer2:task_lib '
+}
+
+test_run_options() {
+ # Should be the same as the build options.
+ # 'Test run option completion'
+ assert_expansion 'run --keep_g' \
+ 'run --keep_going '
+ assert_expansion 'run --expe' \
+ 'run --experimental_'
+}
+
+test_tristate_option() {
+ # 'Test tristate option completion'
+ assert_expansion 'build --nocache_test_result' \
+ 'build --nocache_test_results '
+}
+
+make_dirs() {
+ mkdir -p video/streamer2/testing || fail "mkdir failed"
+ mkdir -p ${PACKAGE_PATH_PREFIX:-}video/streamer2/stuff || fail "mkdir failed"
+ mkdir -p video/streamer2/names || fail "mkdir failed"
+}
+
+
+test_directory_expansion() {
+ # 'Test expansion of directory names, even across package_path'
+
+ make_dirs
+
+ assert_expansion 'build vide' \
+ 'build video/'
+ assert_expansion 'build video/' \
+ 'build video/streamer2/'
+ assert_expansion 'build video/streamer2/t' \
+ 'build video/streamer2/testing/'
+ assert_expansion 'build video/streamer2/s' \
+ 'build video/streamer2/stuff/'
+
+ # Now add BUILD files; it should no longer expand the trailing slashes:
+ make_empty_packages
+
+ assert_expansion 'build video/streamer2/t' \
+ 'build video/streamer2/testing'
+ assert_expansion 'build video/streamer2/s' \
+ 'build video/streamer2/stuff'
+
+ # Use of absolute forms of labels:
+ assert_expansion 'build //vide' \
+ 'build //video/'
+ assert_expansion 'build //video/' \
+ 'build //video/streamer2/'
+ assert_expansion 'build //video/streamer2/t' \
+ 'build //video/streamer2/testing'
+ assert_expansion 'build //video/streamer2/s' \
+ 'build //video/streamer2/stuff'
+}
+
+test_directory_expansion_in_subdir() {
+ # 'Test expansion of directory names, when in a subdir of the workspace.'
+
+ make_dirs
+ cd video 2>/dev/null || exit
+
+ # Use of "video" while in "video" => no match:
+ assert_expansion 'build vide' \
+ 'build vide'
+ assert_expansion 'build video/' \
+ 'build video/'
+ assert_expansion 'build video/streamer2/t' \
+ 'build video/streamer2/t'
+ assert_expansion 'build video/streamer2/s' \
+ 'build video/streamer2/s'
+
+ # Use of "//video" while in "video" => matches absolute:
+ assert_expansion 'build //vide' \
+ 'build //video/'
+ assert_expansion 'build //video/' \
+ 'build //video/streamer2/'
+ assert_expansion 'build //video/streamer2/t' \
+ 'build //video/streamer2/testing/'
+ assert_expansion 'build //video/streamer2/s' \
+ 'build //video/streamer2/stuff/'
+
+ # Use of relative paths => matches
+ assert_expansion 'build streamer2/t' \
+ 'build streamer2/testing/'
+ assert_expansion 'build streamer2/s' \
+ 'build streamer2/stuff/'
+}
+
+test_target_expansion() {
+ # 'Test expansion of target names within packages'
+
+ make_packages
+
+ # TODO(bazel-team): (2009) it would be good to test that "streamer2\t"
+ # yielded a menu of "streamer2:" and "streamer2/", but testing the
+ # terminal output (as opposed to the result of expansion) is
+ # beyond our ability right now.
+
+ assert_expansion 'build video/streamer2:ta' \
+ 'build video/streamer2:task_lib '
+
+ # Special characters
+ assert_expansion 'build video/streamer2:with_s' \
+ 'build video/streamer2:with_special+_,=-.@~chars '
+
+ # Also, that 'bazel build' matches test and non-test rules (lack
+ # of trailing space after match => not unique match).
+ assert_expansion 'build video/streamer2:to' \
+ 'build video/streamer2:token_bucket'
+
+ assert_expansion 'build video/streamer2/s' \
+ 'build video/streamer2/stuff'
+
+ assert_expansion 'build video/streamer2/stuff:s' \
+ 'build video/streamer2/stuff:stuff '
+
+ # Test that 'bazel build' does not match commented-out rules.
+ assert_expansion 'build video/streamer2:comment_build_target_1o' \
+ 'build video/streamer2:comment_build_target_1o'
+
+ assert_expansion 'build video/streamer2:comment_build_target_2' \
+ 'build video/streamer2:comment_build_target_2new '
+
+ # Test that 'bazel test' expands only test rules.
+ assert_expansion 'test video/streamer2:to' \
+ 'test video/streamer2:token_bucket_test '
+
+ # Test that 'blaze test' does not match commented-out rules.
+ assert_expansion 'test video/streamer2:token_bucket_t_1o' \
+ 'test video/streamer2:token_bucket_t_1o'
+
+ assert_expansion 'test video/streamer2:token_bucket_t' \
+ 'test video/streamer2:token_bucket_test '
+
+ assert_expansion_error_not_contains 'test video/streamer2:match' \
+ 'syntax error'
+
+ # Test that :all wildcard is expanded when there is more than one
+ # match.
+ #
+ # One match => no :all.
+ assert_expansion 'test video/streamer2:' \
+ 'test video/streamer2:token_bucket_test '
+ # Multiple matches => :all.
+ assert_expansion 'build video/streamer2:a' \
+ 'build video/streamer2:all '
+
+ # Test that 'bazel run' expands only non-test binary rules.
+ assert_expansion 'run video/streamer2:to' \
+ 'run video/streamer2:token_bucket_binary '
+
+ # Test that 'bazel run' expands for binary and test rules, but not library
+ # with BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN set.
+ assert_expansion 'run video/streamer2:to' \
+ 'run video/streamer2:token_bucket_' \
+ 'BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN=true'
+
+ # Test the 'bazel run' expands for test rules, with
+ # BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN set.
+ assert_expansion 'run video/streamer2:token_bucket_t' \
+ 'run video/streamer2:token_bucket_test ' \
+ 'BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN=1'
+
+ # Test that 'bazel run' expands only non-test binary rules when the
+ # BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN is false.
+ assert_expansion 'run video/streamer2:to' \
+ 'run video/streamer2:token_bucket_binary ' \
+ 'BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN=false'
+
+ # Test that 'bazel run' expands only non-test binary rules when the
+ # BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN is false.
+ assert_expansion 'run video/streamer2:to' \
+ 'run video/streamer2:token_bucket_binary ' \
+ 'BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN=0'
+
+ # Test that 'bazel run' expands only non-test binary rules when the
+ # BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN is invalid.
+ assert_expansion 'run video/streamer2:to' \
+ 'run video/streamer2:token_bucket_binary ' \
+ 'BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN=junk'
+
+ # Test that 'bazel run' expands only non-test binary rules when the
+ # BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN is empty.
+ assert_expansion 'run video/streamer2:to' \
+ 'run video/streamer2:token_bucket_binary ' \
+ 'BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN='
+
+ # Test that 'bazel run' does not match commented-out rules.
+ assert_expansion 'run video/streamer2:comment_run_target_1o' \
+ 'run video/streamer2:comment_run_target_1o'
+
+ assert_expansion 'run video/streamer2:comment_run_target_2' \
+ 'run video/streamer2:comment_run_target_2new '
+
+ # Test that 'bazel run' expands binaries with spaces in the build rules
+ assert_expansion 'run video/streamer2:J' \
+ 'run video/streamer2:JavaBinary '
+
+ # Test that 'bazel run' expands targets when the name attribute is not first
+ assert_expansion 'run video/streamer2:py' \
+ 'run video/streamer2:pybin '
+
+ # Test that 'bazel run' expands binaries with newlines in the build rules
+ assert_expansion 'run video/streamer2:A' \
+ 'run video/streamer2:AnotherJavaBinary '
+
+ # Test that the expansion of rules with 'name=...' strings isn't messed up.
+ assert_expansion 'build video/streamer2/names:' \
+ 'build video/streamer2/names:foo '
+
+ # Test that dashes are matched even when locale isn't C.
+ LC_ALL=en_US.UTF-8 \
+ assert_expansion 'build dash:m' \
+ 'build dash:mia-bid-multiplier-mixer-module '
+}
+
+test_target_expansion_in_subdir() {
+ # 'Test expansion of targets when in a subdir of the workspace.'
+
+ make_packages
+ cd video 2>/dev/null
+
+ # Relative labels:
+ assert_expansion 'build streamer2:ta' \
+ 'build streamer2:task_lib '
+
+ assert_expansion 'build streamer2:to' \
+ 'build streamer2:token_bucket'
+
+ assert_expansion 'build streamer2/s' \
+ 'build streamer2/stuff'
+
+ assert_expansion 'build streamer2/stuff:s' \
+ 'build streamer2/stuff:stuff '
+
+ # (no match)
+ assert_expansion 'build video/streamer2:ta' \
+ 'build video/streamer2:ta'
+
+ # Absolute labels work as usual:
+ assert_expansion 'build //video/streamer2:ta' \
+ 'build //video/streamer2:task_lib '
+}
+
+test_target_expansion_in_package() {
+ # 'Test expansion of targets when in a package.'
+
+ make_packages
+ cd video/streamer2 2>/dev/null
+
+ assert_expansion 'build :ta' \
+ 'build :task_lib '
+
+ assert_expansion 'build :to' \
+ 'build :token_bucket'
+
+ # allow slashes in rule names
+ assert_expansion 'build :checks/th' \
+ 'build :checks/thingy '
+
+ assert_expansion 'build s' \
+ 'build stuff'
+
+ # (no expansion)
+ assert_expansion 'build :s' \
+ 'build :s'
+}
+
+test_help() {
+ # "Test that bazel help expands subcommand names"
+ assert_expansion 'help qu' \
+ 'help query '
+ assert_expansion 'help bui' \
+ 'help build '
+ assert_expansion 'help shut' \
+ 'help shutdown '
+ assert_expansion 'help start' \
+ 'help startup_options '
+}
+
+test_info() {
+ # "Test that bazel info keys are expanded"
+ assert_expansion 'info commi' \
+ 'info committed-heap-size '
+ assert_expansion 'info i' \
+ 'info install_base '
+ assert_expansion 'info --show_m' \
+ 'info --show_make_env '
+}
+
+run_suite "Tests of bash completion of 'blaze' command."
diff --git a/scripts/bazel-complete-template.bash b/scripts/bazel-complete-template.bash
new file mode 100644
index 0000000000..e1df891b89
--- /dev/null
+++ b/scripts/bazel-complete-template.bash
@@ -0,0 +1,469 @@
+# -*- sh -*- (Bash only)
+#
+# Copyright 2015 Google Inc. 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.
+#
+#
+# Bash completion of Bazel commands.
+#
+# The template is expanded at build time using tables of commands/options
+# derived from the bazel executable built in the same client; the expansion is
+# written to bazel-complete.bash.
+#
+# Provides command-completion for:
+# - bazel prefix options (e.g. --host_jvm_args)
+# - blaze command-set (e.g. build, test)
+# - blaze command-specific options (e.g. --copts)
+# - values for enum-valued options
+# - package-names, exploring all package-path roots.
+# - targets within packages.
+
+# The package path used by the completion routines. Unfortunately
+# this isn't necessarily the same as the actual package path used by
+# Bazel, but that's ok. (It's impossible for us to reliably know what
+# the relevant package-path, so this is just a good guess. Users can
+# override it if they want.)
+#
+# Don't use it directly. Generate the final script with
+# bazel build //scripts:bash_completion instead.
+#
+: ${BAZEL_COMPLETION_PACKAGE_PATH:=%workspace%}
+
+
+# If true, Bazel query is used for autocompletion. This is more
+# accurate than the heuristic grep, especially for strangely-formatted
+# BUILD files. But it can be slower, especially if the Bazel server
+# is busy, and more brittle, if the BUILD file contains serious
+# errors. This is an experimental feature.
+: ${BAZEL_COMPLETION_USE_QUERY:=false}
+
+
+# If true, Bazel run allows autocompletion for test targets. This is convenient
+# for users who run a lot of tests/benchmarks locally with blaze run.
+: ${BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN:=false}
+
+# Some commands might interfer with the important one, so don't complete them
+: ${BAZEL_IGNORED_COMMAND_REGEX:="__none__"}
+
+# Bazel command
+: ${BAZEL:=bazel}
+
+# Pattern to match for looking for a target
+# BAZEL_BUILD_MATCH_PATTERN__* give the pattern for label-*
+# when looking in the the build file.
+# BAZEL_QUERY_MATCH_PATTERN__* give the pattern for label-*
+# when using 'bazel query'.
+# _RUNTEST are special case when BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN
+# is on.
+: ${BAZEL_BUILD_MATCH_PATTERN__test:='(.*_test|test_suite)'}
+: ${BAZEL_QUERY_MATCH_PATTERN__test:='(test|test_suite)'}
+: ${BAZEL_BUILD_MATCH_PATTERN__bin:='.*_binary'}
+: ${BAZEL_QUERY_MATCH_PATTERN__bin:='(binary)'}
+: ${BAZEL_BUILD_MATCH_PATTERN_RUNTEST__bin:='(.*_(binary|test)|test_suite)'}
+: ${BAZEL_QUERY_MATCH_PATTERN_RUNTEST__bin:='(binary|test)'}
+: ${BAZEL_BUILD_MATCH_PATTERN__:='.*'}
+: ${BAZEL_QUERY_MATCH_PATTERN__:=''}
+
+# Usage: _bazel__get_rule_match_pattern <command>
+# Determine what kind of rules to match, based on command.
+_bazel__get_rule_match_pattern() {
+ local var_name pattern
+ if _bazel__is_true "$BAZEL_COMPLETION_USE_QUERY"; then
+ var_name="BAZEL_QUERY_MATCH_PATTERN"
+ else
+ var_name="BAZEL_BUILD_MATCH_PATTERN"
+ fi
+ if [[ "$1" =~ ^label-?([a-z]*)$ ]]; then
+ pattern=${BASH_REMATCH[1]:-}
+ if _bazel__is_true "$BAZEL_COMPLETION_ALLOW_TESTS_FOR_RUN"; then
+ eval "echo \"\${${var_name}_RUNTEST__${pattern}:-\$${var_name}__${pattern}}\""
+ else
+ eval "echo \"\$${var_name}__${pattern}\""
+ fi
+ fi
+}
+
+# Compute workspace directory. Search for the innermost
+# enclosing directory with a WORKSPACE file.
+_bazel__get_workspace_path() {
+ local workspace=$PWD
+ while true; do
+ if [ -f "${workspace}/WORKSPACE" ]; then
+ break
+ elif [ -z "$workspace" -o "$workspace" = "/" ]; then
+ workspace=$PWD
+ break;
+ fi
+ workspace=${workspace%/*}
+ done
+ echo $workspace
+}
+
+
+# Find the current piece of the line to complete, but only do word breaks at
+# certain characters. In particular, ignore these: "':=
+# This method also takes into account the current cursor position.
+#
+# Works with both bash 3 and 4! Bash 3 and 4 perform different word breaks when
+# computing the COMP_WORDS array. We need this here because Bazel options are of
+# the form --a=b, and labels of the form //some/label:target.
+_bazel__get_cword() {
+ local cur=${COMP_LINE:0:$COMP_POINT}
+ # This expression finds the last word break character, as defined in the
+ # COMP_WORDBREAKS variable, but without '=' or ':', which is not preceeded by
+ # a slash. Quote characters are also excluded.
+ local wordbreaks="$COMP_WORDBREAKS"
+ wordbreaks="${wordbreaks//\'/}"
+ wordbreaks="${wordbreaks//\"/}"
+ wordbreaks="${wordbreaks//:/}"
+ wordbreaks="${wordbreaks//=/}"
+ local word_start=$(expr "$cur" : '.*[^\]['"${wordbreaks}"']')
+ echo "${cur:$word_start}"
+}
+
+
+# Usage: _bazel__package_path <workspace> <displacement>
+#
+# Prints a list of package-path root directories, displaced using the
+# current displacement from the workspace. All elements have a
+# trailing slash.
+_bazel__package_path() {
+ local workspace=$1 displacement=$2 root
+ IFS=:
+ for root in ${BAZEL_COMPLETION_PACKAGE_PATH//\%workspace\%/$workspace}; do
+ unset IFS
+ echo "$root/$displacement"
+ done
+}
+
+# Usage: _bazel__options_for <command>
+#
+# Prints the set of options for a given Bazel command, e.g. "build".
+_bazel__options_for() {
+ local options
+ if [[ "${BAZEL_COMMAND_LIST}" =~ ^(.* )?$1( .*)?$ ]]; then
+ local option_name=$(echo $1 | perl -ne 'print uc' | tr "-" "_")
+ eval "echo \${BAZEL_COMMAND_${option_name}_FLAGS}" | tr " " "\n"
+ fi
+}
+# Usage: _bazel__expansion_for <command>
+#
+# Prints the completion pattern for a given Bazel command, e.g. "build".
+_bazel__expansion_for() {
+ local options
+ if [[ "${BAZEL_COMMAND_LIST}" =~ ^(.* )?$1( .*)?$ ]]; then
+ local option_name=$(echo $1 | perl -ne 'print uc' | tr "-" "_")
+ eval "echo \${BAZEL_COMMAND_${option_name}_ARGUMENT}"
+ fi
+}
+
+# Usage: _bazel__matching_targets <kind> <prefix>
+#
+# Prints target names of kind <kind> and starting with <prefix> in the BUILD
+# file given as standard input. <kind> is a basic regex (BRE) used to match the
+# bazel rule kind and <prefix> is the prefix of the target name.
+_bazel__matching_targets() {
+ local kind_pattern="$1"
+ local target_prefix="$2"
+ # The following commands do respectively:
+ # Remove BUILD file comments
+ # Replace \n by spaces to have the BUILD file in a single line
+ # Extract all rule types and target names
+ # Grep the kind pattern and the target prefix
+ # Returns the target name
+ sed 's/#.*$//' \
+ | tr "\n" " " \
+ | sed 's/\([a-zA-Z0-9_]*\) *(\([^)]* \)\{0,1\}name *= *['\''"]\([a-zA-Z0-9_/.+=,@~-]*\)['\''"][^)]*)/\
+type:\1 name:\3\
+/g' \
+ | grep -E "^type:$kind_pattern name:$target_prefix" \
+ | cut -d ':' -f 3
+}
+
+
+# Usage: _bazel__is_true <string>
+#
+# Returns true or false based on the input string. The following are
+# valid true values (the rest are false): "1", "true".
+_bazel__is_true() {
+ local str="$1"
+ [[ "$str" == "1" || "$str" == "true" ]]
+}
+
+# Usage: _bazel__expand_rules_in_package <workspace> <displacement>
+# <current> <label-type>
+#
+# Expands rules in specified packages, exploring all roots of
+# $BAZEL_COMPLETION_PACKAGE_PATH, not just $(pwd). Only rules
+# appropriate to the command are printed. Sets $COMPREPLY array to
+# result.
+#
+# If $BAZEL_COMPLETION_USE_QUERY is true, 'bazel query' is used
+# instead, with the actual Bazel package path;
+# $BAZEL_COMPLETION_PACKAGE_PATH is ignored in this case, since the
+# actual Bazel value is likely to be more accurate.
+_bazel__expand_rules_in_package() {
+ local workspace=$1 displacement=$2 current=$3 label_type=$4
+ local package_name=$(echo "$current" | cut -f1 -d:)
+ local rule_prefix=$(echo "$current" | cut -f2 -d:)
+ local root buildfile rule_pattern r result
+
+ result=
+ pattern=$(_bazel__get_rule_match_pattern "$label_type")
+ if _bazel__is_true "$BAZEL_COMPLETION_USE_QUERY"; then
+ package_name=$(echo "$package_name" | tr -d "'\"") # remove quotes
+ result=$(${BAZEL} --output_base=/tmp/${BAZEL}-completion-$USER query \
+ --keep_going --noshow_progress \
+ "kind('$pattern rule', '$package_name:*')" 2>/dev/null |
+ cut -f2 -d: | grep "^$rule_prefix")
+ else
+ for root in $(_bazel__package_path "$workspace" "$displacement"); do
+ buildfile="$root/$package_name/BUILD"
+ if [ -f "$buildfile" ]; then
+ result=$(_bazel__matching_targets \
+ "$pattern" "$rule_prefix" <"$buildfile")
+ break
+ fi
+ done
+ fi
+
+ index=$(echo $result | wc -w)
+ if [ -n "$result" ]; then
+ echo "$result" | tr " " "\n" | sed 's|$| |'
+ fi
+ # Include ":all" wildcard if there was no unique match. (The zero
+ # case is tricky: we need to include "all" in that case since
+ # otherwise we won't expand "a" to "all" in the absence of rules
+ # starting with "a".)
+ if [ $index -ne 1 ] && expr all : "\\($rule_prefix\\)" >/dev/null; then
+ echo "all "
+ fi
+}
+
+# Usage: _bazel__expand_package_name <workspace> <displacement> <current-word>
+# <label-type>
+#
+# Expands directories, but explores all roots of
+# BAZEL_COMPLETION_PACKAGE_PATH, not just $(pwd). When a directory is
+# a bazel package, the completion offers "pkg:" so you can expand
+# inside the package.
+# Sets $COMPREPLY array to result.
+_bazel__expand_package_name() {
+ local workspace=$1 displacement=$2 current=$3 type=${4:-} root dir index
+ for root in $(_bazel__package_path "$workspace" "$displacement"); do
+ found=0
+ for dir in $(compgen -d $root$current); do
+ [ -L "$dir" ] && continue # skip symlinks (e.g. bazel-bin)
+ [[ "$dir" =~ ^(.*/)?\.[^/]*$ ]] && continue # skip dotted dir (e.g. .git)
+ found=1
+ echo "${dir#$root}/"
+ if [ -f $dir/BUILD ]; then
+ if [ "${type}" = "label-package" ]; then
+ echo "${dir#$root} "
+ else
+ echo "${dir#$root}:"
+ fi
+ fi
+ done
+ [ $found -gt 0 ] && break # Stop searching package path upon first match.
+ done
+}
+
+# Usage: _bazel__expand_target_pattern <workspace> <displacement>
+# <word> <label-syntax>
+#
+# Expands "word" to match target patterns, using the current workspace
+# and displacement from it. "command" is used to filter rules.
+# Sets $COMPREPLY array to result.
+_bazel__expand_target_pattern() {
+ local workspace=$1 displacement=$2 current=$3 label_syntax=$4
+ case "$current" in
+ //*:*) # Expand rule names within package, no displacement.
+ if [ "${label_syntax}" = "label-package" ]; then
+ compgen -S " " -W "BUILD" "$(echo current | cut -f ':' -d2)"
+ else
+ _bazel__expand_rules_in_package "$workspace" "" "$current" "$label_syntax"
+ fi
+ ;;
+ *:*) # Expand rule names within package, displaced.
+ if [ "${label_syntax}" = "label-package" ]; then
+ compgen -S " " -W "BUILD" "$(echo current | cut -f ':' -d2)"
+ else
+ _bazel__expand_rules_in_package \
+ "$workspace" "$displacement" "$current" "$label_syntax"
+ fi
+ ;;
+ //*) # Expand filenames using package-path, no displacement
+ _bazel__expand_package_name "$workspace" "" "$current" "$label_syntax"
+ ;;
+ *) # Expand filenames using package-path, displaced.
+ if [ -n "$current" ]; then
+ _bazel__expand_package_name "$workspace" "$displacement" "$current" "$label_syntax"
+ fi
+ ;;
+ esac
+}
+
+_bazel__get_command() {
+ for word in "${COMP_WORDS[@]:1:COMP_CWORD-1}"; do
+ if echo "$BAZEL_COMMAND_LIST" | grep -wsq -e "$word"; then
+ echo $word
+ break
+ fi
+ done
+}
+
+# Returns the displacement to the workspace given in $1
+_bazel__get_displacement() {
+ if [[ "$PWD" =~ ^$1/.*$ ]]; then
+ echo ${PWD##$1/}/
+ fi
+}
+
+
+# Usage: _bazel__complete_pattern <workspace> <displacement> <current>
+# <type>
+#
+# Expand a word according to a type. The currently supported types are:
+# - {a,b,c}: an enum that can take value a, b or c
+# - label: a label of any kind
+# - label-bin: a label to a runnable rule (basically to a _binary rule)
+# - label-test: a label to a test rule
+# - info-key: an info key as listed by `bazel help info-keys`
+# - command: the name of a command
+# - path: a file path
+# - combinaison of previous type using | as separator
+_bazel__complete_pattern() {
+ local workspace=$1 displacement=$2 current=$3 types=$4
+ for type in $(echo $types | tr "|" "\n"); do
+ case "$type" in
+ label*)
+ _bazel__expand_target_pattern "$workspace" "$displacement" \
+ "$current" "$type"
+ ;;
+ info-key)
+ compgen -S " " -W "${BAZEL_INFO_KEYS}" -- "$current"
+ ;;
+ "command")
+ local commands=$(echo "${BAZEL_COMMAND_LIST}" \
+ | tr " " "\n" | grep -v "^${BAZEL_IGNORED_COMMAND_REGEX}$")
+ compgen -S " " -W "${commands}" -- "$current"
+ ;;
+ path)
+ compgen -f -- "$current"
+ ;;
+ *)
+ compgen -S " " -W "$type" -- "$current"
+ ;;
+ esac
+ done
+}
+
+# Usage: _bazel__expand_options <workspace> <displacement> <current-word>
+# <options>
+#
+# Expands options, making sure that if current-word contains an equals sign,
+# it is handled appropriately.
+_bazel__expand_options() {
+ local workspace="$1" displacement="$2" cur="$3" options="$4"
+ if [[ $cur =~ = ]]; then
+ # also expands special labels
+ current=$(echo "$cur" | cut -f2 -d=)
+ _bazel__complete_pattern "$workspace" "$displacement" "$current" \
+ "$(compgen -W "$options" -- "$cur" | cut -f2 -d=)" \
+ | sort -u
+ else
+ compgen -W "$(echo "$options" | sed 's|=.*$|=|')" -- "$cur" \
+ | sed 's|\([^=]\)$|\1 |'
+ fi
+}
+
+
+_bazel__complete_stdout() {
+ local cur=$(_bazel__get_cword) word command displacement workspace
+
+ # Determine command: "" (startup-options) or one of $BAZEL_COMMAND_LIST.
+ command="$(_bazel__get_command)"
+
+ workspace="$(_bazel__get_workspace_path)"
+ displacement="$(_bazel__get_displacement ${workspace})"
+
+ case "$command" in
+ "") # Expand startup-options or commands
+ local commands=$(echo "${BAZEL_COMMAND_LIST}" \
+ | tr " " "\n" | grep -v "^${BAZEL_IGNORED_COMMAND_REGEX}$")
+ _bazel__expand_options "$workspace" "$displacement" "$cur" \
+ "${commands}\
+ ${BAZEL_STARTUP_OPTIONS}"
+ ;;
+
+ *)
+ case "$cur" in
+ -*) # Expand options:
+ _bazel__expand_options "$workspace" "$displacement" "$cur" \
+ "$(_bazel__options_for $command)"
+ ;;
+ *) # Expand target pattern
+ expansion_pattern="$(_bazel__expansion_for $command)"
+ NON_QUOTE_REGEX="^[\"']"
+ if [[ $command = query && $cur =~ $NON_QUOTE_REGEX ]]; then
+ : # Ideally we would expand query expressions---it's not
+ # that hard, conceptually---but readline is just too
+ # damn complex when it comes to quotation. Instead,
+ # for query, we just expand target patterns, unless
+ # the first char is a quote.
+ elif [ -n "$expansion_pattern" ]; then
+ _bazel__complete_pattern \
+ "$workspace" "$displacement" "$cur" "$expansion_pattern"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+}
+
+_bazel__to_compreply() {
+ local replies="$1"
+ COMPREPLY=()
+ # Trick to preserve whitespaces
+ while IFS="" read -r reply; do
+ COMPREPLY+=("${reply}")
+ done < <(echo "${replies}")
+}
+
+_bazel__complete() {
+ _bazel__to_compreply "$(_bazel__complete_stdout)"
+}
+
+# Some users have aliases such as bt="bazel test" or bb="bazel build", this
+# completion function allows them to have auto-completion for these aliases.
+_bazel__complete_target_stdout() {
+ local cur=$(_bazel__get_cword) word command displacement workspace
+
+ # Determine command: "" (startup-options) or one of $BAZEL_COMMAND_LIST.
+ command="$1"
+
+ workspace="$(_bazel__get_workspace_path)"
+ displacement="$(_bazel__get_displacement ${workspace})"
+
+ _bazel__to_compreply "$(_bazel__expand_target_pattern "$workspace" "$displacement" \
+ "$cur" "$command")"
+}
+
+# default completion for bazel
+complete -F _bazel__complete -o nospace "${BAZEL}"
+
+########################################################################
+## DO NOT EDIT BELOW THIS LINE.
+## This section is automatically generated by update-completion.sh.
diff --git a/scripts/testenv.sh b/scripts/testenv.sh
new file mode 100755
index 0000000000..42ee15381a
--- /dev/null
+++ b/scripts/testenv.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. 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.
+#
+# Setting up the environment for Bazel completion script test
+
+[ -z "$TEST_SRCDIR" ] && { echo "TEST_SRCDIR not set!" >&2; exit 1; }
+
+# Load the unit-testing framework
+source "${TEST_SRCDIR}/src/test/shell/unittest.bash" || \
+ { echo "Failed to source unittest.bash" >&2; exit 1; }
+
+set_up() {
+ mkdir -p $TEST_TMPDIR/workspace
+ cd $TEST_TMPDIR/workspace
+ touch $TEST_TMPDIR/workspace/WORKSPACE
+}
+
+tear_down() {
+ rm -fr $TEST_TMPDIR/workspace/*
+}
diff --git a/src/BUILD b/src/BUILD
index 3149a45027..167799556c 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -80,7 +80,10 @@ genrule(
cmd = "cat $(location //src/main/cpp:client) package-zip > $@ && zip -qA $@",
executable = 1,
output_to_bindir = 1,
- visibility = ["//src/test:__subpackages__"], # For integration tests
+ visibility = [
+ "//scripts:__pkg__", # For bash completion generation
+ "//src/test:__subpackages__", # For integration tests
+ ],
)
filegroup(