Copy tracing things back to maint-0.3.5, for consistency.
[tor.git] / scripts / ci / ci-driver.sh
blobcd91a91bbf57c883293adfc5842192dd13d25c1a
1 #!/bin/bash
3 ####
4 # DO NOT EDIT THIS FILE IN MASTER. ONLY EDIT IT IN THE OLDEST SUPPORTED
5 # BRANCH, THEN MERGE FORWARD.
6 ####
8 # This script is used to build Tor for continuous integration. It should
9 # be kept the same for all supported Tor versions.
11 # It's subject to the regular Tor license; see LICENSE for copying
12 # information.
14 set -o errexit
15 set -o nounset
17 # Options for this script.
18 DEBUG_CI="${DEBUG_CI:-no}"
19 COLOR_CI="${COLOR_CI:-yes}"
21 # Options for which CI system this is.
22 ON_GITLAB="${ON_GITLAB:-yes}"
24 # Options for things we usually won't want to skip.
25 RUN_STAGE_CONFIGURE="${RUN_STAGE_CONFIGURE:-yes}"
26 RUN_STAGE_BUILD="${RUN_STAGE_BUILD:-yes}"
27 RUN_STAGE_TEST="${RUN_STAGE_TEST:-yes}"
29 # Options for how to build Tor. All should be yes/no.
30 FATAL_WARNINGS="${FATAL_WARNINGS:-yes}"
31 HARDENING="${HARDENING:-no}"
32 COVERAGE="${COVERAGE:-no}"
33 RUST="${RUST:-no}"
34 DOXYGEN="${DOXYGEN:-no}"
35 ASCIIDOC="${ASCIIDOC:-no}"
36 TRACING="${TRACING:-no}"
38 # Options for which tests to run. All should be yes/no.
39 CHECK="${CHECK:-yes}"
40 STEM="${STEM:-no}"
41 CHUTNEY="${CHUTNEY:-no}"
42 DISTCHECK="${DISTCHECK:-no}"
44 # Options for where the Tor source is.
45 CI_SRCDIR="${CI_SRCDIR:-.}"
47 # Options for where to build.
48 CI_BUILDDIR="${CI_BUILDDIR:-./build}"
50 # How parallel should we run make?
51 MAKE_J_OPT="${MAKE_J_OPT:--j4}"
52 # Should we stop after make finds an error?
53 MAKE_K_OPT="${MAKE_K_OPT:--k}"
55 # What make target should we use for chutney?
56 CHUTNEY_MAKE_TARGET="${CHUTNEY_MAKE_TARGET:-test-network}"
58 # Where do we find our additional testing tools?
59 CHUTNEY_PATH="${CHUTNEY_PATH:-}"
60 STEM_PATH="${STEM_PATH:-}"
62 #############################################################################
63 # Preliminary functions.
65 # Terminal coloring/emphasis stuff.
66 if [[ "${COLOR_CI}" == "yes" ]]; then
67 T_RED=$(tput setaf 1 || true)
68 T_GREEN=$(tput setaf 2 || true)
69 T_YELLOW=$(tput setaf 3 || true)
70 T_DIM=$(tput dim || true)
71 T_BOLD=$(tput bold || true)
72 T_RESET=$(tput sgr0 || true)
73 else
74 T_RED=
75 T_GREEN=
76 T_YELLOW=
77 T_DIM=
78 T_BOLD=
79 T_RESET=
82 function error()
84 echo "${T_BOLD}${T_RED}ERROR:${T_RESET} $*" 1>&2
86 function die()
88 echo "${T_BOLD}${T_RED}FATAL ERROR:${T_RESET} $*" 1>&2
89 exit 1
92 function skipping()
94 echo "${T_BOLD}${T_YELLOW}Skipping $*${T_RESET}"
97 function hooray()
99 echo "${T_BOLD}${T_GREEN}$*${T_RESET}"
102 if [[ "${DEBUG_CI}" == "yes" ]]; then
103 function debug()
105 echo "${T_DIM}(debug): $*${T_RESET}"
107 else
108 function debug()
114 function yes_or_no()
116 local varname="$1"
117 local value="${!varname}"
118 debug "${varname} is ${value}"
119 if [[ "${value}" != 'yes' && "${value}" != 'no' ]]; then
120 die "${varname} must be 'yes' or 'no'. Got unexpected value ${value}".
124 function incompatible()
126 local varname1="$1"
127 local varname2="$2"
128 local val1="${!varname1}"
129 local val2="${!varname2}"
130 if [[ "${val1}" = 'yes' && "${val2}" = 'yes' ]]; then
131 die "Cannot set both ${varname1} and ${varname2}: they are incompatible."
135 function runcmd()
137 echo "${T_BOLD}\$ $*${T_RESET}"
138 if ! "$@" ; then
139 error "command '$*' has failed."
140 return 1
144 function show_git_version()
146 local tool="$1"
147 local dir="$2"
148 local version="?????"
149 if [[ -e "$dir/.git" ]] ; then
150 version=$(cd "$dir"; git rev-parse HEAD)
152 echo "${T_BOLD}$tool:${T_RESET} $version"
155 if [[ "${ON_GITLAB}" == "yes" ]]; then
156 function start_section()
158 local label="$1"
159 local stamp
160 stamp=$(date +%s)
161 printf "section_start:%s:%s\r\e[0K" "$stamp" "$label"
162 echo "${T_BOLD}${T_GREEN}========= $label${T_RESET}"
164 function end_section()
166 local label="$1"
167 local stamp
168 stamp=$(date +%s)
169 printf "section_end:%s:%s\r\e[0K" "$stamp" "$label"
171 else
172 function start_section()
174 true
176 function end_section()
178 true
182 #############################################################################
183 # Validate inputs.
185 debug Validating inputs
186 yes_or_no DEBUG_CI
187 yes_or_no COLOR_CI
188 yes_or_no ON_GITLAB
189 yes_or_no FATAL_WARNINGS
190 yes_or_no HARDENING
191 yes_or_no COVERAGE
192 yes_or_no RUST
193 yes_or_no DOXYGEN
194 yes_or_no ASCIIDOC
195 yes_or_no TRACING
197 yes_or_no RUN_STAGE_CONFIGURE
198 yes_or_no RUN_STAGE_BUILD
199 yes_or_no RUN_STAGE_TEST
201 yes_or_no CHECK
202 yes_or_no STEM
203 yes_or_no DISTCHECK
205 incompatible DISTCHECK CHECK
206 incompatible DISTCHECK CHUTNEY
207 incompatible DISTCHECK STEM
208 incompatible DISTCHECK COVERAGE
209 incompatible DISTCHECK DOXYGEN
211 if [[ "${CHUTNEY}" = yes && "${CHUTNEY_PATH}" = '' ]] ; then
212 die "CHUTNEY is set to 'yes', but CHUTNEY_PATH was not specified."
215 if [[ "${STEM}" = yes && "${STEM_PATH}" = '' ]] ; then
216 die "STEM is set to 'yes', but STEM_PATH was not specified."
219 #############################################################################
220 # Set up options for make and configure.
222 make_options=()
223 if [[ "$MAKE_J_OPT" != "" ]]; then
224 make_options+=("$MAKE_J_OPT")
226 if [[ "$MAKE_K_OPT" != "" ]]; then
227 make_options+=("$MAKE_K_OPT")
230 configure_options=()
231 if [[ "$FATAL_WARNINGS" == "yes" ]]; then
232 configure_options+=("--enable-fatal-warnings")
234 if [[ "$HARDENING" == "yes" ]]; then
235 configure_options+=("--enable-fragile-hardening")
237 if [[ "$COVERAGE" == "yes" ]]; then
238 configure_options+=("--enable-coverage")
240 if [[ "$RUST" == "yes" ]]; then
241 configure_options+=("--enable-rust")
243 if [[ "$ASCIIDOC" != "yes" ]]; then
244 configure_options+=("--disable-asciidoc")
246 if [[ "$TRACING" == "yes" ]]; then
247 configure_options+=("--enable-tracing-instrumentation-lttng")
250 #############################################################################
251 # Tell the user about our versions of different tools and packages.
253 uname -a
254 printf "python: "
255 python -V || echo "no 'python' binary."
256 printf "python3: "
257 python3 -V || echo "no 'python3' binary."
259 show_git_version Tor "${CI_SRCDIR}"
260 if [[ "${STEM}" = "yes" ]]; then
261 show_git_version Stem "${STEM_PATH}"
263 if [[ "${CHUTNEY}" = "yes" ]]; then
264 show_git_version Chutney "${CHUTNEY_PATH}"
267 #############################################################################
268 # Determine the version of Tor.
270 TOR_VERSION=$(grep -m 1 AC_INIT configure.ac | sed -e 's/.*\[//; s/\].*//;')
272 # Use variables like these when we need to behave differently depending on
273 # Tor version. Only create the variables we need.
274 TOR_VER_AT_LEAST_043=no
275 TOR_VER_AT_LEAST_044=no
277 # These are the currently supported Tor versions; no need to work with anything
278 # ancient in this script.
279 case "$TOR_VERSION" in
280 0.3.*)
281 TOR_VER_AT_LEAST_043=no
282 TOR_VER_AT_LEAST_044=no
284 0.4.[012].*)
285 TOR_VER_AT_LEAST_043=no
286 TOR_VER_AT_LEAST_044=no
288 0.4.3.*)
289 TOR_VER_AT_LEAST_043=yes
290 TOR_VER_AT_LEAST_044=no
293 TOR_VER_AT_LEAST_043=yes
294 TOR_VER_AT_LEAST_044=yes
296 esac
298 #############################################################################
299 # Make sure the directories are all there.
301 # Make sure CI_SRCDIR exists and has a file we expect.
302 if [[ ! -d "$CI_SRCDIR" ]] ; then
303 die "CI_SRCDIR=${CI_SRCDIR} is not a directory"
305 if [[ ! -f "$CI_SRCDIR/src/core/or/or.h" ]] ; then
306 die "CI_SRCDIR=${CI_SRCDIR} does not look like a Tor directory."
309 # Make CI_SRCDIR absolute.
310 CI_SRCDIR=$(cd "$CI_SRCDIR" && pwd)
312 # Create an "artifacts" directory to copy artifacts into.
313 mkdir -p ./artifacts
315 if [[ "$RUN_STAGE_CONFIGURE" = "yes" ]]; then
317 start_section "Autogen"
318 runcmd cd "${CI_SRCDIR}"
319 runcmd ./autogen.sh
320 runcmd mkdir -p "${CI_BUILDDIR}"
321 runcmd cd "${CI_BUILDDIR}"
322 end_section "Autogen"
324 # make the builddir absolute too.
325 CI_BUILDDIR=$(pwd)
327 start_section "Configure"
328 if ! runcmd "${CI_SRCDIR}"/configure "${configure_options[@]}" ; then
329 error "Here is the end of config.log:"
330 runcmd tail config.log
331 die "Unable to continue"
333 end_section "Configure"
334 else
335 debug "Skipping configure stage. Making sure that ${CI_BUILDDIR}/config.log exists."
336 if [[ ! -d "${CI_BUILDDIR}" ]]; then
337 die "Build directory ${CI_BUILDDIR} did not exist!";
339 if [[ ! -f "${CI_BUILDDIR}/config.log" ]]; then
340 die "Tor was not configured in ${CI_BUILDDIR}!";
343 cp config.log "${CI_SRCDIR}"/artifacts
345 runcmd cd "${CI_BUILDDIR}"
346 CI_BUILDDIR=$(pwd)
349 ###############################
350 # Build Tor.
352 if [[ "$RUN_STAGE_BUILD" = "yes" ]] ; then
353 if [[ "$DISTCHECK" = "no" ]]; then
354 start_section "Build"
355 runcmd make "${make_options[@]}" all
356 cp src/app/tor "${CI_SRCDIR}"/artifacts
357 end_section "Build"
358 else
359 export DISTCHECK_CONFIGURE_FLAGS="${configure_options[*]}"
360 # XXXX Set make options?
361 start_section Distcheck
362 if runcmd make "${make_options[@]}" distcheck ; then
363 hooray "Distcheck was successful. Nothing further will be done."
364 # We have to exit early here, since we can't do any other tests.
365 cp tor-*.tar.gz "${CI_SRCDIR}"/artifacts
366 exit 0
367 else
368 error "Diagnostics:"
369 runcmd make show-distdir-testlog || true
370 runcmd make show-distdir-core || true
371 die "Unable to continue."
373 end_section Distcheck
377 ##############################
378 # Run tests.
380 if [[ "$RUN_STAGE_TEST" == "no" ]]; then
381 echo "Skipping tests. Exiting now."
382 exit 0
385 FAILED_TESTS=""
387 if [[ "${DOXYGEN}" = 'yes' ]]; then
388 start_section Doxygen
389 if [[ "${TOR_VER_AT_LEAST_043}" = 'yes' ]]; then
390 if runcmd make doxygen; then
391 hooray "make doxygen has succeeded."
392 else
393 FAILED_TESTS="${FAILED_TESTS} doxygen"
395 else
396 skipping "make doxygen: doxygen is broken for Tor < 0.4.3"
398 end_section Doxygen
401 if [[ "${ASCIIDOC}" = 'yes' ]]; then
402 start_section Asciidoc
403 if runcmd make manpages; then
404 hooray "make manpages has succeeded."
405 else
406 FAILED_TESTS="${FAILED_TESTS} asciidoc"
408 end_section Asciidoc
411 if [[ "${CHECK}" = "yes" ]]; then
412 start_section "Check"
413 if runcmd make "${make_options[@]}" check; then
414 hooray "make check has succeeded."
415 else
416 error "Here are the contents of the test suite output:"
417 runcmd cat test-suite.log || true
418 FAILED_TESTS="${FAILED_TESTS} check"
420 end_section "Check"
423 if [[ "${CHUTNEY}" = "yes" ]]; then
424 start_section "Chutney"
425 export CHUTNEY_TOR_SANDBOX=0
426 export CHUTNEY_ALLOW_FAILURES=2
427 if runcmd make "${CHUTNEY_MAKE_TARGET}"; then
428 hooray "Chutney tests have succeeded"
429 else
430 error "Chutney says:"
431 export CHUTNEY_DATA_DIR="${CHUTNEY_PATH}/net"
432 runcmd "${CHUTNEY_PATH}"/tools/diagnostics.sh || true
433 # XXXX These next two should be part of a make target.
434 runcmd ls test_network_log || true
435 runcmd cat test_network_log || true
436 FAILED_TESTS="${FAILED_TESTS} chutney"
438 end_section "Chutney"
441 if [[ "${STEM}" = "yes" ]]; then
442 start_section "Stem"
443 if [[ "${TOR_VER_AT_LEAST_044}" = 'yes' ]]; then
444 # XXXX This shold probably be part some test-stem make target.
445 if runcmd timelimit -p -t 520 -s USR1 -T 30 -S ABRT \
446 python3 "${STEM_PATH}/run_tests.py" \
447 --tor src/app/tor \
448 --integ --test control.controller \
449 --test control.base_controller \
450 --test process \
451 --log TRACE \
452 --log-file stem.log ; then
453 hooray "Stem tests have succeeded"
454 else
455 error "Stem output:"
456 runcmd tail -1000 "${STEM_PATH}"/test/data/tor_log
457 runcmd grep -v "SocketClosed" stem.log | tail -1000
458 FAILED_TESTS="${FAILED_TESTS} stem"
460 else
461 skipping "Stem: broken with <= 0.4.3. See bug tor#40077"
463 end_section "Stem"
466 # TODO: Coverage
468 if [[ "${FAILED_TESTS}" != "" ]]; then
469 die "Failed tests: ${FAILED_TESTS}"
472 hooray "Everything seems fine."