-
Notifications
You must be signed in to change notification settings - Fork 1
/
git-etc
executable file
·169 lines (153 loc) · 3.86 KB
/
git-etc
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
#!/bin/sh
# Track and restore system files and metadata in git. Use together with bmount.
#
# Usage example:
#
# # to backup
# $ git-etc init
# $ bmount insert /etc/apache2/sites-available /etc/apt
# $ git add . && git commit
#
# # to restore
# $ git clone <url> && git-etc init
# $ git-etc install
#
# TODO: add the functionality from rsconf that automatically detects changed or
# new configs (relative to dpkg's database) in /etc
# development directories, override on install
SCRIPT_HOME="$(dirname "$(readlink -f "$0")")"
DATADIR="$SCRIPT_HOME/share"
ERR_GIT_META_NOT_FOUND=36
ERR_PERL_LCHOWN_NOT_FOUND=37
ERR_GIT_DIFF_NON_EMPTY=38
set -o errexit
pre_test() {
local h="$(git rev-parse --git-dir)/hooks"
if ! grep -Rq "git meta" "$h"; then
echo >&2 "not a git-etc-enabled git repo. run $0 init to fix this."
exit $ERR_REPO_NOT_GITETC
fi
}
git_install_hook() {
local hdir="$1"
local htype="$2"
local hname="$3"
local cleanmarker="## clean $hname ##"
local hfile="$hdir/$htype"
if [ -e "$hfile" ] && ! grep -qF "$cleanmarker" "$hfile"; then
echo "git hook $htype already exists; please incorporate the following into it:"
echo "-- $hfile"
echo "#!/bin/sh"; cat
echo "-- EOF"
else
{ echo "#!/bin/sh"; echo "$cleanmarker"; cat; } > "$hfile"
chmod +x "$hfile"
fi
}
git_install_meta_r_hook() {
cat << EOF | git_install_hook "$@" git_meta_r_hook
if which git-meta >/dev/null; then
git-etc meta-r "\$@"
fi
EOF
}
git_etc_meta_r() {
SUBDIRECTORY_OK=1 . "$(git --exec-path)/git-sh-setup"
cd_to_toplevel
require_work_tree
git meta -r
# only store metadata for files tracked by bmount
for host_bind in $(grep -o -P '(^|.*/).bmrc\s' ".gitmeta"); do
tail -n+2 "$host_bind" | while read source; do
source="$(echo -e "$source")"
source="${source%/}"
echo "$(dirname "$host_bind")/${source#/}"
done
done | sed -e 's|^\./\+||g' | sort -u | grep -vxF '.' | grep -F -f- ".gitmeta" > ".gitmeta.new" || true
mv ".gitmeta.new" ".gitmeta"
git add ".gitmeta"
exit $?
}
git_install_meta_w_hook() {
cat << EOF | git_install_hook "$@" git_meta_w_hook
if which git-meta >/dev/null; then
git meta -w
fi
EOF
}
gitetc_init() {
git init
if ! which git-meta > /dev/null; then
echo >&2 "you need to add git-meta to your path."
exit $ERR_GIT_META_NOT_FOUND
elif ! echo "use Lchown;" | perl; then
echo >&2 "you need to install the Lchown perl module, also called liblchown-perl."
exit $ERR_PERL_LCHOWN_NOT_FOUND
fi
local h="$(git rev-parse --git-dir)/hooks"
git_install_meta_r_hook "$h" pre-commit
git_install_meta_w_hook "$h" post-checkout
git_install_meta_w_hook "$h" post-merge
bmount init import
}
sudogit() {
sudo git "$@"
git reset # re-init index with user's own perms
}
gitetc_install() {
if ! git diff --quiet; then
echo >&2 "abort: git detected changes"
git status
exit $ERR_GIT_DIFF_NON_EMPTY
fi
sudo "$(which bmount)" -u . umountAll
sudogit checkout -- .
sudogit meta -w
sudo "$(which bmount)" -u . mountAll
test "$(bmount -u . status)" = "FULL"
bmount list | while read pp; do
pp="$(echo -e "$pp")" # bmount escapes special chars in list output
local pp_rel="${pp#/}"
if [ -d "$pp_rel" ]; then
sudogit checkout -- "$pp_rel"
else
# git checkout tries to unlink, which doesn't work for bind-mounted files
git cat-file -p "$(git rev-parse "HEAD:$pp_rel")" | sudo tee "$pp_rel" >/dev/null
fi
done
sudogit meta -w
}
USAGE="Usage: $0 [-h] [init|install]"
while getopts r:h o; do
case $o in
h ) subcmd=help;;
\? ) subcmd=?;;
esac
done
shift `expr $OPTIND - 1`
subcmd="${subcmd:-$1}"
subcmd="${subcmd:-?}"
case $subcmd in
init)
gitetc_init
;;
install)
pre_test
gitetc_install
;;
meta-r)
git_etc_meta_r "$@"
;;
help)
cat <<EOF
$USAGE
subcommands (git repo):
init set up this repo as a git-etc repo (add hooks, etc)
install checkout files to / and set correct permissions.
EOF
;;
*)
echo >&2 "$USAGE"
exit 2
;;
esac