#!/usr/bin/env bash
# file : load/load-with-metadata.in
# license : MIT; see accompanying LICENSE file
# The wrapper around brep-load, which pulls the package metadata from a git
# repository and runs brep-load, passing the metadata directory to it.
#
# Specifically, pull a pre-cloned (read-only) git repository with the contents
# of an archive-based bpkg repository. Run brep-load with the `--metadata
#
/owners` option, the --metadata-changed option, if the current snapshot
# of the repository has not yet been processed by brep-load, and forward any
# further arguments to brep-load.
#
# --timeout
#
# Git operation timeout. Specifically, the operation will be aborted if
# there is no network activity for the specified time. Default is 60
# seconds. Note that currently the git timeout is only supported for the
# http(s) transport.
#
# --brep-load
#
# The brep-load program to be used. This should be the path to the brep-load
# executable.
#
# Note also that this script maintains the .load file which contains the
# last successfully processed commit.
#
usage="usage: $0 [] []"
owd="$(pwd)"
trap "{ cd '$owd'; exit 1; }" ERR
set -o errtrace # Trap in functions and subshells.
set -o pipefail # Fail if any pipeline command fails.
shopt -s lastpipe # Execute last pipeline command in the current shell.
shopt -s nullglob # Expand no-match globs to nothing rather than themselves.
@import bpkg-util/utility@ # check_git_connectivity()
# The script's own options.
#
timeout=60
brep_load=
while [[ "$#" -gt 0 ]]; do
case "$1" in
--timeout)
shift
timeout="$1"
shift || true
;;
--brep-load)
shift
brep_load="$1"
shift || true
;;
*)
break
;;
esac
done
# The repository directory.
#
repo_dir="${1%/}"
# Validate options and arguments.
#
if [[ -z "$repo_dir" ]]; then
error "$usage"
fi
if [[ ! -d "$repo_dir" ]]; then
error "'$repo_dir' does not exist or is not a directory"
fi
shift # repo_dir
# If brep-load path is not specified, then use the brep-load program from the
# script directory, if present. Otherwise, use the 'brep-load' path.
#
if [[ -z "$brep_load" ]]; then
brep_load="$(dirname "$(realpath "${BASH_SOURCE[0]}")")/brep-load"
if [[ ! -x "$brep_load" ]]; then
brep_load=brep-load
fi
fi
# Make sure the commit file is present.
#
load_commit="$repo_dir.load"
touch "$load_commit"
# Pull the repository shallowly.
#
if ! remote_url="$(git -C "$repo_dir" config --get remote.origin.url)"; then
error "'$repo_dir' is not a git repository"
fi
# Save the repository name and branch of where the latest commit has been
# fetched from, separated by space. For example 'origin master'.
#
refs=$(git -C "$repo_dir" log -1 --format=%D FETCH_HEAD)
repo_branch="$(sed -n -E 's%^.+ ([^/ ]+)/([^/ ]+)$%\1 \2%p' <<<"$refs")"
if [[ -z "$repo_branch" ]]; then
error "unable to extract repository and branch from '$refs'"
fi
# Git doesn't support the connection timeout option. The options we use are
# just an approximation of the former, that, in particular, don't cover the
# connection establishing. To work around this problem, before running a git
# command that assumes the remote repository communication we manually check
# connectivity with the remote repository.
#
check_git_connectivity "$remote_url" "$timeout"
# Fail if no network activity happens during the time specified.
#
# Note: keep $repo_branch expansion unquoted.
#
git -c http.lowSpeedLimit=1 -c "http.lowSpeedTime=$timeout" \
-C "$repo_dir" fetch -q --depth=1 $repo_branch
git -C "$repo_dir" reset -q --hard FETCH_HEAD
# Match the HEAD commit id to the one stored in the file. If it matches, then
# nothing changed in the repository since it has been processed by brep-load
# last time and we should not pass the --metadata-changed option to brep-load.
#
commit="$(git -C "$repo_dir" rev-parse HEAD)"
pc="$(cat "$load_commit")"
loader_options=(--metadata "$repo_dir/owners")
if [[ "$commit" != "$pc" ]]; then
loader_options+=(--metadata-changed)
fi
"$brep_load" "${loader_options[@]}" "$@"
echo "$commit" >"$load_commit"