]> git.sur5r.net Git - i3/i3/commitdiff
travis: check spelling of binaries and manpages, use docker
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 1 Feb 2016 08:42:55 +0000 (09:42 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Sat, 6 Feb 2016 09:36:43 +0000 (10:36 +0100)
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.

16 files changed:
.travis.yml
generate-command-parser.pl
i3-input/main.c
include/libi3.h
libi3/format_placeholders.c
man/i3-input.man
man/i3-msg.man
src/commands.c
src/config_parser.c
travis-build.Dockerfile [new file with mode: 0644]
travis/check-formatting.sh [new file with mode: 0755]
travis/check-safe-wrappers.sh [new file with mode: 0755]
travis/check-spelling.pl [new file with mode: 0755]
travis/docker-build-and-push.sh [new file with mode: 0755]
travis/ha.sh [new file with mode: 0755]
travis/run-tests.sh [new file with mode: 0755]

index 54ef5caefbf2af6d6fd619add192ef3722b0d774..aa574d09e0f1002ba13bedcc9e0e4e753658df5a 100644 (file)
@@ -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
index c0a9a4d42755ea9c11b6c983fa216f53fc849459..6208945dc87558f0ee88cd5cfdbfcd9a9bd68e69 100755 (executable)
@@ -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;
index e196891c343d5cbfcb4b0deff322ed12f7aa9f18..64a089dd8f9cb5d947f4f572a8c0361531556310 100644 (file)
@@ -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);
index 9f6eff2bbebc941257b91634e11b3432f81dd191..4c722671559880ae42c2f193fd1f13e125e2a23f 100644 (file)
@@ -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);
index 825cab5cf19531be1475a8ededf7009445c74482..c9cbbea446274567c09e8c62927ef390884d6c8a 100644 (file)
@@ -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) {
index b67a14030afcf21157112ac8845740c447b3bf05..07a91783115e8394092207842dd341a332bea5be 100644 (file)
@@ -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 <format>::
-Every occurence of "%s" in the <format> string is replaced by the user input,
+Every occurrence of "%s" in the <format> string is replaced by the user input,
 and the result is sent to i3 as a command. Default value is "%s".
 
 -l <limit>::
index 911fc995c47bd1b7acaddecaa428fe1d7b895118..e0c70c44e9231920e600573419a1712ce3c37d32 100644 (file)
@@ -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
index 9f5af8c20203bbfc4afa2927dbceb8c51c4a8b01..1612a5eff608cb8133442fd78cf256060d45684b 100644 (file)
@@ -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;
             }
index 27cdeb93fe571cd5d2869ad4855f9e4e415d8236..e97a37e1dce4a7ddce1bc6f8ed0cf89165480ef0 100644 (file)
@@ -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 (file)
index 0000000..0861b26
--- /dev/null
@@ -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 (executable)
index 0000000..abdb116
--- /dev/null
@@ -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 (executable)
index 0000000..f6911ca
--- /dev/null
@@ -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 (executable)
index 0000000..71feec3
--- /dev/null
@@ -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 (executable)
index 0000000..7dfd339
--- /dev/null
@@ -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 (executable)
index 0000000..688755c
--- /dev/null
@@ -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 (executable)
index 0000000..87c5dbb
--- /dev/null
@@ -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