util-linux: move package to package/system/utils
[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 --color | grep -vE '^. master$'
100 }
101
102 env_diff() {
103         env_init
104         env_sync_data
105         git diff --cached --color
106         env_link_config
107 }
108
109 env_save() {
110         env_init
111         env_sync
112         env_link_config
113 }
114
115 env_revert() {
116         env_init
117         env_do_reset
118         env_link_config
119 }
120
121 env_ask_sync() {
122         env_sync_data
123         LINES="$(env_diff | wc -l)" # implies env_init
124         [ "$LINES" -gt 0 ] && {
125                 if ask_bool 1 "Do you want to save your changes"; then
126                         env_sync
127                 else
128                         env_do_reset
129                 fi
130         }
131 }
132
133 env_clear() {
134         env_init
135         [ -L "$BASEDIR/.config" ] && rm -f "$BASEDIR/.config"
136         [ -L "$BASEDIR/files" ] && rm -f "$BASEDIR/files"
137         [ -f "$ENVDIR/.config" ] || ( cd "$ENVDIR/files" && find | grep -vE '^\.$' > /dev/null )
138         env_sync_data
139         if ask_bool 1 "Do you want to keep your current config and files"; then
140                 mkdir -p "$BASEDIR/files"
141                 shopt -s dotglob
142                 cp -a "$ENVDIR/files/"* "$BASEDIR/files" 2>/dev/null >/dev/null
143                 shopt -u dotglob
144                 cp "$ENVDIR/.config" "$BASEDIR/"
145         else
146                 rm -rf "$BASEDIR/files" "$BASEDIR/.config"
147         fi
148         cd "$BASEDIR"
149         rm -rf "$ENVDIR"
150 }
151
152 env_delete() {
153         local name="${1##*/}"
154         env_init
155         [ -z "$name" ] && usage
156         branch="$(git branch | grep '^\* ' | awk '{print $2}')"
157         [ "$name" = "$branch" ] && error "cannot delete the currently selected environment"
158         git branch -D "$name"
159 }
160
161 env_switch() {
162         local name="${1##*/}"
163         [ -z "$name" ] && usage
164
165         env_init
166         env_ask_sync
167         git checkout "$name" || error "environment '$name' not found"
168         env_link_config
169 }
170
171 env_rename() {
172         local NAME="${1##*/}"
173         env_init
174         git branch -m "$NAME"
175 }
176
177 env_new() {
178         local NAME="$1"
179         local branch
180         local from="master"
181
182         [ -z "$NAME" ] && usage
183         env_init 1
184         
185         branch="$(git branch | grep '^\* ' | awk '{print $2}')"
186         if [ -n "$branch" -a "$branch" != "master" ]; then
187                 env_ask_sync
188                 if ask_bool 0 "Do you want to clone the current environment?"; then
189                         from="$branch"
190                 fi
191                 rm -f "$BASEDIR/.config" "$BASEDIR/files"
192         fi
193         git checkout -b "$1" "$from"
194         if [ -f "$BASEDIR/.config" -o -d "$BASEDIR/files" ]; then
195                 if ask_bool 1 "Do you want to start your configuration repository with the current configuration?"; then
196                         [ -d "$BASEDIR/files" -a \! -L "$BASEDIR/files" ] && {
197                                 mkdir -p "$ENVDIR/files"
198                                 shopt -s dotglob
199                                 mv "$BASEDIR/files/"* "$ENVDIR/files/" 2>/dev/null
200                                 shopt -u dotglob
201                                 rmdir "$BASEDIR/files"
202                         }
203                         env_sync
204                 else
205                         rm -rf "$BASEDIR/.config" "$BASEDIR/files"
206                 fi
207         fi
208         env_link_config
209 }
210
211 COMMAND="$1"; shift
212 case "$COMMAND" in
213         help) usage 0;;
214         new) env_new "$@";;
215         list) env_list "$@";;
216         clear) env_clear "$@";;
217         switch) env_switch "$@";;
218         delete) env_delete "$@";;
219         rename) env_rename "$@";;
220         diff) env_diff "$@";;
221         save) env_save "$@";;
222         revert) env_revert "$@";;
223         *) usage;;
224 esac