blob: 2e366f0ca2feb874cc9c59b1d6c8ba1114f3f53b [file] [log] [blame]
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
## usage: . scripts/fx-env.sh [--bash-build-completions]
##
## optional arguments:
## --bash-build-completion Enables BASH completion support for the `fx build`
## command. See //scripts/gn_complete/README.md for
## other requirements.
### NOTE!
###
### This is not a normal shell script that executes on its own.
###
### It's evaluated directly in a user's interactive shell using
### the `.` or `source` shell built-in.
###
### Hence, this code must be careful not to pollute the user's shell
### with variable or function symbols that users don't want.
function __fx_env_main() {
local bash_build_completion=false
while [[ $# -ne 0 ]]; do
case "$1" in
--bash-build-completion)
bash_build_completion=true
;;
*)
echo -e >&2 "ERROR: Unknown argument \"$1\""
return 1
;;
esac
shift
done
if [[ -n "${ZSH_VERSION}" ]]; then
export FUCHSIA_DIR="$(cd "$(dirname "${(%):-%x}")/.." >/dev/null 2>&1 && pwd)"
else
export FUCHSIA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." >/dev/null 2>&1 && pwd)"
fi
# __patched_path <old-regex> <new-component>
# Prints a new path value based on the current $PATH, removing path components
# that match <old-regex> and adding <new-component> to the end.
function __patched_path {
local old_regex="$1"
local new_component="$2"
local stripped
# Put each PATH component on a line, delete any lines that match the regex,
# then glue back together with ':' characters.
stripped="$(
set -o pipefail &&
echo "${PATH}" |
tr ':' '\n' |
grep -v -E "^${old_regex}$" |
tr '\n' ':'
)"
# The trailing newline will have become a colon, so no need to add another
# one here.
echo "${stripped}${new_component}"
}
### fx-update-path: add useful tools to the PATH
# Add tools to path, removing prior tools directory if any. This also
# matches the Zircon tools directory added by zset, so add it back too.
function fx-update-path {
local jiri_bin_dir="${FUCHSIA_DIR}/.jiri_root/bin"
export PATH="$(__patched_path "${jiri_bin_dir}" "${jiri_bin_dir}")"
export PATH="$(__patched_path "${FUCHSIA_DIR}/scripts/git" "${FUCHSIA_DIR}/scripts/git")"
local rust_dir="$(source "${FUCHSIA_DIR}/tools/devshell/lib/vars.sh" && echo -n "${PREBUILT_RUST_DIR}/bin")"
export PATH="$(__patched_path "${rust_dir}" "${rust_dir}")"
# XXX(raggi): these can get stale, so this really needs rework. Probably the
# only way to handle this more correctly is to wrap fx in a function that
# re-runs fx-update-path whenever `fx set` or `fx use` succeed.
local fuchsia_tools_dir="$(fx-config-read 2>/dev/null; echo "${FUCHSIA_BUILD_DIR}/tools")"
local zircon_tools_dir="$(fx-config-read 2>/dev/null; echo "${ZIRCON_TOOLS_DIR}")"
if [[ -n "${fuchsia_tools_dir}" ]]; then
export PATH="$(__patched_path \
"${FUCHSIA_OUT_DIR}/[^/]*/tools" \
"${fuchsia_tools_dir}")"
fi
if [[ -n "${zircon_tools_dir}" ]]; then
export PATH="$(__patched_path \
"${FUCHSIA_OUT_DIR}/[^/]*/tools" \
"${zircon_tools_dir}")"
fi
}
### fx-prompt-info: prints the current configuration for display in a prompt
function fx-prompt-info {
if [[ ${PWD}/ = ${FUCHSIA_DIR}/* ]]; then
# Run in a subshell to avoid polluting this shell's environment with data
# from the config file, which can change without updating this shell's
# environment.
(
source "${FUCHSIA_DIR}/tools/devshell/lib/vars.sh"
if fx-build-dir-if-present; then
echo "${FUCHSIA_BUILD_DIR##*/}"
else
echo "???"
fi
)
fi
}
### fx-set-prompt: displays the current configuration in the prompt
function fx-set-prompt {
if [[ -n "${ZSH_VERSION}" ]]; then
autoload -Uz colors && colors
setopt PROMPT_SUBST
export PS1='%B%F{yellow}[$(fx-prompt-info)] %B%F{blue}%m:%~%#%f%b '
export PS2='%B%F{blue}>%f%b '
else
export PS1='\[\e[0;1;33m\][$(fx-prompt-info)] \[\e[34m\]\h:\w\\$\[\e[0m\] '
export PS2='\[\e[0;1;34m\]>\[\e[0m\] '
fi
}
### fd: navigate to directories with autocomplete
# $ fd --help # for usage.
function fd {
local fd_python
local dest
fd_python="${FUCHSIA_DIR}/scripts/fd.py"
dest=$(eval ${fd_python} "$@")
cd -- "${dest}"
}
if [[ -z "${ZSH_VERSION}" ]]; then
function __fd {
local cur
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ ${cur:0:2} == "//" ]]; then
COMPREPLY=($(/bin/ls -dp1 ${FUCHSIA_DIR}/${cur}* 2>/dev/null | \
sed -n "s|^${FUCHSIA_DIR}/\(.*/\)\$|\1|p" | xargs echo))
else
COMPREPLY=($(/bin/ls -dp1 ${cur}* 2>/dev/null | grep "/$" | xargs echo))
fi
}
complete -o nospace -F __fd fd
fi
### fx-go: alias of fd, for backward compatibility
function fx-go {
echo "fx-go is to be deprecated in Q1 2018 in favor of 'fd'. For more help, fd --help"
fd "$@"
}
# Support command-line auto-completions for the fx command.
if [[ -z "${ZSH_VERSION}" ]]; then
function __fx_complete_cmd {
local cmd cur prev
cmd="${COMP_WORDS[1]}"
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
case "${cmd}" in
set)
if [[ ${COMP_CWORD} -eq 2 ]]; then
__fx_set_compreply_for_product_board "${cur}"
return
fi
;;
vendor)
if [[ ${COMP_CWORD} -eq 2 ]]; then
# return only vendors that have vendor/*/scripts/devshell/*
COMPREPLY=()
for v in "${FUCHSIA_DIR}"/vendor/"${cur}"*/scripts/devshell; do
v=${v##"${FUCHSIA_DIR}/vendor/"}
v=${v%%"/scripts/devshell"}
COMPREPLY+=("$v")
done
return
elif [[ ${COMP_CWORD} -eq 3 ]]; then
COMPREPLY=()
for file in "${FUCHSIA_DIR}"/vendor/"${prev}"/scripts/devshell/"${cur}"*; do
if [[ -x "${file}" ]]; then
COMPREPLY+=("${file##*/}")
fi
done
return
fi
;;
build)
if [[ ${COMP_CWORD} -eq 2 ]]; then
__fx_complete_build "${cur}"
fi
;;
esac
}
# Only define the completion function for `fx build` if requested.
if $bash_build_completion; then
function __fx_complete_build {
local target_py="${FUCHSIA_DIR}/scripts/gn_complete/complete.py"
# In a subshell, so as not to pollute the user's environment,
# load the build environment variables and execute the completion
# script.
COMPREPLY=(
$(
source "${FUCHSIA_DIR}/tools/devshell/lib/vars.sh"
fx-config-read
"${target_py}" "${1}" 2> /dev/null
)
)
}
else
function __fx_complete_build { :; }
fi
function __fx_set_compreply_for_product_board {
local prefix=$1
if [[ "${prefix}" =~ \. ]]; then
# product is filled, find a board
local product="${prefix%%\.*}"
prefix="${prefix##*\.}"
for file in "${FUCHSIA_DIR}"/{.,vendor/*}/boards/"${prefix}"*.gni*; do
if [[ -f "${file}" ]]; then
file="${file##*/}"
COMPREPLY+=("${product}.${file%%".gni"}")
fi
done
else
# find a product
if [[ $(type -t compopt) == 'builtin' ]]; then
compopt -o nospace
fi
for file in "${FUCHSIA_DIR}"/{.,vendor/*}/products/"${prefix}"*.gni*; do
if [[ -f "${file}" ]]; then
file="${file##*/}"
COMPREPLY+=("${file%%".gni"}")
fi
done
if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
COMPREPLY=("${COMPREPLY[0]}.")
fi
fi
}
function __fx {
local fuchsia_tools_dir="$(fx-config-read 2>/dev/null; echo "${FUCHSIA_BUILD_DIR}/tools")"
COMPREPLY=()
if [[ ${COMP_CWORD} -eq 1 ]]; then
local files cmd
cmd="${COMP_WORDS[1]}"
files=("${FUCHSIA_DIR}"/tools/devshell/"${cmd}"* "${FUCHSIA_DIR}"/tools/devshell/contrib/"${cmd}"*)
if [[ -d "${fuchsia_tools_dir}" ]]; then
files+=("${fuchsia_tools_dir}"/"${cmd}"*)
fi
for file in "${files[@]}"; do
if [[ -x "${file}" ]]; then
COMPREPLY+=("${file##*/}")
fi
done
else
__fx_complete_cmd
fi
}
complete -o default -F __fx fx
fi
}
__fx_env_main "$@"
unset __fx_env_main