#!/usr/bin/env bash # ... # shellcheck disable=2317,2059 # created: 20240515 # purpose: automatic git pull of repos # author: afinet # # update: 20240620 # purpose: progress bar local_repository_folder=$HOME"/GIT-LAB/" # Array of git repositories REPOS=($(find $local_repository_folder -name ".git" -type d)) # Lenght of the array PULL_ITER=${#REPOS[@]} # Progress bar dedicated variables # We can control how progress bar work PROGRESS_BAR_CHAR=(█ ▒) # Display template # We can control how informations is displayed PROGRESS_BAR_INFO_TEMPLATE=' %s [%2d/%2d] ' PROGRESS_BAR_COMPL_TEMPLATE=' %2d%% ' PROGRESS_BAR_TEMPLATE='\033[1m%s%s\033[0m%s%s\r' # control which information is displayed" PROGRESS_BAR_DISPLAY_INFO=1 PROGRESS_BAR_DISPLAY_COMPL=1 puller() { SECONDS=0 i=1 reporting=false report=$'============================\nPulling generated messages :\n============================\n' for repo in ${REPOS[@]}; do run_error="" echo $repo $i run_error=$(git -C $repo/.. pull 2>&1 > /dev/null) if [[ $run_error ]]; then reporting=true report=$report$"* On $repo :"$'\n'"$run_error"$'\n' fi ((i++)) done duration=$SECONDS ((i--)) echo "[Finished] - Pulled $i/$PULL_ITER repositories in $((duration / 60)):$((duration % 60))" if [ "$reporting" = true ]; then echo "$report" fi } draw_progressbar() { # function parameters local -r progress=${1?"progress is mandatory"} local -r total=${2?"total elements is mandatory"} local -r info=${3:-"In progress"} # function local variables local progress_segment local todo_segment local info_segment="" local compl_segment="" if [[ ${PROGRESS_BAR_DISPLAY_INFO:-1} -eq 1 ]]; then printf -v info_segment "${PROGRESS_BAR_INFO_TEMPLATE}" \ "$info" "$progress" "$total" fi local -r progress_ratio=$((progress * 100 / total)) if [[ ${PROGRESS_BAR_DISPLAY_COMPL:-0} -eq 1 ]]; then printf -v compl_segment "${PROGRESS_BAR_COMPL_TEMPLATE}" \ "$progress_ratio" fi # progress bar construction # calculate each element sizes, bar must fit in ou screen local -r bar_size=$((COLUMNS - ${#info_segment} - ${#compl_segment})) local -r progress_segment_size=$((bar_size * progress_ratio / 100)) local -r todo_segment_size=$((bar_size - progress_segment_size)) printf -v progress_segment "%${progress_segment_size}s" "" printf -v todo_segment "%${todo_segment_size}s" "" printf >&2 "$PROGRESS_BAR_TEMPLATE" \ "$info_segment" \ "${progress_segment// /${PROGRESS_BAR_CHAR[0]}}" \ "${todo_segment// /${PROGRESS_BAR_CHAR[1]}}" \ "$compl_segment" } parse_output() { # trap if shell column count change trap change_column_size WINCH # while puller() echoes while read -r line; do if [[ "$line" =~ ^/ ]];then current_repo=$(echo $line | cut -d " " -f 1 | cut -d "/" -f 5-7 | sed 's/\//::/g') iteration=$(echo $line | cut -d " " -f 2) printf -v info "Pulling %-35s %s" $current_repo draw_progressbar \ "$iteration" \ "$PULL_ITER" \ "$info" else printf >&2 "\033[0K\r" printf "%s\n" "$line" fi done } change_column_size() { printf >&2 "%${COLUMNS}s" "" printf >&2 "\033[0K\r" COLUMNS=$(tput cols) } main() { COLUMNS=$(tput cols) puller > >(parse_output) } main exit 0