-
-
Notifications
You must be signed in to change notification settings - Fork 151
/
compile_commits.sh
executable file
·238 lines (187 loc) · 4.83 KB
/
compile_commits.sh
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Copyright (C) 2023-2023 The DOSBox Staging Team
#
# Compiles all branch commits from the current commit backward.
# It Automatically uses the latest supported version of GCC and Clang,
# building with both compilers if available.
#
# When a failure occurs, the log is printed and the problematic commit
# will be checked out, so you can inspect and amend the commit.
#
# CLI tools used:
# - Bash 3.x or Zsh, for enhanced error handling versus SH
# - GNU ls, for natural-sorting the native files by version
# - GNU sed, to parse the default branch
# - Git, (any version should be fine)
# - All the project's build depenencies (Meson, Ninja, etc)
#
set -euo pipefail
# Common variables that are setup and used below
declare temp_file
declare head_commit
declare current_branch
declare -a commits
declare -a compilers
declare meson_setup
# GNU tools
declare LS
declare SED
populate_gnu_ls() {
# shellcheck disable=2010
if \ls --version 2> /dev/null | grep -q GNU; then
LS=$(command -v ls)
elif command -v gdir > /dev/null; then
LS=$(command -v gdir)
else
echo "Please install corutils with your package manager and then:"
echo " - Adjust your PATH to find GNU 'ls' first, or"
echo " - Symlink 'ls' to your GNU 'ls' binary, or"
echo " - If on macOS, simply 'brew install coreutils' and you're done!"
exit 1
fi
}
populate_gnu_sed() {
if \sed --version 2> /dev/null | grep -q GNU; then
SED=$(command -v sed)
elif command -v gsed > /dev/null; then
SED=$(command -v gsed)
else
echo "Please install GNU sed with your package manager."
echo " - If on macOS, simply 'brew install gnu-sed' and you're done!"
exit 1
fi
}
extract_cpp_from_native_file() {
grep cpp "$1" | cut -d "'" -f 4
}
get_native_file_for_compiler() {
local compiler
compiler="$1"
populate_gnu_ls
local native_file
for native_file in $("$LS" \
--reverse \
--sort=version \
.github/meson/native-"$compiler"*.ini); do
local cpp
cpp=$(extract_cpp_from_native_file "$native_file")
if command -v "$cpp" &> /dev/null; then
echo "$native_file"
return
fi
done
}
allocate_temp_file() {
temp_file=$(mktemp 2> /dev/null || mktemp -t temp)
echo "Realtime log: $temp_file"
# Cleanup the log on termination
trap 'rm -f "$temp_file"' EXIT
}
run() {
# Split the command into an array
local -a cmds
IFS=" " read -r -a cmds <<< "$1"
# Execute the command with arguments
if ! "${cmds[@]}" &> "$temp_file"; then
echo "failed"
echo ""
echo "---"
cat "$temp_file"
echo "---"
echo ""
return 1
fi
return 0
}
populate_commits() {
populate_gnu_sed
current_branch=$(git rev-parse --abbrev-ref HEAD)
local default_branch
default_branch=$(git symbolic-ref refs/remotes/origin/HEAD 2> /dev/null \
| "$SED" 's@^refs/remotes/origin/@@')
if [[ -z $default_branch ]]; then
echo "Failed to determine the default branch."
exit 1
fi
commits=()
while IFS= read -r line; do
commits+=("$line")
done < <(git log --format="%h" HEAD --not "$default_branch" --reverse)
if ((${#commits[@]} <= 1)); then
echo "Branch does not have multiple commits; skipping"
exit 0
fi
head_commit="${commits[0]}"
}
meson_setup_for_compiler() {
local compiler
compiler="$1"
local native_file
native_file=$(get_native_file_for_compiler "$compiler")
if [[ -z $native_file ]]; then
echo "No supported $compiler versions found, skipping"
return 1
fi
echo "Using $compiler native file: $native_file"
local options
options="-Dbuildtype=debug -Dunit_tests=disabled -Dwarning_level=0 -Dc_args=-w -Dcpp_args=-w"
meson_setup="meson setup $options --native-file=$native_file build/$compiler"
if ! run "$meson_setup"; then
echo "Reproduce with:"
echo "$meson_setup"
echo ""
return 1
fi
return 0
}
populate_compilers() {
compilers=()
if meson_setup_for_compiler gcc; then
compilers+=(gcc)
fi
if meson_setup_for_compiler clang; then
compilers+=(clang)
fi
if ((${#compilers[@]} == 0)); then
echo "No supported compilers found, quitting"
exit 1
fi
}
compile_commit() {
local compiler
compiler="$1"
local commit
commit="$2"
local title
local meson_compile
meson_compile="meson compile -C build/$compiler"
if ! run "$meson_compile"; then
echo "Reproduce with:"
echo "git checkout $head_commit"
echo "$meson_setup"
echo "git checkout $commit"
echo "$meson_compile"
exit 1
fi
echo -n " $compiler"
}
main() {
allocate_temp_file
populate_commits
populate_compilers
for commit in "${commits[@]}"; do
git checkout "$commit" &> /dev/null
title=$(git show \
--no-patch \
--format="%s" "$commit")
printf "Compiling %s %-40.40s.." "$commit" "$title"
for compiler in "${compilers[@]}"; do
compile_commit "$compiler" "$commit"
done
echo ""
done
git checkout "$current_branch" &> /dev/null
}
main