You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
2.6 KiB
126 lines
2.6 KiB
#!/usr/bin/env bash |
|
|
|
declare -A colors |
|
colors[red]=$(tput setaf 1) |
|
colors[green]=$(tput setaf 2) |
|
colors[blue]=$(tput setaf 4) |
|
colors[reset]=$(tput sgr0) |
|
declare processes=4 |
|
declare quiet |
|
declare force |
|
declare -a dirs |
|
declare -a ignore_dir |
|
declare -a ignore_dirs |
|
declare -a errs |
|
|
|
usage() { |
|
LESS=-FEXR less <<'HELP' |
|
gitup [OPTIONS] [dirs] |
|
|
|
search for git repos and update them |
|
|
|
if unspecified, dir defaults to $HOME |
|
|
|
-i [dir] comma separated list of directory paths to not search |
|
-p [number] how many processes to run `git pull` in parallel |
|
-q quiet level, may be stacked |
|
first level suppresses output from `git pull` |
|
second level suppresses job info |
|
-F don't run interactively, `git pull` all dirs |
|
use with caution, make sure you know which dirs will be matched |
|
works best if gitup is provided a list of dirs known to have git repos |
|
-h print this help |
|
HELP |
|
} |
|
|
|
color() { |
|
local c |
|
c="$1" |
|
shift |
|
printf '%s' "${colors[$c]}" |
|
printf '%s\n' "$@" |
|
printf '%s' "${colors[reset]}" |
|
} |
|
|
|
err() { |
|
color red "$@" >&2 |
|
} |
|
|
|
die() { |
|
[[ -n "$1" ]] && err "$1" |
|
exit 1 |
|
} |
|
|
|
has() { |
|
local verbose |
|
if [[ $1 = '-v' ]]; then |
|
verbose=1 |
|
shift |
|
fi |
|
for c; do c="${c%% *}" |
|
if ! command -v "$c" &> /dev/null; then |
|
(( "$verbose" > 0 )) && err "$c not found" |
|
return 1 |
|
fi |
|
done |
|
} |
|
|
|
has -v fzf git || die |
|
|
|
while getopts ':hqp:i:F' x; do o="$OPTARG" |
|
case "$x" in |
|
h) usage; exit; ;; |
|
p) processes="$o" ;; |
|
q) (( ++quiet )) ;; |
|
i) IFS=',' read -ra ignore_dir <<< "$o" ;; |
|
F) (( ++force )) ;; |
|
esac |
|
done |
|
shift $(( OPTIND - 1 )) |
|
|
|
while :; do |
|
if [[ -d "$1" ]]; then |
|
dirs+=( "$1" ) |
|
fi |
|
shift || break |
|
done |
|
|
|
for o in "${ignore_dir[@]}"; do |
|
ignore_dirs+=( -path "*/$o" -o ) |
|
done |
|
|
|
(( ${#dirs[@]} > 0 )) || dirs=("$HOME") |
|
|
|
mapfile -t repos < <(find "${dirs[@]}" \ |
|
\( "${ignore_dirs[@]}" \ |
|
-fstype 'devfs' \ |
|
-o -fstype 'devtmpfs' \ |
|
-o -fstype 'proc' \ |
|
\) -prune -o -name '.git' -printf '%h\n' 2> /dev/null | |
|
fzf --multi --cycle --inline-info +s -e ${force:+-f /}) |
|
|
|
(( ${#repos[@]} > 0 )) || exit |
|
|
|
update() { |
|
local name dir |
|
dir="$1" |
|
name="${dir##*/}" |
|
(( quiet > 1 )) || color blue ":: updating $name" |
|
if git -C "$dir" pull ${quiet:+-q}; then |
|
(( quiet > 1 )) || color green ":: updated $name" |
|
else |
|
errs+=( "$name" ) |
|
fi |
|
} |
|
|
|
for d in "${repos[@]}"; do |
|
(( count++ >= processes )) && wait -n |
|
update "$d" & |
|
done |
|
wait |
|
|
|
if (( "${#errs[@]}" > 0 )); then |
|
color red 'The following packages failed to update:' |
|
color red " ${errs[*]}" |
|
fi |
|
color green "updated ${#repos[@]} repos"
|
|
|