| #!/usr/bin/env bash | |
| # Bazelisk looks for this file, and runs it in place of the Bazel command if present. | |
| # See https://github.com/bazelbuild/bazelisk/blob/master/README.md#other-features | |
| # This gives us a place to create a custom environment for Bazel to run in. | |
| set -eu | |
| BOLD=$([ -t 0 ] && tput bold || echo "") | |
| RED=$([ -t 0 ] && tput setaf 1 || echo "") | |
| GREEN=$([ -t 0 ] && tput setaf 2 || echo "") | |
| YELLOW=$([ -t 0 ] && tput setaf 3 || echo "") | |
| CL=$([ -t 0 ] && tput sgr0 || echo "") # reset | |
| readonly COMPLETION_SNIPPET_DELIM="bazel-completion" | |
| readonly COMPLETION_SNIPPET_BEGIN_DELIM="# BEGIN-${COMPLETION_SNIPPET_DELIM}" | |
| readonly COMPLETION_SNIPPET_END_DELIM="# END-${COMPLETION_SNIPPET_DELIM}" | |
| ARGS=( "$@" ) | |
| TARGETS_AND_FLAGS=( "${ARGS[@]:1}" ) | |
| TARGETS=( "${TARGETS_AND_FLAGS[@]%%-*}" ) | |
| print_help() { | |
| VERB=${1} | |
| DESC=${2} | |
| LENGTH=${#VERB} | |
| while [[ ${LENGTH} -lt 20 ]]; do | |
| VERB="${VERB} " | |
| LENGTH=${#VERB} | |
| done | |
| echo " ${VERB}${DESC}" | |
| } | |
| ####################################### | |
| # Modify an rcfile with a snippet without duplication. | |
| # | |
| # Globals: | |
| # COMPLETION_SNIPPET_BEGIN_DELIM | |
| # COMPLETION_SNIPPET_END_DELIM | |
| # Arguments: | |
| # RCFILE - the rcfile to modify | |
| # SNIPPET_TMP - a file containing the snippet to append to RCFILE | |
| ####################################### | |
| append_to_rcfile() { | |
| RCFILE="${1}" | |
| SNIPPET_TMP="${2}" | |
| RCFILE_TMP=$(mktemp) | |
| PATTERN_TMP=$(mktemp) | |
| echo "/^${COMPLETION_SNIPPET_BEGIN_DELIM}/,/^${COMPLETION_SNIPPET_END_DELIM}/{next}1" > "${PATTERN_TMP}" | |
| awk -f "${PATTERN_TMP}" "$RCFILE" > "${RCFILE_TMP}" | |
| cat "${SNIPPET_TMP}" >> "${RCFILE_TMP}" | |
| cp "${RCFILE_TMP}" "${RCFILE}" | |
| rm "${PATTERN_TMP}" "${SNIPPET_TMP}" "${RCFILE_TMP}" | |
| echo -e "${YELLOW}Completion snippet added to ${RCFILE}${CL}" | |
| } | |
| ####################################### | |
| # Configure autocompletion for bazel. | |
| # Optimistically tries to configure for both zsh and bash. | |
| # | |
| # Globals: | |
| # HOME | |
| # COMPLETION_SNIPPET_BEGIN_DELIM | |
| # COMPLETION_SNIPPET_END_DELIM | |
| # Arguments: | |
| # None | |
| ####################################### | |
| configure_bazel_autocompletion() { | |
| readonly ZSHRC="${HOME}/.zshrc" | |
| readonly BASH_PROFILE="${HOME}/.bash_profile" | |
| readonly WORKSPACE_DIR=$(bazel info workspace --ui_event_filters=-INFO) | |
| DID_CONFIGURE="none" | |
| ## | |
| ## Zsh | |
| ## | |
| if [[ -f "${ZSHRC}" ]]; then | |
| readonly ZSH_COMPLETION_SCRIPT="${WORKSPACE_DIR}/bazel/completion/zsh/_bazel" | |
| readonly ZSH_SNIPPET_TMP=$(mktemp) | |
| mkdir -p "${HOME}/.zsh/completion/" | |
| cp "${ZSH_COMPLETION_SCRIPT}" "${HOME}/.zsh/completion/" | |
| cat << EOF >> "${ZSH_SNIPPET_TMP}" | |
| ${COMPLETION_SNIPPET_BEGIN_DELIM} | |
| autoload -U +X compinit && compinit | |
| zstyle ':completion:*' use-cache on | |
| zstyle ':completion:*' cache-path ~/.zsh/cache | |
| fpath[1,0]=~/.zsh/completion/ | |
| ${COMPLETION_SNIPPET_END_DELIM} | |
| EOF | |
| append_to_rcfile "${ZSHRC}" "${ZSH_SNIPPET_TMP}" | |
| DID_CONFIGURE="zsh" | |
| fi | |
| ## | |
| ## Bash | |
| ## | |
| if [[ -f "${BASH_PROFILE}" ]]; then | |
| readonly BASH_COMPLETION_SCRIPT="${WORKSPACE_DIR}/bazel/completion/bash/bazel.bash" | |
| readonly BASH_SNIPPET_TMP=$(mktemp) | |
| cat << EOF >> "${BASH_SNIPPET_TMP}" | |
| ${COMPLETION_SNIPPET_BEGIN_DELIM} | |
| if [ -f "${BASH_COMPLETION_SCRIPT}" ]; then | |
| source "${BASH_COMPLETION_SCRIPT}" | |
| fi | |
| ${COMPLETION_SNIPPET_END_DELIM} | |
| EOF | |
| append_to_rcfile "${BASH_PROFILE}" "${BASH_SNIPPET_TMP}" | |
| DID_CONFIGURE="bash" | |
| fi | |
| if [[ "${DID_CONFIGURE}" == "none" ]]; then | |
| echo -e "${RED}Completion setup was expecting to find ${BASH_PROFILE} or ${ZSHRC}${CL}." | |
| echo -e "${YELLOW}Please contact the #bazel slack channel for help.${CL}" | |
| exit 1 | |
| fi | |
| echo -e "${GREEN}Bazel completion should now be available (in a new terminal) 🎉${CL}" | |
| } | |
| case "${ARGS[0]}" in | |
| "completion") | |
| if [ ! -x ${TARGETS+x} ]; then | |
| echo -e "${RED}ERROR${CL}: 'bazel completion' does not take any arguments." | |
| exit 1 | |
| fi | |
| configure_bazel_autocompletion | |
| ;; | |
| "outputs") | |
| if [ -x ${TARGETS+x} ]; then | |
| echo -e "${RED}ERROR${CL} Requested an empty set of targets\nUsage: 'bazel outputs <targets>'" | |
| exit 1 | |
| fi | |
| echo -e "Querying for outputs for ${TARGETS[*]}\n" | |
| for T in "${TARGETS[@]}"; do | |
| OUTS=$(${BAZEL_REAL} aquery "${T}" --include_commandline=false --output jsonproto 2> /dev/null |\ | |
| jq --raw-output '((.actions[]?.outputIds)[] as $ids | (.artifacts[] | select(.id | IN( $ids )))) as $art | $art.execPath') | |
| echo "${BOLD}${T}${CL}:" | |
| if [ -x ${OUTS+x} ]; then | |
| echo -e "\t${YELLOW}No outputs${CL}" | |
| else | |
| printf "\t${GREEN}%s${CL}\n" "${OUTS[@]}" | |
| fi | |
| done | |
| ;; | |
| "help" | "--help") | |
| ${BAZEL_REAL} "$@" | |
| if [[ "${#ARGS[@]}" -eq 1 ]]; then | |
| echo -e "\nCustom commands:" | |
| print_help "outputs" "Prints the output paths to any artifacts that are created when requesting a build" | |
| print_help "completion" "Configures bazel CLI autocompletion for ~/.zshrc and/or ~/.bash_profile." | |
| fi | |
| ;; | |
| *) | |
| exec -a bazel "${BAZEL_REAL}" "$@" | |
| esac |