summaryrefslogtreecommitdiffstats
path: root/aiaiai-sh-functions
blob: 57fe04d7495a56299c5a040821201b65b09a4a81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/bin/sh -efu

# Copyright 2011-2012 Intel Corporation
# Author: Artem Bityutskiy
# License: GPLv2

. shell-error

if [ -z "${__included_aiaiai_sh_functions-}" ]; then
__included_aiaiai_sh_functions=1

# Print an error message and exit
# Usage: die <message>
die()
{
	fatal "Fatal error: $1"
}

# Print a separator line to stdout
print_separator()
{
	local i=0

	while [ $i -lt 80 ]; do
		i=$(($i+1));
		printf "-";
	done
	echo
}

# Die if a program is not in PATH
# Usage: program_required <program_name>
program_required()
{
	local prg="$1"; shift
	local msg="$1"; shift

	if ! command -v "$prg" >/dev/null 2>&1; then
		message "Program \"$prg\" is required but not found in PATH"
		if [ -n "$msg" ]; then
			die "$msg"
		else
			exit 1
		fi
	fi
}

# Fetch the first occurrence of an mbox header from a file
# Usage: fetch_header <header_name> < <mbox_file>
fetch_header()
{
	local hdr="$1"

	program_required "formail" ""

	# Take only the first occurrence of the header
	formail -z -c -x "$hdr:" | head -n1 | aiaiai-decode-rfc-2047
}

# Similar to fetch_header, but exits with code 1 if the header hasn't been
# found, and has a little bit different interface (the result is stored in
# "<var>").
#
# Usage: fetch_header_or_die <var> <header_name> < <mbox_file>
fetch_header_or_die()
{
	local var="$1"; shift
	local hdr="$1"; shift
	local res="$(fetch_header "$hdr")"

	[ -n "$res" ] || die "Cannot find the \"$hdr:\" header"

	eval "$var=\"\$res\""
}

fetch_header_per_patch()
{
	local hdr="$1"

	program_required "formail" ""

	# Take only the first occurrence of the header per message
	formail -s sh -c "formail -z -c -x \"$hdr:\" | head -n1" | aiaiai-decode-rfc-2047
}

git_dir()
{
	local path="$1"
	local dotgit="$path/.git"

	if [ -d "$dotgit" ]; then
		printf "%s" "$dotgit"
	elif [ -d "$path" ]; then
		printf "%s" "$path"
	else
		die "not a git repository: $path"
	fi
}

# Apply a patch. In case of error, print user-friendly diagnostic messages to
# stdin.
# Usage: apply_patch < <mbox_file>
apply_patch()
{
	local am cmt

	program_required "patch" ""

	cmt="$(git rev-parse "HEAD^{commit}")"

	am="$(git am 2>&1)" || {
		cat <<EOF
Failed to apply patch(es) with git am on top of:
$(git log -1 --oneline "$cmt")

$am

Results of "patch --merge=diff3 -p1 < .git/rebase-apply/patch":

$(patch --merge=diff3 -p1 < .git/rebase-apply/patch 2>&1)

$(print_separator)

$(git diff --no-color)
EOF
		return 1
	}
}

# A helper function for 'build_failure()'. This function expects the properly
# formatted build log a stdin and outputs user-readable failure report to
# stdout.
__print_build_log()
{
	local config="$(leave_first "$1")";
	local arch="$(leave_second "$1")"; shift
	local commit_id="$1"; shift

	cat <<EOF
Failed to build the following commit for configuration "$config"${arch:+ "(architecture $arch)"}":

$(git log -1 --oneline "$commit_id")

$(cat)
EOF
}

# Format a build failure report.
# Usage: build_failure <defconfig> <commit_id> < <build_log>
build_failure()
{
	# The build log might have been generated with multiple jobs which
	# means it is probably messy and the error message is probably not at
	# the very end. To make it more probable that we actually print the
	# build error message within 24 lines we do the following:
	# * filter sparse/smatch/cppcheck/coccinelle output
	# * filter out 'CHECK   drivers/blah.c' Kbuild lines
	# * print 24 lines preceding the 'make[]: *** [] blah' pattern which
	#   make generates after an error

	sed -n '# Filter out useless stuff
		/\[sparse\]$/d
	        /\[smatch\]$/d
	        /\[cppcheck\]$/d
	        /\[coccinelle\]$/d
		/^  CHECK   /d
		# Add the line to the hold buffer
		H
		# If the line is the error marker, print out the entire hold
		# buffer and quit
		/^make\[.*\]: \*\*\* \[.*\]/ { g; p; q; }
		# Do the same if the last line is reached
		$                            { g; p; q; }' | tail -n24 |
		__print_build_log "$@"
}

# Check if the build failed.
# Usage: build_failed <build_log>
build_failed()
{
	local build_log="$1"
	local failed

	failed="$(tail -n1 -- "$build_log")"
	test "$failed" = "FAILURE"
}

# Filter out the first element from a comma-separated list of elements.
# Usage: strip_first <list>
strip_first()
{
	printf "%s" "$1" | sed -e 's/^[^,]*,\{0,1\}//g'
}

# Filter out all but the first element from a comma-separated list of elements.
# Usage: leave_first <list>
leave_first()
{
	printf "%s" "$1" | sed -e 's/,.*$//g'
}

# Filter out all but the second element from a comma-separated list of elements.
# Usage: leave_second <list>
leave_second()
{
	leave_first "$(strip_first "$1")"
}

# Filter out all but the third element from a comma-separated list of elements.
# Usage: leave_third <list>
leave_third()
{
	leave_second "$(strip_first "$1")"
}

fi #__included_aiaiai_sh_functions