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.

gitup 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #!/usr/bin/env bash
  2. declare -A colors
  3. colors[red]=$(tput setaf 1)
  4. colors[green]=$(tput setaf 2)
  5. colors[blue]=$(tput setaf 4)
  6. colors[reset]=$(tput sgr0)
  7. declare processes=4
  8. declare quiet
  9. declare -a dirs
  10. usage() {
  11. LESS=-FEXR less <<'HELP'
  12. gitup [dir] [OPTIONS]
  13. search for git repos and update them
  14. if unspecified, dir defaults to $HOME
  15. -p [number] how many processes to run git pull in parallel
  16. -q quiet level, may be stacked
  17. first level suppresses output from `git pull`
  18. second level suppresses job info
  19. -h print this help
  20. HELP
  21. }
  22. color() {
  23. local c
  24. c="$1"
  25. shift
  26. printf '%s' "${colors[$c]}" >&2
  27. printf '%s\n' "$@" >&2
  28. printf '%s' "${colors[reset]}" >&2
  29. }
  30. err() {
  31. color red "$@" >&2
  32. }
  33. die() {
  34. [[ -n "$1" ]] && err "$1"
  35. exit 1
  36. }
  37. has() {
  38. local verbose
  39. if [[ $1 = '-v' ]]; then
  40. verbose=1
  41. shift
  42. fi
  43. for c; do c="${c%% *}"
  44. if ! command -v "$c" &> /dev/null; then
  45. (( "$verbose" > 0 )) && err "$c not found"
  46. return 1
  47. fi
  48. done
  49. }
  50. has -v fzf git || die
  51. while getopts ":hqp:" x; do
  52. case "$x" in
  53. h) usage; exit; ;;
  54. p) processes="$OPTARG" ;;
  55. q) (( quiet++ )) ;;
  56. esac
  57. done
  58. shift $(( OPTIND - 1 ))
  59. while :; do
  60. if [[ -d "$1" ]]; then
  61. dirs+=( "$1" )
  62. fi
  63. shift || break
  64. done
  65. (( ${#dirs[@]} > 0 )) || dirs=("$HOME")
  66. mapfile -t repos < <(find -L "${dirs[@]}" -name '.git' -printf '%h\n' 2> /dev/null \
  67. | fzf --multi --cycle --inline-info)
  68. (( ${#repos[@]} > 0 )) || exit
  69. update() {
  70. local name dir
  71. dir="$1"
  72. name="${dir##*/}"
  73. (( quiet > 1 )) || color blue ":: updating $name"
  74. if git -C "$dir" pull ${quiet:+-q}; then
  75. (( quiet > 1 )) || color green ":: updated $name"
  76. else
  77. color red ":: failed to update $name"
  78. fi
  79. }
  80. for d in "${repos[@]}"; do
  81. (( count++ >= processes )) && wait -n
  82. update "$d" &
  83. done
  84. wait
  85. printf '%d repos updated\n' "${#repos[@]}"