blob: 13926e40585671306e3ec5111f787d3259e6b2de [file] [log] [blame]
#!/bin/bash
# Copyright 2020 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.
function get_host_tools_dir {
local -r build_dir="$(fx-build-dir-if-present && echo "${FUCHSIA_BUILD_DIR}")"
local -r host_tools="${build_dir}/host-tools"
if [[ -d "${build_dir}" && -d "${host_tools}" ]]; then
echo "${host_tools}"
fi
}
function get_exec_from_metadata {
local -r metadata_file=$1
export PREBUILT_3P_DIR FUCHSIA_DIR HOST_PLATFORM
export HOST_TOOLS_DIR="$(get_host_tools_dir)"
awk -F ' *= *' -f - "${metadata_file}" <<'EOF'
/^#### +EXECUTABLE */ {
gsub(/\${PREBUILT_3P_DIR}/, ENVIRON["PREBUILT_3P_DIR"], $2);
gsub(/\${FUCHSIA_DIR}/, ENVIRON["FUCHSIA_DIR"], $2);
gsub(/\${HOST_TOOLS_DIR}/, ENVIRON["HOST_TOOLS_DIR"], $2);
gsub(/\${HOST_PLATFORM}/, ENVIRON["HOST_PLATFORM"], $2);
print $2;
}
EOF
}
function _relative {
cmd="$1"
if [[ "${cmd}" == *"${FUCHSIA_DIR}"* ]]; then
echo "//${cmd#${FUCHSIA_DIR}/}"
else
echo "${cmd}"
fi
}
function find_executable {
local cmd_name="$1"
local cmd_path="$(commands "${cmd_name}")"
# no metadata, so let's try to find the file
if [[ -z "${cmd_path}" ]]; then
# no file in regular script directories, look in host_tools
cmd_path="$(find_host_tools "${cmd_name}")"
fi
# If multiple commands match, use the first one
echo "$(find_exec_from_path "${cmd_path}" | head -1)"
}
function find_exec_from_path {
local cmd_path="$1"
cmd_path="${cmd_path%.fx}"
local fx_file_path="${cmd_path}.fx"
if [[ ! -f "${fx_file_path}" ]]; then
# no metadata, so let's try to find the file
echo "${cmd_path}"
if [[ ! -x "${cmd_path}" ]]; then
return 1
fi
else
# there's metadata
local from_metadata="$(get_exec_from_metadata "${fx_file_path}")"
if [[ -n "${from_metadata}" ]]; then
# EXECUTABLE is defined in the metadata, use it
echo "${from_metadata}"
if [[ -f "${cmd_path}" && ! "${cmd_path}" -ef "${from_metadata}" ]]; then
fx-error "Invalid ${fx_file_path}: if both ${basename_exec} and EXECUTABLE metadata exist, they must point to the same file"
return 1
fi
else
# no EXECUTABLE in the metadata, so return the cmd_path itself
echo "${cmd_path}"
if [[ ! -x "${cmd_path}" ]]; then
return 1
fi
fi
fi
}
function find_execs_and_metadata {
local cmd_name=$1
shift
if [[ -z "${cmd_name}" ]]; then
cmd_name="*"
fi
local dirs=()
for d in "$@"; do
if [[ -d "${d}" ]]; then
dirs+=( "${d}" )
fi
done
if [[ ${#dirs[@]} -eq 0 ]]; then
return 0
fi
# run find assuming "-executable" is supported
cmds="$( find "${dirs[@]}" -maxdepth 1 -type f \
\( -executable -name "${cmd_name}" \) -o \
\( -name "${cmd_name}.fx" \) 2>/dev/null )"
if [[ $? -ne 0 ]]; then
# assume that the error was caused because versions of find older than 4.3.0
# don't support -executable. Run with -perm +100 instead, which is not
# supported in versions of find newer than 4.5.12, so it can't be used always.
cmds="$( find "${dirs[@]}" -maxdepth 1 -type f \
\( -perm +100 -name "${cmd_name}" \) -o \
\( -name "${cmd_name}.fx" \) 2>/dev/null )"
if [[ $? -ne 0 ]]; then
{
echo "ERROR: 'find' failed unexpectedly, please execute fx with '-x' and report a bug."
echo "At least one of the commands below was expected to work:"
echo 'find ' "${dirs[@]}" '-maxdepth 1 -type f \( -executable -name' "\"${cmd_name}\"" '\) -o \( -name ' "\"${cmd_name}.fx\"" '\)'
echo 'find ' "${dirs[@]}" '-maxdepth 1 -type f \( -perm +100 -name' "\"${cmd_name}\"" '\) -o \( -name ' "\"${cmd_name}.fx\"" '\)'
} >&2
exit 1
fi
fi
sort -u <<< "${cmds}"
}
function find_host_tools {
local cmd_name=$1
local -r host_tools="$(get_host_tools_dir)"
if [[ -z "${host_tools}" ]]; then
return
fi
# get a list of non-host-tools commands and metadata files, separated by
# semi-colon.
cmds="$(commands | tr '\n' ';')"
binaries=()
# do not list a host tool if there's a subcommand script or an .fx metadata
# file with the same name.
for binary in $(find_execs_and_metadata "${cmd_name}" "${host_tools}"); do
name="${binary##*/}" # remove path, equivalent to basename but faster
# only return the binary if no {binary} or {binary}.fx as other commands
if [[ "${cmds}" != */${name}.fx\;* && "${cmds}" != */${name}\;* ]]; then
binaries+=( "${binary}" )
fi
done
echo "${binaries[@]}"
}
function commands {
local cmd_name=${1:-}
local dirs
# handle "vendor VENDOR COMMAND"
if [[ "${cmd_name}" == "vendor" && $# -eq 3 ]]; then
vendor=$2
cmd_name=$3
dirs=("${FUCHSIA_DIR}"/vendor/${vendor}/scripts/devshell)
# handle "vendor VENDOR"
elif [[ "${cmd_name}" == "vendor" && $# -eq 2 ]]; then
vendor=$2
cmd_name=""
dirs=("${FUCHSIA_DIR}"/vendor/${vendor}/scripts/devshell)
else
dirs=("${FUCHSIA_DIR}"/tools/devshell{,/contrib} "${FUCHSIA_DIR}"/vendor/*/scripts/devshell)
fi
find_execs_and_metadata "${cmd_name}" "${dirs[@]}"
}