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