summaryrefslogtreecommitdiff
path: root/bin/common/gt
blob: 73213cb1111ebc3ec5a2a7c2cbd55ea15da4d6eb (plain) (blame)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/bin/sh

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

# dependencies:
# - git
# - $EDITOR: -e
# - parallel: optional, if installed will run the commands on all repos with parallel
# - gt-cmd, gt-st

if [ "$GIT_TRACK_REPOS" ]; then
	export REPOS="$GIT_TRACK_REPOS"
else
	export REPOS="$HOME/sync/share/git-track.txt"
fi

# prevent file not found errors
touch "$REPOS" || exit 1

which parallel >/dev/null 2>&1 && parallel=1

help() {
	cat >&2 <<EOF
usage: gt [OPTION]
-a PATH         add repo 
-c COMMAND      run 'git COMMAND' in each repo
-d              be done in every project
-h              show this help
-l              list repos
-e 		edit repos in \$EDITOR
-f FILE         use FILE as list of repos
-u 		pull in repos out of sync
-s 		show status of files and remotes
EOF
}

list_repos() { cut -f 1 -d ' ' "$REPOS"; }
quit_when_no_repos() { 
	if [ "$(wc -l <"$REPOS")" -eq 0 ];
	then 
		>&2 printf 'No repositories added.\n'
		exit 1
	fi
}

# 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
}

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


while getopts ":a:c:f:dlsheu" opt; do
	case "$opt" in
	a)
		if ! cd "$OPTARG" 2>/dev/null; then
			>&2 printf 'Not a directory.\n'
			exit 1
		fi

		repo="$(git rev-parse --show-toplevel)"
		remote_url="$(git remote show -n origin | awk '/^  Fetch/ {print $NF}')"
	        # TODO: check if remote_url is not empty

		if grep "^$repo " "$REPOS" >/dev/null 2>&1; then
			printf >&2 'added already.\n'
			exit 3
		fi

		printf '%s %s\n' "$repo" "$remote_url" >>"$REPOS"

		printf >&2 'added.\n'
		;;
	c)
		quit_when_no_repos
		list_repos |
			if [ "$parallel" ]; then
				parallel gt-cmd "{}" "$OPTARG"
			else
				xargs -I{} gt-cmd "{}" "$OPTARG"
			fi
		;;
    d)
        if [ "$parallel" ]; then
            list_repos |
                parallel 'cd {};
            cd "$(git rev-parse --show-toplevel || printf '\''.\\n'\'')"
            git pull --ff > /dev/null 2>&1
            git add .
            git commit --all -m "checkpoint" > /dev/null 2>&1
            git push > /dev/null 2>&1
            printf '\''{}: done.\n'\'' | sed "s@^$HOME@~@"
            '
        else
            list_repos | while read -r proj
            do
                (
                    cd "$proj"
                    cd "$(git rev-parse --show-toplevel || printf '.\n')"
                    git pull --ff > /dev/null 2>&1
                    git add .
                    git commit --all -m "checkpoint" > /dev/null 2>&1
                    git push > /dev/null 2>&1
                    printf '%s: done.\n' "$proj"
                )
            done
        fi
        ;;
    s) 
		quit_when_no_repos
		list_repos | xargs -I{} gt-st {} ;;
	l) 
		quit_when_no_repos
		list_repos ;;
	e) $EDITOR "$REPOS" ;;
	f) REPOS="$OPTARG" ;;
	u)
		quit_when_no_repos
		>&2 printf 'pull:\n'
		if [ "$parallel" ]; then
			list_repos | parallel gt-cmd {} pull  
		else
			list_repos | xargs -I{} gt-cmd {} pull
		fi

		>&2 printf 'push:\n'
		list_repos |
			xargs -I{} gt-st {} |
			awk -F: '/↑/ {print $1}' |
			sed "s@^~@$HOME@" |
			if [ "$parallel" ]; then
				parallel gt-cmd {} push
			else
				xargs -I{} gt-cmd {} push
			fi
		;;
	h) help ;;
	:)
		printf >&2 -- '-%s requires argument\n' "$OPTARG"
		exit 1
		;;
	?)
		printf >&2 -- 'Invalid option: -%s\n' "$OPTARG"
		exit 1
		;;
	esac
done