|
|
@ -2737,31 +2737,72 @@ export -f service:state |
|
|
|
charm:upstream-version() { |
|
|
|
local charm="$1" version cache_file="$state_tmpdir/$FUNCNAME.cache.$1" path |
|
|
|
if [ -e "$cache_file" ]; then |
|
|
|
cat "$cache_file" |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
if ! path=$(charm.has_direct_action "$charm" "upstream-versions"); then |
|
|
|
return 0 |
|
|
|
{ |
|
|
|
read-0 errlvl |
|
|
|
cat |
|
|
|
} <"$cache_file" |
|
|
|
return $errlvl |
|
|
|
fi |
|
|
|
version=$("$path" -l 1) || { |
|
|
|
err "Failed to get upstream version for ${DARKYELLOW}$charm${NORMAL}." |
|
|
|
return 1 |
|
|
|
} |
|
|
|
if path=$(charm.has_direct_action "$charm" "upstream-version-normalize"); then |
|
|
|
version=$("$path" "$version") || { |
|
|
|
err "Failed to normalize upstream version for ${DARKYELLOW}$charm${NORMAL}." |
|
|
|
( |
|
|
|
if ! mkdir "$cache_file.lock" 2>/dev/null; then |
|
|
|
while true; do |
|
|
|
sleep 0.1 |
|
|
|
[ -d "${cache_file}.lock" ] || break |
|
|
|
done |
|
|
|
if [ -e "$cache_file" ]; then |
|
|
|
{ |
|
|
|
read-0 errlvl |
|
|
|
if [ "$errlvl" == 0 ]; then |
|
|
|
cat |
|
|
|
else |
|
|
|
cat >&2 |
|
|
|
fi |
|
|
|
} <"$cache_file" |
|
|
|
return $errlvl |
|
|
|
fi |
|
|
|
return 1 |
|
|
|
} |
|
|
|
fi |
|
|
|
echo "$version" > "$cache_file" |
|
|
|
e "$version" |
|
|
|
fi |
|
|
|
trap_add EXIT,ERR "rmdir \"${cache_file}\".lock" |
|
|
|
if ! path=$(charm.has_direct_action "$charm" "upstream-versions"); then |
|
|
|
touch "$cache_file" |
|
|
|
return 0 |
|
|
|
fi |
|
|
|
rm -f "${cache_file}.wip" |
|
|
|
touch "${cache_file}.wip" |
|
|
|
( |
|
|
|
version=$("$path" -l 1) |
|
|
|
errlvl=$? |
|
|
|
if [ "$errlvl" != 0 ]; then |
|
|
|
err "Action ${WHITE}upstream-versions${NORMAL} failed for ${DARKPINK}$charm${NORMAL}." |
|
|
|
return $errlvl |
|
|
|
fi |
|
|
|
if path=$(charm.has_direct_action "$charm" "upstream-version-normalize"); then |
|
|
|
version=$("$path" "$version") |
|
|
|
errlvl=$? |
|
|
|
if [ "$errlvl" != 0 ]; then |
|
|
|
err "Failed to normalize upstream version for ${DARKPINK}$charm${NORMAL}." |
|
|
|
return $errlvl |
|
|
|
fi |
|
|
|
fi |
|
|
|
echo "$version" |
|
|
|
) > "${cache_file}.wip" 2>&1 |
|
|
|
errlvl=$? |
|
|
|
p0 "$errlvl" > "${cache_file}" |
|
|
|
if [ "$errlvl" != 0 ]; then |
|
|
|
cat "${cache_file}.wip" | tee -a "${cache_file}" >&2 |
|
|
|
rm "${cache_file}.wip" |
|
|
|
return $errlvl |
|
|
|
fi |
|
|
|
cat "${cache_file}.wip" | tee -a "${cache_file}" |
|
|
|
rm "${cache_file}.wip" |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
service:upstream-version() { |
|
|
|
local service="$1" version |
|
|
|
charm=$(get_service_charm "$service") || return 1 |
|
|
|
version=$(charm:upstream-version "$charm") || return 1 |
|
|
|
charm=$(get_service_charm "$service") || return $? |
|
|
|
version=$(charm:upstream-version "$charm") || return $? |
|
|
|
e "$version" |
|
|
|
} |
|
|
|
export -f service:upstream-version |
|
|
@ -5703,14 +5744,81 @@ if [ "${PIPESTATUS[0]}" != 0 ]; then |
|
|
|
fi |
|
|
|
[ "$action" == "build" ] && exit 0 |
|
|
|
|
|
|
|
state:fields:resolve-parallel() { |
|
|
|
local cols=("$@") service jobs state_msg out errlvl col |
|
|
|
first_job=1 |
|
|
|
tick_pid= |
|
|
|
concurrent_jobs=0 |
|
|
|
MAX_CONCURRENT_JOBS=$(nproc) |
|
|
|
for col in "${cols[@]}"; do |
|
|
|
for service in "${services_args[@]}"; do |
|
|
|
if [ "$concurrent_jobs" -ge "$MAX_CONCURRENT_JOBS" ]; then |
|
|
|
wait -n # -p job_id ## not supported in this version of bash |
|
|
|
## job list is not accurate, but the number of elt is |
|
|
|
((concurrent_jobs--)) |
|
|
|
fi |
|
|
|
( |
|
|
|
out=$( |
|
|
|
case "${col//_/-}" in |
|
|
|
root) |
|
|
|
if [[ " ${compose_yml_services[*]} " == *" ${service} "* ]]; then |
|
|
|
echo "1" |
|
|
|
else |
|
|
|
echo "0" |
|
|
|
fi |
|
|
|
;; |
|
|
|
name) e "$service" ;; |
|
|
|
charm) get_service_charm "$service" ;; |
|
|
|
state) service:state "$service" ;; |
|
|
|
type) get_service_type "$service" ;; |
|
|
|
upstream-version) service:upstream-version "$service" ;; |
|
|
|
*) |
|
|
|
if has_service_action "$service" "get-$col" >/dev/null; then |
|
|
|
state_msg=$(run_service_action "$service" "get-$col") || exit 1 |
|
|
|
if [[ "$state_msg" == *$'\n'* ]]; then |
|
|
|
e "${state_msg%%$'\n'*}" |
|
|
|
else |
|
|
|
e "${state_msg}" |
|
|
|
fi |
|
|
|
fi |
|
|
|
;; |
|
|
|
esac 2>&1 |
|
|
|
) |
|
|
|
errlvl="$?" |
|
|
|
p0 "$service" "$col" "$errlvl" "$out" |
|
|
|
) & |
|
|
|
jobs=("${jobs[@]}" $!) |
|
|
|
((concurrent_jobs++)) |
|
|
|
if [ -n "$first_job" ]; then |
|
|
|
## launch tick |
|
|
|
( |
|
|
|
while true; do |
|
|
|
sleep 0.1 |
|
|
|
p0 "" "" "" "" |
|
|
|
done |
|
|
|
) & |
|
|
|
tick_pid=$! |
|
|
|
first_job= |
|
|
|
fi |
|
|
|
done |
|
|
|
done |
|
|
|
wait "${jobs[@]}" |
|
|
|
if [ -n "$tick_pid" ]; then |
|
|
|
kill "$tick_pid" |
|
|
|
fi |
|
|
|
} |
|
|
|
|
|
|
|
if [ "$action" == "status" ]; then |
|
|
|
if ! [ -t 1 ]; then |
|
|
|
state_raw_output=1 |
|
|
|
fi |
|
|
|
|
|
|
|
if [[ -n "${state_all_services}" ]] || [[ "${#state_filters[@]}" -gt 0 ]]; then |
|
|
|
compose_yml_services=($(compose:yml:root:services)) || exit 1 |
|
|
|
fi |
|
|
|
if [[ -n "${state_all_services}" ]]; then |
|
|
|
state_columns=("root" ${state_columns[@]}) |
|
|
|
fi |
|
|
|
|
|
|
|
state_columns_raw=() |
|
|
|
for col in "${state_columns[@]}"; do |
|
|
|
if [[ "$col" =~ ^[+-] ]]; then |
|
|
@ -5731,13 +5839,136 @@ if [ "$action" == "status" ]; then |
|
|
|
esac |
|
|
|
fi |
|
|
|
done |
|
|
|
declare -A state_columns_idx=() |
|
|
|
declare -A filter_idx=() |
|
|
|
filter_cols=() |
|
|
|
non_filter_cols=("${state_columns_raw[@]}") |
|
|
|
for filter in "${state_filters[@]}"; do |
|
|
|
IFS="=" read -r key value <<<"$filter" |
|
|
|
if [[ " ${non_filter_cols[*]} " == *" $key "* ]]; then |
|
|
|
## remove from non_filter_cols |
|
|
|
non_filter_cols=(${non_filter_cols[*]/$key}) |
|
|
|
fi |
|
|
|
state_columns_idx["$col"]="${#filter_cols[@]}" |
|
|
|
filter_cols+=("${key}") |
|
|
|
done |
|
|
|
tot_nb_cols=$(( ${#non_filter_cols[@]} + ${#filter_cols[@]} )) |
|
|
|
|
|
|
|
while read-0-err E "${state_columns_raw[@]}"; do |
|
|
|
values=() |
|
|
|
for col in "${state_columns_raw[@]}"; do |
|
|
|
color= |
|
|
|
value="${!col}" |
|
|
|
if [ -z "$state_raw_output" ]; then |
|
|
|
## make services_idx |
|
|
|
declare -A services_idx=() |
|
|
|
idx=0 |
|
|
|
for service in "${services_args[@]}"; do |
|
|
|
services_idx["$service"]=$((idx++)) |
|
|
|
done |
|
|
|
## make state_columns_idx |
|
|
|
idx=0 |
|
|
|
for col in "${non_filter_cols[@]}"; do |
|
|
|
state_columns_idx["$col"]=$((${#filter_cols[@]} + idx++)) |
|
|
|
done |
|
|
|
|
|
|
|
values=() ## all values |
|
|
|
new_service_args=("${services_args[@]}") ## will remove service not satisfying filters |
|
|
|
while read-0 service col E out; do |
|
|
|
if [[ " ${new_service_args[*]} " != *" $service "* ]]; then |
|
|
|
continue |
|
|
|
fi |
|
|
|
col_index="${state_columns_idx[$col]}" |
|
|
|
service_index="${services_idx[$service]}" |
|
|
|
values[$((service_index * tot_nb_cols + col_index))]="$out" |
|
|
|
## check if all filter are valuated and satisfied |
|
|
|
for filter in "${state_filters[@]}"; do |
|
|
|
IFS="=" read -r key value <<<"$filter" |
|
|
|
col_index="${state_columns_idx[$key]}" |
|
|
|
if [ -z "${values[$((service_index * tot_nb_cols + col_index))]}" ]; then |
|
|
|
break |
|
|
|
fi |
|
|
|
if [ "${values[$((service_index * tot_nb_cols + col_index))]}" != "$value" ]; then |
|
|
|
new_service_args=(${new_service_args[*]/"$service"}) |
|
|
|
break |
|
|
|
fi |
|
|
|
done |
|
|
|
done < <(state:fields:resolve-parallel "${filter_cols[@]}") |
|
|
|
|
|
|
|
|
|
|
|
services_args=("${new_service_args[@]}") |
|
|
|
if [ "${#services_args[@]}" == 0 ]; then |
|
|
|
warn "No services found matching the filters." >&2 |
|
|
|
exit 0 |
|
|
|
fi |
|
|
|
|
|
|
|
spinner_chars="⣷⣯⣟⡿⢿⣻⣽⣾" |
|
|
|
spinner_idx=0 |
|
|
|
spinner_bg_steps=4 |
|
|
|
spinner_bg_dir=1 |
|
|
|
first_draw=1 |
|
|
|
last_draw= |
|
|
|
if [ -z "$state_raw_output" ]; then |
|
|
|
echo -en "\e[?25l"; stty -echo 2>/dev/null |
|
|
|
trap_add EXIT,ERR "echo -en '\e[?25h'; stty echo 2>/dev/null" |
|
|
|
fi |
|
|
|
errors=() |
|
|
|
declare -A errors_hash_idx=() |
|
|
|
error_idx=0 |
|
|
|
values_valued=0 |
|
|
|
values_total=$(( ${#services_args[@]} * ${#state_columns_raw[@]} )) |
|
|
|
while read-0 service col E out; do |
|
|
|
if [ -n "$service" ]; then |
|
|
|
col_index="${state_columns_idx[$col]}" |
|
|
|
service_index="${services_idx[$service]}" |
|
|
|
if [[ "$E" != 0 ]]; then |
|
|
|
error_hash=$(H "$col" "$E" "$out") |
|
|
|
matching_error_idx="${errors_hash_idx[$error_hash]}" |
|
|
|
if [[ -z "${matching_error_idx}" ]]; then |
|
|
|
errors+=("$error_idx:$service:$col:$E:$out") |
|
|
|
out="!Err[$((error_idx))]" |
|
|
|
errors_hash_idx["$error_hash"]="$error_idx" |
|
|
|
error_idx=$((error_idx + 1)) |
|
|
|
else |
|
|
|
## find the error to add the service |
|
|
|
error="${errors[$matching_error_idx]}" |
|
|
|
error="${error#*:}" |
|
|
|
error_service="${error%%:*}" |
|
|
|
error_tail="${error#*:}" |
|
|
|
errors[$matching_error_idx]="$matching_error_idx:$error_service,$service:$error_tail" |
|
|
|
out="!Err[$((matching_error_idx))]" |
|
|
|
fi |
|
|
|
fi |
|
|
|
values[$((service_index * tot_nb_cols + col_index))]="$out" |
|
|
|
values_valued=$((values_valued + 1)) |
|
|
|
if [[ "$values_valued" != "$values_total" ]]; then |
|
|
|
last_draw=1 |
|
|
|
continue |
|
|
|
fi |
|
|
|
fi |
|
|
|
[ -n "$state_raw_output" ] && continue |
|
|
|
|
|
|
|
## Draw table |
|
|
|
if [ -n "$first_draw" ]; then |
|
|
|
first_draw= |
|
|
|
else |
|
|
|
## move up one line per service |
|
|
|
printf "\033[%dA" "${#services_args[@]}" |
|
|
|
fi |
|
|
|
if [[ "$spinner_bg_dir" == "1" ]]; then |
|
|
|
spinner_bg_step=$((spinner_bg_step + 1)) |
|
|
|
if [ "$spinner_bg_step" -ge "$spinner_bg_steps" ]; then |
|
|
|
spinner_idx=$(( (spinner_idx + 1) % ${#spinner_chars} )) |
|
|
|
spinner_bg_dir=0 |
|
|
|
fi |
|
|
|
else |
|
|
|
spinner_bg_step=$((spinner_bg_step - 1)) |
|
|
|
if [ "$spinner_bg_step" -le 0 ]; then |
|
|
|
spinner_idx=$(( (spinner_idx + 1) % ${#spinner_chars} )) |
|
|
|
spinner_bg_dir=1 |
|
|
|
fi |
|
|
|
fi |
|
|
|
SPINNERGRAY=$'\e[38;5;28;48;5;'"$((232 + spinner_bg_step))"'m' |
|
|
|
|
|
|
|
while read-0-err E "${state_columns_raw[@]}"; do |
|
|
|
line_values=() |
|
|
|
for col in "${state_columns_raw[@]}"; do |
|
|
|
color= |
|
|
|
value="${!col}" |
|
|
|
read -r -- value_trim <<<"${!col}" |
|
|
|
case "${col//_/-}" in |
|
|
|
root) |
|
|
@ -5767,107 +5998,115 @@ if [ "$action" == "status" ]; then |
|
|
|
if [[ "${value_trim}" == "N/A" ]]; then |
|
|
|
color=gray |
|
|
|
fi |
|
|
|
if [[ "$value_trim" == "!Err"* ]]; then |
|
|
|
color=darkred |
|
|
|
fi |
|
|
|
if [[ "$spinner_chars" == *"$value_trim"* ]]; then |
|
|
|
color=spinnergray |
|
|
|
fi |
|
|
|
;; |
|
|
|
esac |
|
|
|
color="${color^^}" |
|
|
|
fi |
|
|
|
if [ -n "$color" ]; then |
|
|
|
values+=("${!color}$value${NORMAL}") |
|
|
|
else |
|
|
|
values+=("$value") |
|
|
|
fi |
|
|
|
done |
|
|
|
first=1 |
|
|
|
for value in "${values[@]}"; do |
|
|
|
if [ -n "$first" ]; then |
|
|
|
first= |
|
|
|
else |
|
|
|
if [ -n "$state_raw_output_nul" ]; then |
|
|
|
printf "\0" |
|
|
|
if [ -n "$color" ]; then |
|
|
|
line_values+=("${!color}$value${NORMAL}") |
|
|
|
else |
|
|
|
line_values+=("$value") |
|
|
|
fi |
|
|
|
done |
|
|
|
first=1 |
|
|
|
for value in "${line_values[@]}"; do |
|
|
|
if [ -n "$first" ]; then |
|
|
|
first= |
|
|
|
else |
|
|
|
printf " " |
|
|
|
fi |
|
|
|
fi |
|
|
|
printf "%s" "$value" |
|
|
|
done |
|
|
|
if [ -n "$state_raw_output_nul" ]; then |
|
|
|
printf "\0" |
|
|
|
else |
|
|
|
printf "%s" "$value" |
|
|
|
done |
|
|
|
printf "\n" |
|
|
|
done < <( |
|
|
|
set -o pipefail |
|
|
|
for service in "${services_args[@]}"; do |
|
|
|
for col in "${state_columns_raw[@]}"; do |
|
|
|
col_index="${state_columns_idx[$col]}" |
|
|
|
service_index="${services_idx[$service]}" |
|
|
|
value_idx="$((service_index * tot_nb_cols + col_index))" |
|
|
|
if ! [[ -v "values[$value_idx]" ]]; then |
|
|
|
p0 " ${spinner_chars:$spinner_idx:1} " |
|
|
|
elif [ -z "${values[$((service_index * tot_nb_cols + col_index))]}" ]; then |
|
|
|
p0 "N/A" |
|
|
|
else |
|
|
|
p0 "${values[$((service_index * tot_nb_cols + col_index))]}" |
|
|
|
fi |
|
|
|
done |
|
|
|
done | { |
|
|
|
if [ -z "$state_raw_output" ]; then |
|
|
|
col-0:normalize:size "${state_columns_align}" |
|
|
|
else |
|
|
|
cat |
|
|
|
fi |
|
|
|
} |
|
|
|
echo 0 |
|
|
|
) |
|
|
|
if [ "$E" != 0 ]; then |
|
|
|
err "Unexpected failure" |
|
|
|
exit $E |
|
|
|
fi |
|
|
|
done < <( |
|
|
|
set -o pipefail |
|
|
|
filter_cols=() |
|
|
|
for filter in "${state_filters[@]}"; do |
|
|
|
IFS="=" read -r key value <<<"$filter" |
|
|
|
## if not already in state_columns_raw |
|
|
|
[[ " ${state_columns_raw[*]} " == *" $key "* ]] || |
|
|
|
filter_cols+=("${key//-/_}") |
|
|
|
done < <(state:fields:resolve-parallel "${non_filter_cols[@]}") |
|
|
|
|
|
|
|
for error in "${errors[@]}"; do |
|
|
|
echo "" >&2 |
|
|
|
idx=${error%%:*}; error=${error#*:} |
|
|
|
service=${error%%:*}; error=${error#*:} |
|
|
|
col=${error%%:*}; error=${error#*:} |
|
|
|
E=${error%%:*}; error=${error#*:} |
|
|
|
service_list_str="" |
|
|
|
services=(${service//,/ }) |
|
|
|
first=1 |
|
|
|
for service in "${services[@]}"; do |
|
|
|
if [ -n "$first" ]; then |
|
|
|
first= |
|
|
|
else |
|
|
|
service_list_str+=", " |
|
|
|
fi |
|
|
|
service_list_str+="${DARKYELLOW}$service${NORMAL}" |
|
|
|
done |
|
|
|
echo "${RED}Error${DARKRED}[$idx]:${NORMAL} while computing" \ |
|
|
|
"${WHITE}$col${NORMAL} for $service_list_str" >&2 |
|
|
|
echo "$error" | prefix " ${GRAY}|${NORMAL} " >&2 |
|
|
|
echo " ${GRAY}..${NORMAL} ${WHITE}Exited${NORMAL} with errorlevel ${DARKRED}$E${NORMAL}" >&2 |
|
|
|
done |
|
|
|
if [[ "${#errors[@]}" -gt 0 ]]; then |
|
|
|
exit 1 |
|
|
|
fi |
|
|
|
|
|
|
|
if [ -n "$state_raw_output" ]; then |
|
|
|
|
|
|
|
for service in "${services_args[@]}"; do |
|
|
|
declare -A values=() |
|
|
|
for col in "${state_columns_raw[@]}" "${filter_cols[@]}"; do |
|
|
|
case "${col//_/-}" in |
|
|
|
root) |
|
|
|
if [[ " ${compose_yml_services[*]} " == *" ${service} "* ]]; then |
|
|
|
value="1" |
|
|
|
else |
|
|
|
value="0" |
|
|
|
fi |
|
|
|
;; |
|
|
|
name) value="$service" ;; |
|
|
|
charm) |
|
|
|
value=$(get_service_charm "$service") || { echo 1; exit 1; } |
|
|
|
;; |
|
|
|
state) |
|
|
|
value=$(service:state "$service") || { echo 1; exit 1; } |
|
|
|
;; |
|
|
|
type) |
|
|
|
value=$(get_service_type "$service") || { echo 1; exit 1; } |
|
|
|
;; |
|
|
|
upstream-version) |
|
|
|
value=$(service:upstream-version "$service") || { echo 1; exit 1; } |
|
|
|
value=${value:-N/A} |
|
|
|
;; |
|
|
|
*) |
|
|
|
if has_service_action "$service" "get-$col" >/dev/null; then |
|
|
|
state_msg=$(run_service_action "$service" "get-$col") || { echo 1; exit 1 ; } |
|
|
|
if [[ "$state_msg" == *$'\n'* ]]; then |
|
|
|
value="${state_msg%%$'\n'*}" |
|
|
|
## XXXvlab: For now, these are not used, but we could |
|
|
|
## display them in additional lines (in same "cell") |
|
|
|
msgs="${state_msg#*$'\n'}" |
|
|
|
else |
|
|
|
value=${state_msg} |
|
|
|
fi |
|
|
|
else |
|
|
|
value="N/A" |
|
|
|
fi |
|
|
|
;; |
|
|
|
esac |
|
|
|
values["$col"]="$value" |
|
|
|
done |
|
|
|
for filter in "${state_filters[@]}"; do |
|
|
|
IFS="=" read -r key value <<<"$filter" |
|
|
|
[[ "${values[$key]}" != "$value" ]] && |
|
|
|
continue 2 |
|
|
|
done |
|
|
|
first=1 |
|
|
|
for col in "${state_columns_raw[@]}"; do |
|
|
|
p0 "${values[$col]}" |
|
|
|
col_index="${state_columns_idx[$col]}" |
|
|
|
service_index="${services_idx[$service]}" |
|
|
|
value_idx="$((service_index * tot_nb_cols + col_index))" |
|
|
|
value="${values[$value_idx]}" |
|
|
|
if [ -n "$first" ]; then |
|
|
|
first= |
|
|
|
else |
|
|
|
if [ -n "$state_raw_output_nul" ]; then |
|
|
|
printf "\0" |
|
|
|
else |
|
|
|
printf " " |
|
|
|
fi |
|
|
|
fi |
|
|
|
printf "%s" "$value" |
|
|
|
done |
|
|
|
done | { |
|
|
|
if [ -z "$state_raw_output" ]; then |
|
|
|
col-0:normalize:size "${state_columns_align}" |
|
|
|
if [ -n "$state_raw_output_nul" ]; then |
|
|
|
printf "\0" |
|
|
|
else |
|
|
|
cat |
|
|
|
printf "\n" |
|
|
|
fi |
|
|
|
} |
|
|
|
echo 0 |
|
|
|
) |
|
|
|
if [ "$E" != 0 ]; then |
|
|
|
echo "E: '$E'" >&2 |
|
|
|
exit 1 |
|
|
|
done |
|
|
|
fi |
|
|
|
|
|
|
|
exit 0 |
|
|
|
fi |
|
|
|
|
|
|
|