fixup the previous commit
[racktables] / gateways / git-commit
CommitLineData
033c2594
DO
1#!/bin/sh
2
3# This file is a part of RackTables, a datacenter and server room management
4# framework. See accompanying file "COPYING" for the full copyright and
5# licensing information.
6
7# This script implements a simple (one file at a time) one-way feed into a git
8# repository. To make a commit it takes the following PHP code:
9#
10# $params = array
11# (
51582c54
DO
12# 'u' => 'racktables_pseudo_user',
13# 'r' => '/path/to/repository',
14# 'f' => 'path/to/file/within/the/repository/file.txt',
15# 'm' => 'commit message text',
6204720d 16# 'a' => 'Some Author <user@example.org>',
033c2594
DO
17# );
18# $rc = callScript ('git-commit', $params, $file_contents, $stdout, $stderr);
19#
20# The meaning of $stdout and $stderr is the same as in queryTerminal().
89e549b7 21#
1bba27d1
DO
22# This script uses sudo to switch between the pseudo-users and requires an
23# entry in sudoers along the following lines:
24# httpduser ALL=(racktablesuser) NOPASSWD:/path/to/racktables/gateways/git-commit
033c2594 25
0859a212 26THISFILE=`basename "$0"`
51582c54
DO
27
28usage_and_exit()
29{
30 cat >&2 <<ENDOFMESSAGE
6204720d 31Usage: $THISFILE -u <u> -r <r> -f <f> [-m <m> -a <a>]
51582c54
DO
32 -u <username> A pseudo-user to work as (this script will try to sudo
33 itself if the current user is not the same). The user
34 must be able to write to the repository filesystem and to
35 run "git pull", "git commit" and "git push" without any
36 user interaction (i.e. the git remote must be on a local
37 filesystem or be configured to use SSH keys).
38 -r <repodir> An absolute path to an existing git repository.
39 -f <filepath> A relative path to a file within the repository (if the
40 file or the path do not exist, the missing component(s)
41 will be created automatically).
42 -m <msg> An optional custom commit message instead of the default
43 one. The message may be a multi-line string, in which
44 case it should follow the format recommended in the
45 "discussion" section of the git-commit(1) man page.
6204720d
DO
46 -a <author> An optional git commit author instead of the default or the
47 one previously configured with git-config(1).
51582c54 48ENDOFMESSAGE
033c2594
DO
49 exit 1
50}
51
51582c54
DO
52# Both callScript() and GNU getopt support both short and long option formats.
53# However, use of any getopt normally implies shift, which unsets the $@
54# special parameter and makes it impossible or difficult to pass properly
55# quoted option values to self via sudo. The getopts shell builtin (available
56# in bash, dash and other shells) depends on its own state variables rather
57# than shifting, but supports short options only.
58#
59# The only easy way to use any long options in this script would be to make
60# the username a fixed argument, which could be tested before the getopt
61# processing, but that would not look consistent. Hence this script uses
62# getopts and short options for all arguments.
63
6204720d 64while getopts u:r:f:m:a: opt; do
51582c54
DO
65 case "$opt" in
66 u)
67 SUDOUSER="$OPTARG"
68 ;;
69 r)
70 REPODIR="$OPTARG"
71 ;;
72 f)
73 FILEPATH="$OPTARG"
74 ;;
75 m)
76 COMMITMSG="$OPTARG"
77 ;;
6204720d
DO
78 a)
79 AUTHOR="$OPTARG"
80 ;;
51582c54
DO
81 *)
82 echo "$THISFILE: internal error parsing options!" >&2
83 exit 3
84 esac
85done
86: ${COMMITMSG:=update $FILEPATH}
87
88if [ -z "$SUDOUSER" -o -z "$REPODIR" -o -z "$FILEPATH" ]; then
89 echo "$THISFILE: not all mandatory parameters are present" >&2
90 usage_and_exit
91fi
033c2594
DO
92
93[ `whoami` = "$SUDOUSER" ] || {
a44f372d 94 sudo --non-interactive --set-home --user="$SUDOUSER" -- "$0" "$@"
033c2594
DO
95 exit $?
96}
97
98cd "$REPODIR"
99git pull --quiet || {
0859a212 100 echo "$THISFILE: failed to run 'git pull' (rc=$?)" >&2
033c2594
DO
101 exit 2
102}
103
579666a7
DO
104# git processes the path to the file automatically, but the shell
105# redirection obviously does not.
106DIRNAME=`dirname "$FILEPATH"`
107[ -d "$DIRNAME" ] || mkdir -p "$DIRNAME"
108
033c2594
DO
109# New file contents is on stdin.
110cat > "$FILEPATH" || {
0859a212 111 echo "$THISFILE: failed to write new file contents, trying to roll back." >&2
033c2594 112 git checkout --quiet -- "$FILEPATH" || {
0859a212 113 echo "$THISFILE: failed to run 'git checkout' after a write error." >&2
033c2594
DO
114 exit 4
115 }
116 exit 3
117}
118
579666a7
DO
119# git-diff exits with 0 if the file is not in the repository.
120if ! git cat-file -e HEAD:"$FILEPATH" 2>/dev/null || ! git diff --quiet -- "$FILEPATH"; then
033c2594 121 git add -- "$FILEPATH"
6204720d 122 git commit --quiet --message="$COMMITMSG" ${AUTHOR:+--author="$AUTHOR"} -- "$FILEPATH"
033c2594 123 git push --quiet || {
0859a212 124 echo "$THISFILE: failed to run 'git push' (rc=$?)" >&2
033c2594
DO
125 exit 5
126 }
579666a7 127fi
033c2594
DO
128
129exit 0