From fbfbdb8e124480bc90bbd6a8b59c1692c4ebd531 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 1 Feb 2016 09:42:55 +0100 Subject: [PATCH] travis: check spelling of binaries and manpages, use docker We now build a docker base container based on debian sid (where the very latest packages are available). That base container is updated once a month, or whenever travis-build.Dockerfile or debian/control change, but re-used for subsequent travis runs. While the initial build might take up to 15 minutes, subsequent builds typically run in a minute or two. All the different steps that we run on travis are now factored into separate scripts in the travis/ directory. Switching to docker should also help with issue #2174. --- .travis.yml | 56 ++++++++--------------------- generate-command-parser.pl | 2 +- i3-input/main.c | 4 +-- include/libi3.h | 2 +- libi3/format_placeholders.c | 2 +- man/i3-input.man | 2 +- man/i3-msg.man | 2 +- src/commands.c | 2 +- src/config_parser.c | 2 +- travis-build.Dockerfile | 29 +++++++++++++++ travis/check-formatting.sh | 2 ++ travis/check-safe-wrappers.sh | 19 ++++++++++ travis/check-spelling.pl | 64 +++++++++++++++++++++++++++++++++ travis/docker-build-and-push.sh | 11 ++++++ travis/ha.sh | 7 ++++ travis/run-tests.sh | 8 +++++ 16 files changed, 164 insertions(+), 50 deletions(-) create mode 100644 travis-build.Dockerfile create mode 100755 travis/check-formatting.sh create mode 100755 travis/check-safe-wrappers.sh create mode 100755 travis/check-spelling.pl create mode 100755 travis/docker-build-and-push.sh create mode 100755 travis/ha.sh create mode 100755 travis/run-tests.sh diff --git a/.travis.yml b/.travis.yml index 54ef5cae..aa574d09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,49 +1,23 @@ sudo: required dist: trusty +services: + - docker language: c compiler: - gcc - clang -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - clang-format-3.5 - - libllvm3.5 - - clang-3.5 - - gcc-5 -before_install: - - sudo DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-suggests --no-install-recommends devscripts equivs xdotool +env: + global: + - BASENAME="i3wm/travis-base:$(date +'%Y-%m')-$(./travis/ha.sh)" + - secure: "B5IICA8MPx/FKaB50rTPqL8P1NU+Q0yuWl+lElL4+a9xSyLikfm3NzUPHoVwx8lNw2AVK6br7p0OmF7vMFjqAgrgc1cajTtEae5uFRKNUrWLpXM046YgNEYLLIHsQOjInxE+S4O6EFVzsUqsu8aeo2Xhq4sm4iUocG7e5isYgYo=" # DOCKER_PASS + - secure: "EIvrq8PG7lRjidppG0RCv4F0X4GP3DT9F5+ixVuGPfhK/hZT3jYC2AVY9G+NnUcXVwQEpW92rlqpftQ/qZ13FoyWokC8ZyoyD06fr5FPCfoFF3OczZwAJzZYkObI/hE9+/hXcylx/Os6N4INd2My1ntGk3JPsWL9riopod5EjSg=" # DOCKER_EMAIL + - secure: "hvhBunS4xXTgnIOsk/BPT7I7FrJhvVwCSt5PfxxvMqNaztOJI9BuK7ZrZ5Cy38KyHwlh3VHAH5AaCygJcPauoSQCV3bpnlbaWn3ruq2F0Q697Q5uNf73liXzyUqb9/Zvfvge4y4WWOhP5tVz1C6ZBe/NfhU7pqKLMA+6ads+99c=" # DOCKER_USER install: - - sudo DEBIAN_FRONTEND=noninteractive mk-build-deps --install --remove --tool 'apt-get -yq --no-install-suggests --no-install-recommends' debian/control - # Install as many dependencies as possible via apt because cpanm is not very reliable/easy to debug. - - sudo DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-suggests --no-install-recommends libanyevent-perl libanyevent-i3-perl libextutils-pkgconfig-perl xcb-proto cpanminus xvfb xserver-xephyr xauth libinline-perl libxml-simple-perl libmouse-perl libmousex-nativetraits-perl libextutils-depends-perl perl-modules libtest-deep-perl libtest-exception-perl libxml-parser-perl libtest-simple-perl libtest-fatal-perl libdata-dump-perl libtest-differences-perl libxml-tokeparser-perl libtest-use-ok-perl libipc-run-perl libxcb-xtest0-dev - - sudo /bin/sh -c 'cpanm -n -v X11::XCB || true' - - sudo /bin/sh -c 'cpanm -n -v AnyEvent::I3 || true' -script: - if [ -a .git/shallow ]; then git fetch --unshallow; fi - - if [ "$CC" = "clang" ]; then export CC="clang-3.5"; fi - - if [ "$CC" = "gcc" ]; then export CC="gcc-5"; fi - - CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror" make -j ASAN=1 - - (cd testcases && xvfb-run ./complete-run.pl --parallel=1 || (cat latest/complete-run.log; false)) - - clang-format-3.5 -i $(find . -name "*.[ch]" | tr '\n' ' ') && git diff --exit-code || (echo 'Code was not formatted using clang-format!'; false) - - | - funcs='malloc|calloc|realloc|strdup|strndup|asprintf|write' - cstring='"([^"\\]|\\.)*"' - cchar="'[^\\\\]'|'\\\\.[^']*'" - regex="^([^'\"]|${cstring}|${cchar})*\<(${funcs})\>" - detected=0 - while IFS= read -r file; do - if { cpp -w -fpreprocessed "$file" || exit "$?"; } | grep -E -- "$regex"; then - echo "^ $file calls a function that has a safe counterpart." - detected=1 - fi - done << EOF - $(find -name '*.c' -not -name safewrappers.c -not -name strndup.c) - EOF - if [ "$detected" -ne 0 ]; then - echo - echo "Calls of functions that have safe counterparts were detected." - exit 1 - fi + - docker pull ${BASENAME} || ./travis/docker-build-and-push.sh +script: + - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-safe-wrappers.sh + - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-formatting.sh + - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 -e CC -e CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror" ${BASENAME} make all mans -j ASAN=1 + - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-spelling.pl + - docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/run-tests.sh diff --git a/generate-command-parser.pl b/generate-command-parser.pl index c0a9a4d4..6208945d 100755 --- a/generate-command-parser.pl +++ b/generate-command-parser.pl @@ -109,7 +109,7 @@ for my $line (@lines) { # Second step: Generate the enum values for all states. # It is important to keep the order the same, so we store the keys once. -# We sort descendingly by length to be able to replace occurences of the state +# We sort descendingly by length to be able to replace occurrences of the state # name even when one state’s name is included in another one’s (like FOR_WINDOW # is in FOR_WINDOW_COMMAND). my @keys = sort { (length($b) <=> length($a)) or ($a cmp $b) } keys %states; diff --git a/i3-input/main.c b/i3-input/main.c index e196891c..64a089dd 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -176,14 +176,14 @@ static int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_rel static void finish_input() { char *command = (char *)concat_strings(glyphs_utf8, input_position); - /* count the occurences of %s in the string */ + /* count the occurrences of %s in the string */ int c; int len = strlen(format); int cnt = 0; for (c = 0; c < (len - 1); c++) if (format[c] == '%' && format[c + 1] == 's') cnt++; - printf("occurences = %d\n", cnt); + printf("occurrences = %d\n", cnt); /* allocate space for the output */ int inputlen = strlen(command); diff --git a/include/libi3.h b/include/libi3.h index 9f6eff2b..4c722671 100644 --- a/include/libi3.h +++ b/include/libi3.h @@ -513,7 +513,7 @@ typedef struct placeholder_t { } placeholder_t; /** - * Replaces occurences of the defined placeholders in the format string. + * Replaces occurrences of the defined placeholders in the format string. * */ char *format_placeholders(char *format, placeholder_t *placeholders, int num); diff --git a/libi3/format_placeholders.c b/libi3/format_placeholders.c index 825cab5c..c9cbbea4 100644 --- a/libi3/format_placeholders.c +++ b/libi3/format_placeholders.c @@ -16,7 +16,7 @@ #endif /* - * Replaces occurences of the defined placeholders in the format string. + * Replaces occurrences of the defined placeholders in the format string. * */ char *format_placeholders(char *format, placeholder_t *placeholders, int num) { diff --git a/man/i3-input.man b/man/i3-input.man index b67a1403..07a91783 100644 --- a/man/i3-input.man +++ b/man/i3-input.man @@ -26,7 +26,7 @@ Specify the path to the i3 IPC socket (it should not be necessary to use this option, i3-input will figure out the path on its own). -F :: -Every occurence of "%s" in the string is replaced by the user input, +Every occurrence of "%s" in the string is replaced by the user input, and the result is sent to i3 as a command. Default value is "%s". -l :: diff --git a/man/i3-msg.man b/man/i3-msg.man index 911fc995..e0c70c44 100644 --- a/man/i3-msg.man +++ b/man/i3-msg.man @@ -89,7 +89,7 @@ i3-msg -t get_tree === I3SOCK If no ipc-socket is specified on the commandline, this variable is used -to determine the path, at wich the unix domain socket is expected, on which +to determine the path, at which the unix domain socket is expected, on which to connect to i3. == SEE ALSO diff --git a/src/commands.c b/src/commands.c index 9f5af8c2..1612a5ef 100644 --- a/src/commands.c +++ b/src/commands.c @@ -250,7 +250,7 @@ void cmd_criteria_match_windows(I3_CMD) { DLOG("matches window!\n"); accept_match = true; } else { - DLOG("doesnt match\n"); + DLOG("doesn't match\n"); FREE(current); continue; } diff --git a/src/config_parser.c b/src/config_parser.c index 27cdeb93..e97a37e1 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -910,7 +910,7 @@ bool parse_file(const char *f, bool use_nagbar) { FREE(bufcopy); /* Then, allocate a new buffer and copy the file over to the new one, - * but replace occurences of our variables */ + * but replace occurrences of our variables */ char *walk = buf, *destwalk; char *new = smalloc(stbuf.st_size + extra_bytes + 1); destwalk = new; diff --git a/travis-build.Dockerfile b/travis-build.Dockerfile new file mode 100644 index 00000000..0861b26a --- /dev/null +++ b/travis-build.Dockerfile @@ -0,0 +1,29 @@ +# vim:ft=Dockerfile +FROM debian:sid + +RUN echo force-unsafe-io > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup +# Paper over occasional network flakiness of some mirrors. +RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retry + +# NOTE: I tried exclusively using gce_debian_mirror.storage.googleapis.com +# instead of httpredir.debian.org, but the results (Fetched 123 MB in 36s (3357 +# kB/s)) are not any better than httpredir.debian.org (Fetched 123 MB in 34s +# (3608 kB/s)). Hence, let’s stick with httpredir.debian.org (default) for now. + +# Install mk-build-deps (for installing the i3 build dependencies), +# clang and clang-format-3.5 (for checking formatting and building with clang), +# lintian (for checking spelling errors), +# test suite dependencies (for running tests) +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + dpkg-dev devscripts git equivs \ + clang clang-format-3.5 \ + lintian \ + libanyevent-perl libanyevent-i3-perl libextutils-pkgconfig-perl xcb-proto cpanminus xvfb xserver-xephyr xauth libinline-perl libinline-c-perl libxml-simple-perl libmouse-perl libmousex-nativetraits-perl libextutils-depends-perl perl-modules libtest-deep-perl libtest-exception-perl libxml-parser-perl libtest-simple-perl libtest-fatal-perl libdata-dump-perl libtest-differences-perl libxml-tokeparser-perl libipc-run-perl libxcb-xtest0-dev libx11-xcb-perl libanyevent-i3-perl && \ + rm -rf /var/lib/apt/lists/* + +# Install i3 build dependencies. +COPY debian/control /usr/src/i3-debian-packaging/control +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive mk-build-deps --install --remove --tool 'apt-get --no-install-recommends -y' /usr/src/i3-debian-packaging/control && \ + rm -rf /var/lib/apt/lists/* diff --git a/travis/check-formatting.sh b/travis/check-formatting.sh new file mode 100755 index 00000000..abdb1168 --- /dev/null +++ b/travis/check-formatting.sh @@ -0,0 +1,2 @@ +#!/bin/sh +clang-format-3.5 -i $(find . -name "*.[ch]" | tr '\n' ' ') && git diff --exit-code || (echo 'Code was not formatted using clang-format!'; false) diff --git a/travis/check-safe-wrappers.sh b/travis/check-safe-wrappers.sh new file mode 100755 index 00000000..f6911ca2 --- /dev/null +++ b/travis/check-safe-wrappers.sh @@ -0,0 +1,19 @@ +#!/bin/sh +funcs='malloc|calloc|realloc|strdup|strndup|asprintf|write' +cstring='"([^"\\]|\\.)*"' +cchar="'[^\\\\]'|'\\\\.[^']*'" +regex="^([^'\"]|${cstring}|${cchar})*\<(${funcs})\>" +detected=0 +while IFS= read -r file; do + if { cpp -w -fpreprocessed "$file" || exit "$?"; } | grep -E -- "$regex"; then + echo "^ $file calls a function that has a safe counterpart." + detected=1 + fi +done << EOF +$(find -name '*.c' -not -name safewrappers.c -not -name strndup.c) +EOF +if [ "$detected" -ne 0 ]; then + echo + echo "Calls of functions that have safe counterparts were detected." + exit 1 +fi diff --git a/travis/check-spelling.pl b/travis/check-spelling.pl new file mode 100755 index 00000000..71feec31 --- /dev/null +++ b/travis/check-spelling.pl @@ -0,0 +1,64 @@ +#!/usr/bin/env perl +# vim:ts=4:sw=4:expandtab +# +# © 2016 Michael Stapelberg +# +# Checks for spelling errors in binaries and manpages (to be run by continuous +# integration to point out spelling errors before accepting contributions). + +use strict; +use warnings; +use v5.10; +use autodie; +use lib 'testcases/lib'; +use i3test::Util qw(slurp); +use Lintian::Check qw(check_spelling); + +# Lintian complains if we don’t set a vendor. +use Lintian::Data; +use Lintian::Profile; +Lintian::Data->set_vendor( + Lintian::Profile->new('debian', ['/usr/share/lintian'], {})); + +my $exitcode = 0; + +# Whitelist for spelling errors in manpages, in case the spell checker has +# false-positives. +my $binary_spelling_exceptions = { + #'exmaple' => 1, # Example for how to add entries to this whitelist. + 'betwen' => 1, # asan_flags.inc contains this spelling error. +}; +my @binaries = qw( + i3 + i3-config-wizard/i3-config-wizard + i3-dump-log/i3-dump-log + i3-input/i3-input + i3-msg/i3-msg + i3-nagbar/i3-nagbar + i3bar/i3bar +); +for my $binary (@binaries) { + check_spelling(slurp($binary), $binary_spelling_exceptions, sub { + my ($current, $fixed) = @_; + say STDERR qq|Binary "$binary" contains a spelling error: "$current" should be "$fixed"|; + $exitcode = 1; + }); +} + +# Whitelist for spelling errors in manpages, in case the spell checker has +# false-positives. +my $manpage_spelling_exceptions = { +}; + +for my $name (glob('man/*.1')) { + for my $line (split(/\n/, slurp($name))) { + next if $line =~ /^\.\\\"/o; + check_spelling($line, $manpage_spelling_exceptions, sub { + my ($current, $fixed) = @_; + say STDERR qq|Manpage "$name" contains a spelling error: "$current" should be "$fixed"|; + $exitcode = 1; + }); + } +} + +exit $exitcode; diff --git a/travis/docker-build-and-push.sh b/travis/docker-build-and-push.sh new file mode 100755 index 00000000..7dfd3392 --- /dev/null +++ b/travis/docker-build-and-push.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +# .dockerignore is created on demand so that release.sh and other scripts are +# not influenced by our travis setup. +echo .git > .dockerignore + +docker build --pull --no-cache --rm -t=${BASENAME} -f travis-build.Dockerfile . +docker login -e ${DOCKER_EMAIL} -u ${DOCKER_USER} -p ${DOCKER_PASS} +docker push ${BASENAME} diff --git a/travis/ha.sh b/travis/ha.sh new file mode 100755 index 00000000..688755c3 --- /dev/null +++ b/travis/ha.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# Returns a hash to be used as version number suffix for the i3/travis-base +# docker container. The hash is over all files which influence what gets +# installed in the container, so that any changes in what needs to be installed +# will result in a cache invalidation. + +cat debian/control travis-build.Dockerfile | sha256sum | dd bs=1 count=8 status=none diff --git a/travis/run-tests.sh b/travis/run-tests.sh new file mode 100755 index 00000000..87c5dbb7 --- /dev/null +++ b/travis/run-tests.sh @@ -0,0 +1,8 @@ +#!/bin/sh +cd testcases +# Try running the tests in parallel so that the common case (tests pass) is +# quick, but fall back to running them in sequence to make debugging easier. +if ! xvfb-run ./complete-run.pl +then + xvfb-run ./complete-run.pl --parallel=1 || (cat latest/complete-run.log; false) +fi