Commit | Line | Data |
---|---|---|
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 | 26 | THISFILE=`basename "$0"` |
51582c54 DO |
27 | |
28 | usage_and_exit() | |
29 | { | |
30 | cat >&2 <<ENDOFMESSAGE | |
6204720d | 31 | Usage: $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 | 48 | ENDOFMESSAGE |
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 | 64 | while 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 | |
85 | done | |
86 | : ${COMMITMSG:=update $FILEPATH} | |
87 | ||
88 | if [ -z "$SUDOUSER" -o -z "$REPODIR" -o -z "$FILEPATH" ]; then | |
89 | echo "$THISFILE: not all mandatory parameters are present" >&2 | |
90 | usage_and_exit | |
91 | fi | |
033c2594 DO |
92 | |
93 | [ `whoami` = "$SUDOUSER" ] || { | |
a44f372d | 94 | sudo --non-interactive --set-home --user="$SUDOUSER" -- "$0" "$@" |
033c2594 DO |
95 | exit $? |
96 | } | |
97 | ||
98 | cd "$REPODIR" | |
99 | git 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. | |
106 | DIRNAME=`dirname "$FILEPATH"` | |
107 | [ -d "$DIRNAME" ] || mkdir -p "$DIRNAME" | |
108 | ||
033c2594 DO |
109 | # New file contents is on stdin. |
110 | cat > "$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. |
120 | if ! 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 | 127 | fi |
033c2594 DO |
128 | |
129 | exit 0 |