63e26eb154da83b638b8c2dc766edbc8a6f98f3f
[openwrt/staging/stintel.git] / scripts / env
1 #!/usr/bin/env bash
2 BASEDIR="$PWD"
3 ENVDIR="$PWD/env"
4 export GREP_OPTIONS=
5
6 usage() {
7 cat <<EOF
8 Usage: $0 [options] <command> [arguments]
9 Commands:
10 help This help text
11 list List environments
12 clear Delete all environment and revert to flat config/files
13 new <name> Create a new environment
14 switch <name> Switch to a different environment
15 delete <name> Delete an environment
16 rename <newname> Rename the current environment
17 diff Show differences between current state and environment
18 save [message] Save your changes to the environment, optionally using
19 the given commit message
20 revert Revert your changes since last save
21
22 Options:
23
24 EOF
25 exit ${1:-1}
26 }
27
28 error() {
29 echo "$0: $*"
30 exit 1
31 }
32
33 ask_bool() {
34 local DEFAULT="$1"; shift
35 local def defstr val
36 case "$DEFAULT" in
37 1) def=0; defstr="Y/n";;
38 0) def=1; defstr="y/N";;
39 *) def=; defstr="y/n";;
40 esac
41 while [ -z "$val" ]; do
42 local VAL
43
44 echo -n "$* ($defstr): "
45 read VAL
46 case "$VAL" in
47 y*|Y*) val=0;;
48 n*|N*) val=1;;
49 *) val="$def";;
50 esac
51 done
52 return "$val"
53 }
54
55 env_init() {
56 local CREATE="$1"
57 if [ -z "$CREATE" ]; then
58 [ -d "$ENVDIR" ] || exit 0
59 fi
60 [ -x "$(which git 2>/dev/null)" ] || error "Git is not installed"
61 mkdir -p "$ENVDIR" || error "Failed to create the environment directory"
62 cd "$ENVDIR" || error "Failed to switch to the environment directory"
63 [ -d .git ] || {
64 git init &&
65 touch .config &&
66 mkdir files &&
67 git add . &&
68 git commit -q -m "Initial import"
69 } || {
70 rm -rf .git
71 error "Failed to initialize the environment directory"
72 }
73 }
74
75 env_sync_data() {
76 [ \! -L "$BASEDIR/.config" -a -f "$BASEDIR/.config" ] && mv "$BASEDIR/.config" "$ENVDIR"
77 git add .
78 git add -u
79 }
80
81 env_sync() {
82 local STR="$1"
83 env_sync_data
84 git commit -m "${STR:-Update} at $(date)"
85 }
86
87 env_link_config() {
88 rm -f "$BASEDIR/.config"
89 ln -s env/.config "$BASEDIR/.config"
90 mkdir -p "$ENVDIR/files"
91 [ -L "$BASEDIR/files" ] || ln -s env/files "$BASEDIR/files"
92 }
93
94 env_do_reset() {
95 git reset --hard HEAD
96 git clean -d -f
97 }
98
99 env_list() {
100 env_init
101 git branch --color | grep -vE '^. master$'
102 }
103
104 env_diff() {
105 env_init
106 env_sync_data
107 git diff --cached --color
108 env_link_config
109 }
110
111 env_save() {
112 env_init
113 env_sync "$@"
114 env_link_config
115 }
116
117 env_revert() {
118 env_init
119 env_do_reset
120 env_link_config
121 }
122
123 env_ask_sync() {
124 env_sync_data
125 LINES="$(env_diff | wc -l)" # implies env_init
126 [ "$LINES" -gt 0 ] && {
127 if ask_bool 1 "Do you want to save your changes"; then
128 env_sync
129 else
130 env_do_reset
131 fi
132 }
133 }
134
135 env_clear() {
136 env_init
137 [ -L "$BASEDIR/.config" ] && rm -f "$BASEDIR/.config"
138 [ -L "$BASEDIR/files" ] && rm -f "$BASEDIR/files"
139 [ -f "$ENVDIR/.config" ] || ( cd "$ENVDIR/files" && find | grep -vE '^\.$' > /dev/null )
140 env_sync_data
141 if ask_bool 1 "Do you want to keep your current config and files"; then
142 mkdir -p "$BASEDIR/files"
143 shopt -s dotglob
144 cp -a "$ENVDIR/files/"* "$BASEDIR/files" 2>/dev/null >/dev/null
145 shopt -u dotglob
146 cp "$ENVDIR/.config" "$BASEDIR/"
147 else
148 rm -rf "$BASEDIR/files" "$BASEDIR/.config"
149 fi
150 cd "$BASEDIR"
151 rm -rf "$ENVDIR"
152 }
153
154 env_delete() {
155 local name="${1##*/}"
156 env_init
157 [ -z "$name" ] && usage
158 branch="$(git branch | grep '^\* ' | awk '{print $2}')"
159 [ "$name" = "$branch" ] && error "cannot delete the currently selected environment"
160 git branch -D "$name"
161 }
162
163 env_switch() {
164 local name="${1##*/}"
165 [ -z "$name" ] && usage
166
167 env_init
168 env_ask_sync
169 git checkout "$name" || error "environment '$name' not found"
170 env_link_config
171 }
172
173 env_rename() {
174 local NAME="${1##*/}"
175 env_init
176 git branch -m "$NAME"
177 }
178
179 env_new() {
180 local NAME="$1"
181 local branch
182 local from="master"
183
184 [ -z "$NAME" ] && usage
185 env_init 1
186
187 branch="$(git branch | grep '^\* ' | awk '{print $2}')"
188 if [ -n "$branch" -a "$branch" != "master" ]; then
189 env_ask_sync
190 if ask_bool 0 "Do you want to clone the current environment?"; then
191 from="$branch"
192 fi
193 rm -f "$BASEDIR/.config" "$BASEDIR/files"
194 fi
195 git checkout -b "$1" "$from"
196 if [ -f "$BASEDIR/.config" -o -d "$BASEDIR/files" ]; then
197 if ask_bool 1 "Do you want to start your configuration repository with the current configuration?"; then
198 [ -d "$BASEDIR/files" -a \! -L "$BASEDIR/files" ] && {
199 mkdir -p "$ENVDIR/files"
200 shopt -s dotglob
201 mv "$BASEDIR/files/"* "$ENVDIR/files/" 2>/dev/null
202 shopt -u dotglob
203 rmdir "$BASEDIR/files"
204 }
205 env_sync
206 else
207 rm -rf "$BASEDIR/.config" "$BASEDIR/files"
208 fi
209 fi
210 env_link_config
211 }
212
213 COMMAND="$1"; shift
214 case "$COMMAND" in
215 help) usage 0;;
216 new) env_new "$@";;
217 list) env_list "$@";;
218 clear) env_clear "$@";;
219 switch) env_switch "$@";;
220 delete) env_delete "$@";;
221 rename) env_rename "$@";;
222 diff) env_diff "$@";;
223 save) env_save "$@";;
224 revert) env_revert "$@";;
225 *) usage;;
226 esac