]> Pileus Git - ~andy/sunrise/blob - app-portage/overlay-utils/files/sunrise-commit
app-portage/overlay-utils: Version bump, switch to git
[~andy/sunrise] / app-portage / overlay-utils / files / sunrise-commit
1 #!/bin/bash
2 # sunrise-commit - Automates the Gentoo Sunrise Overlay commit process
3 # Released into the public domain
4
5 source /etc/init.d/functions.sh
6
7 BLUE=$BRACKET
8 BOLD=$'\e[0;01m'
9 DARKGREEN=$'\e[32m'
10 GREEN=$GOOD
11 LIGHTBLUE=$HILITE
12 RED=$BAD
13 YELLOW=$WARN
14
15 commit_path=
16
17 current_git_status=( )
18 cwd_is_ebuild_dir=0
19 items_added=( )
20 items_deleted=( )
21 items_modified=( )
22 items_not_version_controlled=( )
23 opt_changelog=0
24 opt_noformat=0
25 opt_norepoman=0
26 opt_local=0
27 opt_quiet=0
28 opt_verbose=0
29
30 changelog_append() {
31         if [[ $opt_changelog == 1 ]] ; then
32                 get_current_git_status
33                 if [[ "${current_git_status[*]}" =~ "ChangeLog" ]] ; then
34                         echo "!!! Error: Only one ChangeLog entry should be made per commit, and you have"
35                         echo "!!! already modified your ChangeLog locally since your last commit. To keep the"
36                         echo "!!! pre-existing modifications please run sunrise-commit again without the -c"
37                         echo "!!! option. To discard the pre-existing modifications run:"
38                         echo "!!!   git reset HEAD ChangeLog ; git checkout ChangeLog"
39                         echo "!!!"
40                         echo -n "!!! "
41                         echo -n "${BOLD}Are you SURE you want to append to ChangeLog?${NORMAL} [${GREEN}No${NORMAL}/${RED}Yes${NORMAL}] "
42                         read choice
43                         echo
44                         case "$choice" in
45                                 yes|Yes|YES)
46                                         ;;
47
48                                 n*|N*|"")
49                                         echo "Aborting.  Run sunrise-commit without the -c this time around."
50                                         exit 1 ;;
51
52                                 *)
53                                         echo "Unrecognized response - assuming no."
54                                         echo "Aborting.  Run sunrise-commit without the -c this time around."
55                                         exit 1 ;;
56                         esac
57                 fi
58                 ebegin "Appending/creating ChangeLog"
59                 echangelog "$*"
60                 eend $?
61         fi
62 }
63
64 create_digests() {
65         if [[ $cwd_is_ebuild_dir == 1 ]] ; then
66                 ebegin "Digesting ebuilds"
67                 for i in *.ebuild ; do
68                         ebuild "$i" manifest
69                         break
70                 done
71                 eend $?
72         fi
73 }
74
75 # Sort current changed items into arrays based on symbols in `git status`
76 # output. For now we're only concerned with the symbols in the first column of
77 # the output. See `git help status` for symbol definitions.
78 #
79 # Returns with exit status 1 if the current dir isn't under version control.
80 get_current_git_status() {
81         local IFS_SAVED="$IFS"
82         local item column_1 column_2
83         IFS=$'\n'
84         current_git_status=( )
85         items_added=( )
86         items_deleted=( )
87         items_modified=( )
88         items_not_version_controlled=( )
89         items2_deleted=( )
90         items2_modified=( )
91         for line in $(git status --porcelain -uall 2>&1) ; do
92                 [[ "$line" =~ "Not a git repository" ]] && return 1
93                 current_git_status+=( "$line" )
94                 column_1=${line:0:1}
95                 column_2=${line:1:1}
96                 item=${line:3}
97
98                 # Use the first item in the commit message
99                 if [[ -z $commit_path ]]; then
100                         case "$item" in
101                                 *-*/*/*)
102                                         commit_path=$(awk -F/ '{ print $1 "/" $2 }' <<<"$item") ;;
103                                 *)
104                                         # Not a package; use full path
105                                         commit_path=$item ;;
106                         esac
107                 fi
108
109                 case $column_1 in
110                         A)   items_added+=( "$item" ) ;;
111                         D)   items_deleted+=( "$item" ) ;;
112                         M)   items_modified+=( "$item" ) ;;
113                         R)      case $column_2 in
114                                         D)   items2_deleted+=( "$item" ) ;;
115                                         M)   items2_modified+=( "$(echo "${item}" | cut -d ' ' -f3 )" ) ;;
116                                 esac ;;
117                         "?")   items_not_version_controlled+=( "$item" ) ;;
118                 esac
119                 case $column_1 in
120                         ' '|A|D|M)
121                         case $column_2 in
122                                 D)   items2_deleted+=( "$item" ) ;;
123                                 M)   items2_modified+=( "$item" ) ;;
124                         esac ;;
125                 esac
126         done
127         IFS="$IFS_SAVED"
128 }
129
130 repoman_check() {
131         if [[ $opt_norepoman == 0 ]] ; then
132                 if [[ $cwd_is_ebuild_dir == 1 ]] ; then
133                         ebegin "Running repoman"
134                         export PORTDIR_OVERLAY="$(dirname "$(dirname "$(pwd)")")"
135                         repoman
136                         eend $?
137                 fi
138         fi
139 }
140
141 git_add() {
142         local num_unversioned_dirs=0
143
144         while ! [[ -e .git ]] ; do
145                 (( num_unversioned_dirs++ ))
146                 pushd .. >/dev/null 2>&1
147                 if [[ $? == 1 ]] ; then
148                         (( num_unversioned_dirs-- ))
149                         cd .. 2>/dev/null
150                 fi
151         done
152
153         get_current_git_status
154
155         ebegin "Adding local changes to working copy"
156         if [[ ${#items_not_version_controlled[*]} > 0 ]] ; then
157                 if [[ $opt_verbose == 1 ]] ; then
158                         git add -v -- "${items_not_version_controlled[@]}" || set $?
159                 else
160                         git add -- "${items_not_version_controlled[@]}" || set $?
161                 fi
162         fi
163
164         if [[ ${#items2_modified[*]} > 0 ]] ; then
165                 if [[ $opt_verbose == 1 ]] ; then
166                         git add -v -- "${items2_modified[@]}" || set $?
167                 else
168                         git add -- "${items2_modified[@]}" || set $?
169                 fi
170         fi
171
172         if [[ ${#items2_deleted[*]} > 0 ]] ; then
173                 git rm -- "${items2_deleted[@]}" || set $?
174         fi
175         eend ${1:-0}
176
177         for (( i=num_unversioned_dirs ; i > 0 ; i-- )) ; do
178                 popd >/dev/null
179         done
180
181         return ${1:-0}
182 }
183
184 git_commit() {
185         local commit_message="$*"
186
187         get_current_git_status
188         if [[ ${#current_git_status[*]} == 0 ]] ; then
189                 echo "!!! Error: No working copy changes found in current directory. Aborting commit."
190                 exit 1
191         fi
192
193         if [[ $opt_noformat == 0 ]] ; then
194                 commit_message="${commit_path}: ${commit_message}"
195         fi
196
197         echo
198         echo "${DARKGREEN}The following local changes will be committed to the repository:${NORMAL}"
199         echo
200
201         get_current_git_status
202         for item in "${current_git_status[@]}" ; do
203                 echo "$item"
204         done
205
206         echo
207         echo "${DARKGREEN}The following commit message will be used:${NORMAL}"
208         echo
209         echo "$commit_message"
210
211         if [[ $opt_quiet == 0 ]] ; then
212                 echo
213                 echo -n "${BOLD}Commit changes?${NORMAL} [${GREEN}Yes${NORMAL}/${RED}No${NORMAL}] "
214                 read choice
215                 echo
216
217                 case "$choice" in
218                         y*|Y*|"")
219                                 ;;
220
221                         *)
222                                 echo "Quitting."
223                                 echo
224                                 return 1 ;;
225                 esac
226         fi
227
228         ebegin "Committing working copy to repository"
229         git commit -m "$commit_message"
230         eend $?
231 }
232
233 git_up() {
234         if [[ $opt_local == 0 ]] ; then
235
236                 ebegin "Updating working copy to latest version from repository"
237
238                 if [[ $opt_verbose == 1 ]] ; then
239                         git pull --rebase -v origin master || set $?  
240                 else
241                         git pull --rebase origin master || set $?
242                 fi
243
244                 eend ${1:-0}
245
246                 get_current_git_status
247         fi
248         return ${1:-0}
249 }
250
251 git_push() {
252         if [[ $opt_local == 0 ]] ; then
253                 ebegin "Pushing commit"
254
255                 if [[ $opt_verbose == 1 ]] ; then
256                         git push -v || set $?
257                 else
258                         git push || set $?
259                 fi
260                 eend $?
261         fi
262 }
263
264 usage() {
265 cat << EOF
266 ${BOLD}Usage:${NORMAL} ${LIGHTBLUE}sunrise-commit${NORMAL} [ ${GREEN}options${NORMAL} ] ${BLUE}message${NORMAL}
267
268 ${GREEN}options${NORMAL}:
269   ${BOLD}--changelog, -c${NORMAL}  Create a ChangeLog entry using ${BLUE}message${NORMAL}
270   ${BOLD}--help, -h${NORMAL}       Show help
271   ${BOLD}--noformat, -m${NORMAL}   Disable automatic formatting of ${BLUE}message${NORMAL}
272   ${BOLD}--norepoman, -p${NORMAL}  Skip repoman check
273   ${BOLD}--local, -l${NORMAL}   Don't pull/push, keep commits local
274   ${BOLD}--quiet, -q${NORMAL}      Don't ask for confirmation
275   ${BOLD}--verbose, -v${NORMAL}    Show detailed information during commit
276
277 ${BLUE}message${NORMAL}:
278   Commit message describing changes and listing names/emails of anyone (other
279   than the commiter) who contributed.
280 EOF
281         exit ${1:-0}
282 }
283
284 [[ -z "$1" ]] && usage 1
285
286 while [[ $# > 0 ]] ; do
287         case "$1" in
288                 --changelog|-c)
289                         if [[ -z "$ECHANGELOG_USER" ]] ; then
290                                 echo "!!! Error: --changelog option requires ECHANGELOG_USER to be set:"
291                                 echo "!!!   export ECHANGELOG_USER=\"Your Name <your@mail.org>\""
292                                 exit 1
293                         fi
294                         opt_changelog=1
295                         shift ;;
296
297                 --help|-h)
298                         usage ;;
299
300                 --noformat|-m)
301                         opt_noformat=1
302                         shift ;;
303
304                 --norepoman|-p)
305                         opt_norepoman=1
306                         shift ;;
307
308                 --local|-l)
309                         opt_local=1
310                         shift ;;
311
312                 --quiet|-q)
313                         opt_quiet=1
314                         shift ;;
315
316                 --verbose|-v)
317                         opt_verbose=1
318                         shift ;;
319
320                 -*)
321                         echo "!!! Error: Unknown option ${1}. See: sunrise-commit -h"
322                         exit 1 ;;
323
324                 *)
325                         break ;;
326         esac
327 done
328
329 if [[ -z "$*" ]] ; then
330         echo "!!! Error: You must supply a commit message. See: sunrise-commit -h"
331         exit 1
332 fi
333
334 (shopt -s nullglob; f=(*.ebuild); [[ ${#f[*]} -ne 0 ]] ) && cwd_is_ebuild_dir=1
335
336 [[ $cwd_is_ebuild_dir == 1 && ! -e metadata.xml ]] && cp ../../skel.metadata.xml metadata.xml >/dev/null 2>&1
337
338 git_add || exit $?
339 changelog_append "$*" || exit $?
340 create_digests || exit $?
341 git_add || exit $?
342 repoman_check || exit $?
343 git_commit "$*" || exit $?
344 git_up || exit $?
345 git_push || exit $?