blob: f21681fe9bbc49f741d7f396c73c11081531e674 [file] [log] [blame]
#!/bin/bash
# Copyright 2018 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=Software delivery
### start the update server and attach to a running fuchsia device
## usage: fx serve-updates [-v] [-l host[:port]] [--no-auto-config]
## -l host:port host and port that "pm serve" will listen on
## --no-auto-config do not configure this host as a package server on the device
## -v verbose mode, shows info and debug messages from "pm"
## -C|--clean clean the package repository first. This flag is only
## valid if the incremental package publishing is enabled.
##
## This command supports incremental package publishing. If enabled, it will
## auto-publish packages as they are created or modified.
##
## To enable incremental package serving, run "fx --enable=incremental serve-updates ..."
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/vars.sh || exit $?
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/fx-optional-features.sh || exit $?
fx-config-read
function usage {
fx-command-help serve-updates
}
fx-standard-switches "$@"
set -- "${FX_ARGV[@]}"
port="8083"
serve_flags=()
verbose=false
auto_config=true
clean_first=false
while (($#)); do
case "$1" in
-l)
shift
port="${1##*:}"
serve_flags+=(-l "$1")
;;
--no-auto-config)
auto_config=false
;;
-v|--verbose)
verbose=true
;;
-C|--clean)
clean_first=true
;;
*)
echo "Unrecognized option: $1"
usage
exit 1
;;
esac
shift
done
if fx-is-bringup; then
fx-error "$0 is not supported in the bringup build configuration, as there are no package features in bringup."
exit 1
fi
if [[ "${verbose}" != true ]]; then
serve_flags+=("-q")
fi
pm_srv_pid=
cleanup() {
if [[ -n "${pm_srv_pid}" ]]; then
if kill -0 "${pm_srv_pid}" 2> /dev/null; then
kill -TERM "${pm_srv_pid}" 2> /dev/null
wait "${pm_srv_pid}" 2> /dev/null
fi
fi
}
trap cleanup EXIT
log() {
# This format matches bootserver so that `fx serve` ui is easier to read.
echo "$(date '+%Y-%m-%d %H:%M:%S') [serve-updates] $@"
}
# In any multi-homing scenario (two target interfaces, or two host interfaces),
# the resolve process can return different results at different times. As such
# we pin the address here, and let the ssh check loop below perform a clear
# whenever it is in the "discovery" state. This stabilizes the "connection"
# under multi-homed conditions.
serve_updates_target_addr=""
target-addr() {
if [[ -z "${serve_updates_target_addr}" ]]; then
serve_updates_target_addr="$(get-device-addr-resource)"
if [[ -n "${serve_updates_target_addr}" && -n "$(get-device-ssh-port)" ]]; then
serve_updates_target_addr="${serve_updates_target_addr}:$(get-device-ssh-port)"
fi
fi
if [[ -n "$serve_updates_target_addr" ]]; then
echo "$serve_updates_target_addr"
return 0
fi
return 1
}
clear-target-addr() {
serve_updates_target_addr=""
}
with-pinned-target() {
# Ensure we pin in the running shell before making a subshell. We also want
# to make sure we get an address at all.
if ! target-addr > /dev/null; then
return 1
fi
(
export FUCHSIA_DEVICE_NAME="$(target-addr)"
"$@"
)
}
repo_dir="${FUCHSIA_BUILD_DIR}/amber-files"
if is_feature_enabled "incremental"; then
fx-info "Incremental package auto-publishing is enabled."
serve_flags+=( -p "all_package_manifests.list" )
if $clean_first; then
$verbose && echo -n >&2 "Cleaning the package repository..."
if [[ -d "${repo_dir}" ]]; then
rm -Rf "${repo_dir}"
fi
$verbose && echo >&2 "done"
fi
$verbose && echo -n >&2 "Preparing the package repository..."
# only show output of prepare_publish if it fails
out="$(fx-command-run build build/images:prepare_publish 2>&1)"
if [[ $? -ne 0 ]]; then
echo >&2 "$out"
exit $?
fi
$verbose && echo >&2 "done"
else
if $clean_first; then
fx-error "Flag '-C' or '--clean' can only be used if the incremental feature is enabled"
exit 1
fi
fi
pm_serve_args=( serve -vt -repo "${repo_dir}" "${serve_flags[@]}" )
# the manifest list file has relative paths and "pm serve" looks for them
# from PWD, so pm command needs to be executed in "$FUCHSIA_BUILD_DIR"
cd "${FUCHSIA_BUILD_DIR}"
if [[ "${auto_config}" == false ]]; then
log "Flag '--no-auto-config' used, automatic device configuration disabled."
log "Use 'fx -d DEVICE add-update-source --port ${port}' to reconfigure devices as needed, since it is not persistent accross reboots."
log "Serving packages on port ${port}..."
fx-command-exec host-tool pm "${pm_serve_args[@]}"
fi
fx-command-exec host-tool pm "${pm_serve_args[@]}" &
pm_srv_pid=$!
# Allow a little slack for pm serve to startup, that way the first kill -0 will catch a dead server
sleep 0.1
if ! kill -0 "${pm_srv_pid}" 2> /dev/null; then
log "Server died, exiting"
wait
exit $?
fi
log "Discovery..."
# State is used to prevent too much output
state="discover"
while true; do
if ! kill -0 "${pm_srv_pid}" 2> /dev/null; then
log "Server died, exiting"
pm_srv_pid=
exit 1
fi
if [[ "$state" == "discover" ]]; then
# While we're still trying to connect to the device, clear the target
# address state so we re-resolve.
clear-target-addr
with-pinned-target fx-command-run shell exit 2>/dev/null
ping_result=$?
else
with-pinned-target fx-command-run shell -O check > /dev/null 2>&1
ping_result=$?
fi
if [[ "$state" == "discover" && "$ping_result" == 0 ]]; then
log "Device up"
state="config"
fi
if [[ "$state" == "config" ]]; then
log "Registering devhost as update source"
if with-pinned-target fx-command-run add-update-source --port "${port}"; then
log "Ready to push packages!"
# Log the uptime so that it is clear(er) from fx serve if the device rebooted.
# The tr is present as the output sometimes contains spurious control characters.
clock=$(with-pinned-target fx-command-run shell clock --monotonic)
if [[ -n ${clock} ]]; then
uptime=$(echo $clock | tr '[[:cntrl:]]' ' ' )
log "Target uptime: $(( $uptime / 1000000000 ))"
state="ready"
else
log "Device lost while checking uptime"
state="discover"
fi
else
log "Device lost while configuring update source"
state="discover"
fi
fi
if [[ "$state" == "ready" ]]; then
if [[ "$ping_result" != 0 ]]; then
log "Device lost"
state="discover"
else
sleep 1
fi
fi
done
# See EXIT trap above for cleanup that occurs