summaryrefslogtreecommitdiff
path: root/bin/common/gt
blob: c16623e35331168c236c205237f836d970670cb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/bin/sh

# Git Trach, track the state of multiple repos from a single file.

# dependencies:
# - git
# - $EDITOR: -e

repos=$HOME/sync/share/git-track.txt
# prevent file not found errors
touch "$repos" || exit 1

help() {
	cat >&2 <<EOF
usage: gt [OPTION]
-a PATH         add repo 
-s              update and show status of each repo
-c COMMAND      run 'git COMMAND' in each repo
-h              show this help
-l              list repos
-e 		edit repos in \$EDITOR
EOF
}

# fetch repository prettily, outputs nothing if failed
fetch() {
	# fetch with one-line printing of progress
	git fetch --progress 2>/dev/null | while read -r line; do # \r\033[0K : clear current line
		printf >&2 '\r\033[0K%s' "$line"
	done
}

# Print repositories prettily
# This function function prints animations (eg. clearing the line)
# to stderr and the final status line is outputted to stdout.
status() {
	while read -r repo; do
		repo_pretty="$(printf '%s' "$repo" | sed "s@$HOME@~@")"

		if [ ! -d "$repo" ]; then
			printf '%s missing\n' "$repo_pretty"
			continue
		fi

		# absolute path
		cd "$repo"

		# replace line with status
		printf >&2 '\r\033[0K'

		status="$(git status --porcelain 2>/dev/null |
			awk '{print $1}' |
			sort | uniq | tr -s '?' |
			tr -d '\n')"
		remote="$(git branch -v 2>/dev/null |
			sed '/^*/!d;s/ahead/↑/;s/behind/↓/;s/[^↓↑]*//g')"

		printf '%s %s %s\n' "$repo_pretty" "$status" "$remote"
	done <"$repos"
}

# run git command in each repo
# $1: command
repos_cmd() {
	while read -r repo; do
		repo_pretty="$(printf '%s' "$repo" | sed "s@$HOME@~@")"
		printf ''\''%s'\'' in %s' "$1" "$repo_pretty"
		(
			cd "$repo"
			git "$1" >/dev/null 2>&1
			[ $? -gt 0 ] && s="x" || s="o"
			printf '\r\033[0K%s: %s\n' "$repo_pretty" "$s"
		)
	done <"$repos"
}

# no options
if [ -z "$1" ]; then
	help
	exit 1
fi

while getopts ":a:c:f:lshe" opt; do
	case "$opt" in
	a)
		cd "$OPTARG" || exit 1
		r="$(git rev-parse --show-toplevel)"
		[ "$r" ] || exit 2

		if grep "$r" "$repos" >/dev/null 2>&1; then
			printf >&2 'added already.\n'
			exit 2
		fi

		printf '%s\n' "$r" >>"$repos"

		printf >&2 'added.\n'
		;;
	c)
		f_command=1
		f_arg="$OPTARG"
		;;
	s) f_status=1 ;;
	l) cat "$repos" ;;
	e) $EDITOR "$repos" ;;
	f) repos="$OPTARG" ;;
	h) help ;;
	:)
		printf >&2 -- '-%s requires argument\n' "$OPTARG"
		exit 1
		;;
	?)
		printf >&2 -- 'Invalid option: -%s\n' "$OPTARG"
		exit 1
		;;
	esac
done

# commands hereafter must happen in order

[ "$(wc -l <"$repos")" -gt 0 ] || exit 0

if [ "$f_command" ]; then
	repos_cmd "$f_arg"
fi

if [ "$f_status" ]; then
	status
fi

# eval "herbe $(status | sed 's/"/\"/g;s/.*/"&"/' | tr '\n' ' ')"