blob: 885aae2018730f9037cb2a51523663af70ff7d2c (
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
#!/usr/bin/env bash
BASEDIR=/git
C_bg_green=$(echo -e "\e[42m")
C_bg_magenta=$(echo -e "\e[45m")
C_bg_default=$(echo -e "\e[49m")
C_bg_lblue=$(echo -e "\e[104m")
_getent() {
local db=$1
local key=$2
getent $db $key | cut -d ':' -f 1
}
_list_repo_dirs() {
find "$1" -maxdepth 6 -type d -not -path '*.git/*' -name '*.git' 2>/dev/null
}
do_list() {
if [ -n "$1" ]; then
local root_path=$(readlink -f "$1")
else
local root_path=$BASEDIR
fi
echo -n "Working.. listing repositories under $root_path"
for repo_path in $(_list_repo_dirs $root_path | sort); do
echo -ne "\r" # to remove working
eval $(stat --format 'local repo_path_uid=%u repo_path_gid=%g repo_path_mode=%a' "$repo_path")
if [ "$repo_path_uid" != "$UID" ]; then
# so there must be a matching gid
local pass=false
for user_gid in $(id -G); do
if [ "$repo_path_gid" == "$user_gid" ]; then
pass=true
fi
done
if ! $pass; then
continue # skip that repo since uid and gids don't match
fi
fi
local shortdesc=$(cut -c 1-40 < "$repo_path/description")
local permissions="owner=$(_getent passwd $repo_path_uid)"
local color="$C_bg_green"
if [ $(( 0$repo_path_mode & 070 )) -gt 0 ]; then # shared
permissions="$permissions group=$(_getent group $repo_path_gid)"
color="$C_bg_lblue"
fi
if [ $(( 0$repo_path_mode & 07 )) -gt 0 ]; then # public
permissions="$permissions PUBLIC"
color="$C_bg_magenta"
fi
printf "%s%-60s (%s) (%s)\n" "$color" "$repo_path$C_bg_default" "$permissions" "$shortdesc"
done
}
_create_repo() {
local label=$1
local shared=$2
local group=$3
local is_public=$4
read -p 'New repository name.git: '
local repo_name=$REPLY
if ! `expr "$repo_name" : '.*\.git' >/dev/null`; then
echo "Repository name must end with .git"
return 1
fi
local repo_dir=$BASEDIR/$USER/${repo_name}
test \! -e "$repo_dir" || { echo "Repo $repo_dir already exist"; exit 1; }
read -p 'Set Description: '
local repo_desc=$REPLY
read -p "Create $label in $repo_dir Ok? (y/N)"
test "$REPLY" == "y" || exit 1
mkdir -p "$repo_dir"
git init -q --bare --shared=$shared "$repo_dir"
chgrp -R "$group" "$repo_dir"
echo "$repo_desc" > "$repo_dir/description"
if $is_public; then
touch "$repo_dir/PUBLIC"
echo "created $repo_dir/PUBLIC to expose via cgit"
fi
echo "done creating $label in $repo_dir"
echo "use 'git repo show $repo_dir' for details"
return 0
}
do_create_public() {
_create_repo "public repository" "0664" "share" true
return $?
}
do_create_shared() {
_create_repo "group-writeable repository" "0660" "share" false
return $?
}
do_create_private() {
_create_repo "private repository" "0600" "$USER" false
return $?
}
do_show() {
for repo_path in $*; do
if ! [ -f "$repo_path/HEAD" ]; then
repo_path="$BASEDIR/$repo_path"
fi
if ! [ -f "$repo_path/HEAD" ]; then
echo "Not a git repository: $repo_path"
continue
fi
local repo_file_mode=$(stat --format %a "$repo_path")
local repo_file_uid=$(stat --format %u "$repo_path")
local repo_file_user=$(_getent passwd $repo_file_uid)
local repo_file_gid=$(stat --format %g "$repo_path")
local repo_file_group=$(_getent group $repo_file_gid)
local repo_git_shared=$(GIT_DIR="$repo_path" git config --get core.sharedrepository)
echo " Directory: $repo_path"
echo " ✔ Permissions mode ${repo_file_mode} (uid=${repo_file_uid}/${repo_file_user} gid=${repo_file_gid}/${repo_file_group})"
echo " git core.sharedrepository=$repo_git_shared"
echo " ⚡ Clone read/write SSH: git clone 'ssh://localnet.cc${repo_path}'"
if [ $(( 0$repo_file_mode & 07 )) -gt 0 ]; then
echo " Clone read/- HTTP: git clone 'http://localnet.cc/cgit/cgit.cgi/${repo_path#$BASEDIR/}'"
fi
echo " Update remote: git remote set-url origin 'ssh://localnet.cc${repo_path}"
echo " ☛ To update description execute: $EDITOR $repo_path/description"
echo ""
done
}
do_mirror() {
local root_path=$(readlink -f "$1")
for repo_path in $(_list_repo_dirs $root_path); do
local is_mirror=$(GIT_DIR="$repo_path" git config --get remote.origin.mirror)
if [ "$is_mirror" != "true" ]; then
continue # skip non-mirror repo
fi
echo "Mirror $repo_path from $(GIT_DIR="$repo_path" git config --get remote.origin.url)"
GIT_DIR="$repo_path" git fetch --force --prune origin
done
}
do_make_public() {
local repo_path=$1
test -f "$repo_path/HEAD" || { echo "$repo_path is not a git repository"; exit 1; }
set -x
git init -q --bare --shared=0664 "$repo_path"
find "$repo_path" -type d -exec chown $USER:share \{\} \;
find "$repo_path" -type d -exec chmod 0775 \{\} \;
find "$repo_path" -type f -exec chmod 0664 \{\} \;
touch "$repo_path/PUBLIC"
set +x
}
do_make_shared() {
local repo_path=$1
test -f "$repo_path/HEAD" || { echo "$repo_path is not a git repository"; exit 1; }
set -x
git init -q --bare --shared=0660 "$repo_path"
find "$repo_path" -type d -exec chown $USER:share \{\} \;
find "$repo_path" -type d -exec chmod 0770 \{\} \;
find "$repo_path" -type f -exec chmod 0660 \{\} \;
chgrp -R share "$repo_path"
rm -f "$repo_path/PUBLIC"
set +x
}
do_make_private() {
local repo_path=$1
test -f "$repo_path/HEAD" || { echo "$repo_path is not a git repository"; exit 1; }
set -x
git init -q --bare --shared=0600 "$repo_path"
find "$repo_path" -type d -exec chown $USER:$USER \{\} \;
find "$repo_path" -type d -exec chmod 0700 \{\} \;
find "$repo_path" -type f -exec chmod 0600 \{\} \;
chgrp -R $USER "$repo_path"
rm -f "$repo_path/PUBLIC"
set +x
}
case "$1" in
list) do_list "$2" ;;
create-public) do_create_public ;;
create-shared) do_create_shared ;;
create-private) do_create_private ;;
make-public) do_make_public "$2" ;;
make-shared) do_make_shared "$2" ;;
make-private) do_make_private "$2" ;;
show)
shift
do_show $*
;;
mirror) do_mirror "$2" ;;
*)
cat <<HERE
Unknown subcommand: '$1'
Subcommands of git repo:
list [<dir>] List infos (optional: only below <dir>)
show <dir...> Show Commands for repo <dir>
mirror <dir> Mirror git repositories under <dir> by looking
for 'Mirror for https://..' in description"
create-public Create new repository that is
- Read/Write by Owner
- Read/Write by 'share' group.
- Read-Only through www via cgit
create-shared Create new repository that is
- Read/Write by Owner
- Read/Write by 'share' group.
create-private Create new repository that is
- Read/Write by Owner only
make-public <dir> Change permissions to public
make-shared <dir> Change permissions to shared
make-private <dir> Change permissions to private
☛ Base directory of repositories: $BASEDIR
☛ Color codes: ${C_bg_magenta}public${C_bg_default}, ${C_bg_lblue}shared${C_bg_default}, ${C_bg_green}private${C_bg_default}
☛ For limited ssh-access with current user configure ~/.ssh/authorized_keys with:
command=\"git shell -c \\\"\$SSH_ORIGINAL_COMMAND\\\"\",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB3.....
HERE
;;
esac
|