language: cpp
dist: bionic

matrix:
  fast_finish: true
  include:
    - if: repo = arvidn/libtorrent
      env: variant=release sonar_scan=1 toolset=gcc
    - env: variant=release toolset=gcc check_headers=1 python=1
    - env: variant=test_debug crypto=openssl docs=1 tests=1 examples=1 tools=1 toolset=darwin
      os: osx
      osx_image: xcode11.2
    - env: variant=test_debug crypto=openssl python=1 toolset=darwin ios=1
      os: osx
      osx_image: xcode11.2
    - env: variant=debug toolset=gcc lint=1 pylint=1 clang_tidy=1
      addons:
        apt:
          packages:
          - python3-pip
    - env: variant=test_debug tests=1 toolset=gcc sanitizer=on fuzzers=1
    - env: variant=test_debug sim=1 crypto=openssl toolset=gcc sanitizer=on
    - env: variant=test_release coverage=1 tests=1 toolset=gcc-coverage
    - env: autotools=1 toolset=gcc install_boost=1
    - env: cmake=1 toolset=gcc install_boost=1
    - env: arch=arm toolset=gcc-arm
      addons:
        apt:
          packages:
          - libboost-tools-dev

notifications:
  email: false

git:
  submodules: false
  depth: 1

branches:
  only:
    - master
    - RC_1_2
    - RC_1_1

cache:
  directories:
    - $HOME/.ccache
    - $HOME/boost

# sources  list: https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json,
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
addons:
  apt:
    packages:
    - python3.7-dev
    - ninja-build

before_install:

  - 'if [[ "$TRAVIS_PULL_REQUEST" != "false" || "$TRAVIS_BRANCH" != "master" ]]; then
      export sonar_scan=0;
    fi'

  # pull down a recent version of boost and build boost-build
  - 'if [[ "$arch" != "arm" ]]; then
      cd $HOME;
      if [[ ! -d boost/.git ]]; then
        git clone --depth=1 --branch=boost-1.72.0 https://github.com/boostorg/boost.git;
      fi;
      export BOOST_ROOT=$PWD/boost;
      echo ${BOOST_ROOT};
      cd boost;
      git submodule update --init --depth=1;
      ./bootstrap.sh;
      ./b2 headers;
      if [[ "$install_boost" = "1" ]]; then
        sudo ./b2 cxxstd=11 release install --with-python --with-system | grep -v "^common.copy " | grep -v "^\.\.\.skipped " | grep -v "th target\.\.\.$";
        cd tools/build;
        ./bootstrap.sh;
        echo "installing boost.build";
        sudo ./b2 install --prefix=/usr/;
        sudo ln -s /usr/local/lib/libboost_python37.so /usr/local/lib/libboost_python.so;
        sudo ln -s /usr/local/lib/libboost_python36.so /usr/local/lib/libboost_python3.so;
      fi;
    fi'
  - export PATH=$BOOST_ROOT:$PATH

  - cd $TRAVIS_BUILD_DIR
  - git submodule update --init --recursive
  - 'if [[ $crypto == "" ]]; then export crypto=built-in; fi'
  - 'if [[ $sanitizer == "" ]]; then export sanitizer=off; fi'
  - 'if [[ $TRAVIS_OS_NAME == "osx" ]]; then
    travis_retry brew update > /dev/null && brew install ccache;
    fi'
  - 'if [[ $TRAVIS_OS_NAME == "osx" && "$python" == "1" ]]; then
      brew unlink python@2;
      travis_retry brew install python;
    fi'
  - 'if [[ "$python" == "1" ]]; then
       which python3;
       python3 --version;
    fi'
  - 'if [[ $TRAVIS_OS_NAME != "osx" ]]; then
      export B2=b2;
      export PIP=pip;
    else
      export B2=b2;
      export PIP=pip3;
      sysctl hw.ncpu;
    fi'
  # we have to use python from brew rather than the system provided python
  # because of OSX System Integrity Protection, which prevents injecting
  # user-libraries (i.e. python modules) into system binaries (i.e. /usr/bin/python)
  - 'if [ "$docs" = "1" ]; then
    ${PIP} install docutils;
    ${PIP} install Pygments;
    travis_retry brew install graphviz hunspell;
    fi'

  - if [ "$coverage" == "1" ]; then
    ${PIP} install --user codecov;
    fi
  - 'echo "toolset: " ${toolset}'
  - 'echo "variant: " ${variant}'
# disable leak checking for now. it reports some suspicious reports against some
# tests
  - export ASAN_OPTIONS=detect_leaks=0;
  - ulimit -a

install:

  - touch ~/user-config.jam
  - 'if [[ $toolset == "gcc" ]]; then
      g++ --version;
      echo "using gcc : : ccache g++ : <cxxflags>-std=c++11 ;" >> ~/user-config.jam;
    fi'
  - 'if [[ $toolset == "gcc-coverage" ]]; then
      echo "using gcc : coverage : ccache g++ --coverage : <cxxflags>-std=c++11 <linkflags>--coverage ;" >> ~/user-config.jam;
    fi'
  - 'if [[ $toolset == "gcc-arm" ]]; then
      echo "using gcc : arm : ccache armv8l-linux-gnueabihf-g++ :
        <cxxflags>-std=c++11
        <cxxflags>-fsigned-char
        <cxxflags>-march=armv8-a+crc
        <cxxflags>-mfpu=crypto-neon-fp-armv8
        <cxxflags>-DTORRENT_FORCE_ARM_CRC32
        <linkflags>-lm
        <linkflags>-static-libstdc++
        <linkflags>-static-libgcc ;" >> ~/user-config.jam;
    fi;'
  - 'if [ $clang_tidy == "1" ]; then
      echo "using clang_tidy : : clang-tidy "-checks=-clang-analyzer-core.*" : <cxxflags>-std=c++11 <cxxflags>-I/usr/local/clang-7.0.0/include/c++/v1 <cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++ ;" >> ~/user-config.jam;
    fi'
  - 'echo "using darwin : : ccache clang++ : <cxxflags>-std=c++11 ;" >> ~/user-config.jam'
  - 'echo "using darwin : ios_sim : ccache clang++ : <cflags>-std=c11 <cxxflags>-std=c++11 <compileflags>-Wno-deprecated-declarations
       <compileflags>\"-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk\"
       <compileflags>-mios-simulator-version-min=7
       <compileflags>-fobjc-abi-version=2
       <linkflags>\"-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk\"
       <linkflags>-mios-simulator-version-min=7
       <linkflags>-fobjc-abi-version=2 ;" >>~/user-config.jam'
  - 'echo "using darwin : ios : ccache clang++ : <cflags>-std=c11 <cxxflags>-std=c++11 <compileflags>-Wno-deprecated-declarations
       <compileflags>\"-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk\"
       <compileflags>-mios-version-min=7
       <compileflags>\"-arch armv7\"
       <compileflags>-fobjc-abi-version=2
       <linkflags>\"-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk\"
       <linkflags>-mios-version-min=7
       <linkflags>\"-arch armv7\"
       <linkflags>-fobjc-abi-version=2 ;" >>~/user-config.jam'
  - 'echo "using python : : $(which python3) : /usr/local/Frameworks/Python.framework/Headers : : <target-os>darwin ;" >> ~/user-config.jam'
  - 'echo "using python : : $(which python3) : : : <target-os>linux ;" >> ~/user-config.jam'
  - if [ "$docs" == "1" ]; then rst2html.py --version; fi
  - 'if [ "$lint" == "1" ]; then curl "https://raw.githubusercontent.com/google/styleguide/71ec7f1e524969c19ce33cfc72e8e023f2b98ee2/cpplint/cpplint.py" >~/cpplint.py; fi'
  - 'if [ "$pylint" == "1" ]; then
      sudo pip3 install flake8;
      flake8 --version;
      python3 -m flake8 --version;
    fi'
  - 'if [ $sonar_scan == "1" ]; then
      wget --quiet https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.2.0.1873-linux.zip;
      wget --quiet https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip;
      unzip sonar-scanner-cli-4.2.0.1873-linux.zip;
      unzip build-wrapper-linux-x86.zip;
      export PATH=$PWD/sonar-scanner-4.2.0.1873-linux/bin:$PWD/build-wrapper-linux-x86:$PATH;
    fi'

  - ccache -V
  - ccache --show-stats
  - ccache --zero-stats

  - 'if [[ "$arch" == "arm" ]]; then
      cd test;
      wget -O gcc-linaro.tar.xz https://releases.linaro.org/components/toolchain/binaries/5.3-2016.05/armv8l-linux-gnueabihf/gcc-linaro-5.3.1-2016.05-x86_64_armv8l-linux-gnueabihf.tar.xz;
      tar xf gcc-linaro.tar.xz;
      export PATH=${PWD}/gcc-linaro-5.3.1-2016.05-x86_64_armv8l-linux-gnueabihf/bin:${PATH};
      armv8l-linux-gnueabihf-g++ --version;
      wget -O boost.zip http://pilotfiber.dl.sourceforge.net/project/boost/boost/1.58.0/boost_1_58_0.zip;
      unzip -qq boost.zip;
      export BOOST_ROOT=$PWD/boost_1_58_0;
      travis_retry sudo apt-get install -y qemu-user-static;
      wget -O ubuntu-base.tar.gz http://cdimage.ubuntu.com/ubuntu-base/releases/14.04/release/ubuntu-base-14.04.5-base-armhf.tar.gz;
      sudo mkdir rootfs;
      sudo tar xf ubuntu-base.tar.gz -C rootfs;
      sudo cp /usr/bin/qemu-arm-static rootfs/usr/bin/;
      sudo chroot rootfs mount -t proc none /proc;
      cd ..;
    fi'

  - if [[ "$cmake" == "1" ]]; then
      which cmake;
      cmake --version;
    fi

script:

  - cd docs
  - 'if [ "$docs" == "1" ]; then
      make spell-check html RST2HTML=rst2html.py AAFIGURE=echo;
    fi'
  - cd ..

  - 'if [ "$lint" == "1" ]; then
      python ~/cpplint.py --extensions=cpp --headers=hpp --filter=-,+runtime/explicit,+whitespace/end_of_line --linelength=90 test/*.{cpp,hpp} src/*.cpp include/libtorrent/*.hpp include/libtorrent/kademlia/*.hpp src/kademlia/*.cpp include/libtorrent/aux_/*.hpp include/libtorrent/extensions/*.hpp simulation/*.{cpp,hpp} tools/*.{cpp,hpp} examples/*.{cpp,hpp};
    fi'
  - 'if [ "$pylint" == "1" ]; then
      flake8 --max-line-length=120;
      python3 -m flake8 --max-line-length=120;
    fi'
  - 'if [ "$sonar_scan" == "1" ]; then
       build-wrapper-linux-x86-64 --out-dir bw-output ${B2} -a -j2 optimization=off crypto=$crypto deprecated-functions=off $toolset variant=$variant -l300 &&
       sonar-scanner -D sonar.login=$SONAR_TOKEN;
    fi'
  - 'if [[ $clang_tidy == "1" ]]; then
       which clang-tidy;
       clang-tidy --version;
       ${B2} -a -j2 clang_tidy;
    fi'

  # the common boost-build command line arguments. It's important they are all
  # the same, in order for builds to be reused between invocations
  - export B2_ARGS="crypto=$crypto debug-iterators=on picker-debugging=on asserts=on invariant-checks=full $toolset variant=$variant"
  - 'if [[ $sanitizer == "on" ]]; then
      export B2_ARGS="${B2_ARGS} address-sanitizer=norecover undefined-sanitizer=norecover";
    fi'

  - 'if [[ $TRAVIS_OS_NAME == "osx" && "$crypto" == "openssl" ]]; then
    export B2_ARGS="${B2_ARGS} openssl-lib=/usr/local/opt/openssl@1.1/lib openssl-include=/usr/local/opt/openssl@1.1/include" ;
    fi'

  - 'if [ "$check_headers" == "1" ]; then
      ${B2} -j2 check-headers ${B2_ARGS};
    fi'

# if we are building with code coverage, report it as soon as possible
# libtorrent is the name of the test suite target
  - cd test
  - 'if [ "$tests" == "1" ]; then
      ${B2} -j2 warnings-as-errors=on warnings=all ${B2_ARGS} testing.execute=off &&
      travis_retry ${B2} -j3 warnings-as-errors=on warnings=all ${B2_ARGS} -l300 &&
      travis_retry ${B2} -j2 warnings-as-errors=on warnings=all ${B2_ARGS} test_natpmp enum_if -l300 &&
      if [[ $TRAVIS_OS_NAME != "osx" ]]; then
        travis_retry ${B2} -j2 warnings-as-errors=on warnings=all ${B2_ARGS} test_lsd -l300;
      fi &&
      if [ "$coverage" == "1" ]; then
        codecov --root .. --gcov-exec gcov-5;
      fi;
    fi'

  # build fuzzers with the same build configuration as the test above, to avoid
  # rebuilding libtorrent itself.
  - cd ../fuzzers
  - 'if [ "$fuzzers" == "1" ]; then
      ${B2} -j2 warnings-as-errors=on warnings=all crypto=$crypto debug-iterators=on picker-debugging=on asserts=on invariant-checks=full $toolset variant=$variant fuzz=off link=shared stage;
    fi'

  - cd ../examples
  - 'if [ "$examples" == "1" ]; then
      ${B2} -j2 warnings-as-errors=on warnings=all ${B2_ARGS} link=shared;
    fi'
  - cd ..

  - cd tools
  - 'if [ "$tools" == "1" ]; then
      ${B2} -j2 warnings-as-errors=on warnings=all ${B2_ARGS} link=shared;
    fi'
  - cd ..

  - if [[ $ios == "1" ]]; then
      ${B2} -q darwin-ios darwin-ios_sim -j2 link=static;
    fi

# a binary built with sanitizer does not interact well with python
# on OSX we need to use the brew version of python, for reasons explained above
# boost.python cannot be built with warnings-as-errors=on
  - cd bindings/python
  - 'if [[ "$python" == "1" ]]; then
      ${B2} -j2 warnings-as-errors=off warnings=all ${B2_ARGS} stage_module stage_dependencies libtorrent-link=shared boost-link=shared &&
      if [[ $TRAVIS_OS_NAME == "osx" ]]; then
        DYLD_LIBRARY_PATH=./dependencies python3 test.py -b;
      else
        LD_LIBRARY_PATH=./dependencies python3 test.py -b;
      fi;
    fi'
  - cd ../..;

# simulation
  - cd simulation
  - 'if [[ "$sim" == "1" ]]; then
      ${B2} -j2 crypto=built-in warnings-as-errors=on warnings=all debug-iterators=on picker-debugging=on asserts=on invariant-checks=full $toolset deprecated-functions=off;
    fi'
  - cd ..

# minimal support for cmake build
  - mkdir build && cd build
  - if [[ "$cmake" == "1" ]]; then
      export CXX=g++ &&
      export CC=gcc &&
      cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-Werror" -DCMAKE_CXX_STANDARD=11 -Dbuild_tests=ON -Dbuild_examples=ON -Dbuild_tools=ON -Dpython-bindings=ON -G Ninja .. &&
      cmake --build . --parallel 2;
    fi
  - cd ..

# run through autotools and ./configure to make sure it works
  - if [[ "$autotools" == "1" ]]; then
      ./autotool.sh &&
      export CXX=g++ &&
      export CC=gcc &&
      export CXXFLAGS="-Werror -Wno-deprecated-declarations" &&
      ./configure --enable-debug --enable-encryption --enable-examples --enable-tests --enable-python-binding &&
      make -j2 check;
    fi

  - ccache --show-stats

  - cd test
  - 'if [[ "$arch" == "arm" ]]; then
      ${B2} arm-tests warnings-as-errors=on warnings=all crypto=$crypto variant=test_arm $toolset target-os=linux link=static testing.launcher="sudo cp -R bin rootfs/; sudo chroot rootfs";
    fi'
  - cd ..
