blob: 522d47ac6f2889d1cb1b9b95122f84fd1e786cd8 [file] [log] [blame]
#!/bin/bash
# Copyright 2023 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.
#### CATEGORY=Build
### Find binaries among build directories, the checkout, and cloud storage
### matching a given build ID.
## usage: fx ls-buildid [--help|-h] [--verbose|-v] [--remote|-r] BUILD_ID
##
## Searches all build directories and the checkout - and optionally official
## cloud storage - for binaries matching a given build ID. The search is
## strictly local by default, and assumes that build directories are of the
## form $FUCHSIA_DIR/out/foo.
##
## --verbose|-v Report the locations in which there was no match.
##
## --remote|-r Extend the search to cloud storage. This takes a dependency
## on `gsutil`, which is expected to be on one's PATH. Further,
## for access to non-public storage, it is assumed that the
## user has already ran `gcloud auth login`.
##
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/../lib/vars.sh || exit $?
fx-config-read
# These are the standard buckets to which official Fuchsia infrastructure
# uploads binaries.
readonly GSUTIL_BUCKETS=(
fuchsia-artifacts
fuchsia-artifacts-internal
fuchsia-artifacts-release
)
id=""
remote=false
verbose=false
while [[ $# -ne 0 ]]; do
case "$1" in
--help|-h)
fx-command-help
exit 0
;;
--remote|-r)
if which gsutil &>/dev/null; then
remote=true
else
fx-warn "Option $1 requires gsutil to be on one's PATH. Proceeding with a strictly local search..."
fi
;;
--verbose|-v)
verbose=true
;;
-*)
fx-error "Unknown flag: $1"
fx-command-help
exit 1
;;
*)
if [[ -z "${id}" ]]; then
id="$1"
else
fx-error "Unexpected argument: '$1'"
exit 1
fi
;;
esac
shift
done
# Relativize against the current working directory on a best-effort basis,
# because that makes for nicer output.
readonly out_dir="${FUCHSIA_OUT_DIR#"$(pwd)"/}"
prebuilt_dir="${FUCHSIA_DIR}/prebuilt"
readonly prebuilt_dir="${prebuilt_dir#"$(pwd)"/}"
# Aggregate all .build-id directories across the various build directories, as
# well as those shipped with prebuilts in the checkout.
build_id_dirs=("${out_dir}"/**/.build-id)
build_id_dirs+=($(find "${prebuilt_dir}" -type d -name .build-id))
for build_id_dir in "${build_id_dirs[@]}"; do
# The would-be entry in the .build-id directory.
dirent="${build_id_dir}/${id:0:2}/${id:2}"
# Whether the .build-id directory is in a build or prebuilt directory, the
# binaries it corresponds to should all lie within the parent.
search_dir="$(dirname "${build_id_dir}")"
if [[ -f "${dirent}" ]]; then
find "${search_dir}" -samefile "${dirent}"
elif $verbose; then
fx-info "No binaries with build ID \"${id}\" found locally under ${search_dir}/"
fi
done
if $remote ; then
for bucket in "${GSUTIL_BUCKETS[@]}"; do
# This gives the current GCS scheme for binaries indexed by build ID.
url="gs://$bucket/debug/${id}.debug"
# gsutil offers no convenient way to check whether the user has access to a
# given GCS bucket. Worse yet, in the case of a stat with insufficient
# privileges, the quiet, error suppression option `-q` is ignored - and the
# resulting error code cannot be differentiated from the case of a
# successful stat call reporting that the object does not exit. Putting all
# this together, the seemingly least worst way to check permissions is to
# see whether `gsutil -q stat ...` returns any output.
output=$(gsutil -q stat "${url}" 2>&1)
result=$?
if [[ -n "${output}" ]]; then
if $verbose ; then
fx-warn "Insufficient privileges to access gs://${bucket}/. (Have you run \`gcloud auth login\`?)"
fi
continue
fi
if [[ $result == 0 ]]; then
echo "${url}"
elif $verbose ; then
fx-info "No binaries with build ID \"${id}\" found under gs://${bucket}/"
fi
done
fi