#!/usr/bin/env bash

# Apache License Version 2.0, January 2004
# https://github.com/codecov/codecov-bash/blob/master/LICENSE

set -e +o pipefail

VERSION="1.0.1"

codecov_flags=( )
url="https://codecov.io"
env="$CODECOV_ENV"
service=""
token=""
search_in=""
# shellcheck disable=SC2153
flags="$CODECOV_FLAGS"
exit_with=0
curlargs=""
curlawsargs=""
dump="0"
clean="0"
curl_s="-s"
name="$CODECOV_NAME"
include_cov=""
exclude_cov=""
ddp="$HOME/Library/Developer/Xcode/DerivedData"
xp=""
files=""
save_to=""
direct_file_upload=""
cacert="$CODECOV_CA_BUNDLE"
gcov_ignore="-not -path './bower_components/**' -not -path './node_modules/**' -not -path './vendor/**'"
gcov_include=""

ft_gcov="1"
ft_coveragepy="1"
ft_fix="1"
ft_search="1"
ft_s3="1"
ft_network="1"
ft_xcodellvm="1"
ft_xcodeplist="0"
ft_gcovout="1"
ft_html="0"
ft_yaml="0"

_git_root=$(git rev-parse --show-toplevel 2>/dev/null || hg root 2>/dev/null || echo "$PWD")
git_root="$_git_root"
remote_addr=""
if [ "$git_root" = "$PWD" ];
then
  git_root="."
fi

branch_o=""
build_o=""
commit_o=""
pr_o=""
prefix_o=""
network_filter_o=""
search_in_o=""
slug_o=""
tag_o=""
url_o=""
git_ls_files_recurse_submodules_o=""
package="bash"

commit="$VCS_COMMIT_ID"
branch="$VCS_BRANCH_NAME"
pr="$VCS_PULL_REQUEST"
slug="$VCS_SLUG"
tag="$VCS_TAG"
# shellcheck disable=2153
build_url="$CI_BUILD_URL"
# shellcheck disable=2153
build="$CI_BUILD_ID"
job="$CI_JOB_ID"

beta_xcode_partials=""

proj_root="$git_root"
gcov_exe="gcov"
gcov_arg=""

b="\033[0;36m"
g="\033[0;32m"
r="\033[0;31m"
e="\033[0;90m"
y="\033[0;33m"
x="\033[0m"

show_help() {
cat << EOF

                Codecov Bash $VERSION

          Global report uploading tool for Codecov
       Documentation at https://docs.codecov.io/docs
    Contribute at https://github.com/codecov/codecov-bash


    -h          Display this help and exit
    -f FILE     Target file(s) to upload

                 -f "path/to/file"     only upload this file
                                       skips searching unless provided patterns below

                 -f '!*.bar'           ignore all files at pattern *.bar
                 -f '*.foo'            include all files at pattern *.foo
                 Must use single quotes.
                 This is non-exclusive, use -s "*.foo" to match specific paths.

    -s DIR       Directory to search for coverage reports.
                 Already searches project root and artifact folders.
    -t TOKEN     Set the private repository token
                 (option) set environment variable CODECOV_TOKEN=:uuid

                 -t @/path/to/token_file
                 -t uuid

    -n NAME      Custom defined name of the upload. Visible in Codecov UI

    -e ENV       Specify environment variables to be included with this build
                 Also accepting environment variables: CODECOV_ENV=VAR,VAR2

                 -e VAR,VAR2

    -k prefix    Prefix filepaths to help resolve path fixing

    -i prefix    Only include files in the network with a certain prefix. Useful for upload-specific path fixing

    -X feature   Toggle functionalities

                 -X gcov          Disable gcov
                 -X coveragepy    Disable python coverage
                 -X fix           Disable report fixing
                 -X search        Disable searching for reports
                 -X xcode         Disable xcode processing
                 -X network       Disable uploading the file network
                 -X gcovout       Disable gcov output
                 -X html          Enable coverage for HTML files
                 -X recursesubs   Enable recurse submodules in git projects when searching for source files
                 -X yaml          Enable coverage for YAML files

    -N           The commit SHA of the parent for which you are uploading coverage. If not present,
                 the parent will be determined using the API of your repository provider.
                 When using the repository provider's API, the parent is determined via finding
                 the closest ancestor to the commit.

    -R root dir  Used when not in git/hg project to identify project root directory
    -F flag      Flag the upload to group coverage metrics

                 -F unittests        This upload is only unittests
                 -F integration      This upload is only integration tests
                 -F ui,chrome        This upload is Chrome - UI tests

    -c           Move discovered coverage reports to the trash
    -z FILE      Upload specified file directly to Codecov and bypass all report generation.
                 This is intended to be used only with a pre-formatted Codecov report and is not
                 expected to work under any other circumstances.
    -Z           Exit with 1 if not successful. Default will Exit with 0

    -- xcode --
    -D           Custom Derived Data Path for Coverage.profdata and gcov processing
                 Default '~/Library/Developer/Xcode/DerivedData'
    -J           Specify packages to build coverage. Uploader will only build these packages.
                 This can significantly reduces time to build coverage reports.

                 -J 'MyAppName'      Will match "MyAppName" and "MyAppNameTests"
                 -J '^ExampleApp$'   Will match only "ExampleApp" not "ExampleAppTests"

    -- gcov --
    -g GLOB      Paths to ignore during gcov gathering
    -G GLOB      Paths to include during gcov gathering
    -p dir       Project root directory
                 Also used when preparing gcov
    -x gcovexe   gcov executable to run. Defaults to 'gcov'
    -a gcovargs  extra arguments to pass to gcov

    -- Override CI Environment Variables --
       These variables are automatically detected by popular CI providers

    -B branch    Specify the branch name
    -C sha       Specify the commit sha
    -P pr        Specify the pull request number
    -b build     Specify the build number
    -T tag       Specify the git tag

    -- Enterprise --
    -u URL       Set the target url for Enterprise customers
                 Not required when retrieving the bash uploader from your CCE
                 (option) Set environment variable CODECOV_URL=https://my-hosted-codecov.com
    -r SLUG      owner/repo slug used instead of the private repo token in Enterprise
                 (option) set environment variable CODECOV_SLUG=:owner/:repo
                 (option) set in your codecov.yml "codecov.slug"
    -S PATH      File path to your cacert.pem file used to verify ssl with Codecov Enterprise (optional)
                 (option) Set environment variable: CODECOV_CA_BUNDLE="/path/to/ca.pem"
    -U curlargs  Extra curl arguments to communicate with Codecov. e.g., -U "--proxy http://http-proxy"
    -A curlargs  Extra curl arguments to communicate with AWS.

    -- Debugging --
    -d           Don't upload, but dump upload file to stdout
    -q PATH      Write upload file to path
    -K           Remove color from the output
    -v           Verbose mode

EOF
}


say() {
  echo -e "$1"
}


urlencode() {
  echo "$1" | curl -Gso /dev/null -w "%{url_effective}" --data-urlencode @- "" | cut -c 3- | sed -e 's/%0A//'
}

swiftcov() {
  _dir=$(dirname "$1" | sed 's/\(Build\).*/\1/g')
  for _type in app framework xctest
  do
    find "$_dir" -name "*.$_type" | while read -r f
    do
      _proj=${f##*/}
      _proj=${_proj%."$_type"}
      if [ "$2" = "" ] || [ "$(echo "$_proj" | grep -i "$2")" != "" ];
      then
        say "    $g+$x Building reports for $_proj $_type"
        dest=$([ -f "$f/$_proj" ] && echo "$f/$_proj" || echo "$f/Contents/MacOS/$_proj")
        # shellcheck disable=SC2001
        _proj_name=$(echo "$_proj" | sed -e 's/[[:space:]]//g')
        # shellcheck disable=SC2086
        xcrun llvm-cov show $beta_xcode_partials -instr-profile "$1" "$dest" > "$_proj_name.$_type.coverage.txt" \
         || say "    ${r}x>${x} llvm-cov failed to produce results for $dest"
      fi
    done
  done
}


# Credits to: https://gist.github.com/pkuczynski/8665367
parse_yaml() {
   local prefix=$2
   local s='[[:space:]]*' w='[a-zA-Z0-9_]*'
   local fs
   fs=$(echo @|tr @ '\034')
   sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
        -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
   awk -F"$fs" '{
      indent = length($1)/2;
      vname[indent] = $2;
      for (i in vname) {if (i > indent) {delete vname[i]}}
      if (length($3) > 0) {
         vn=""; if (indent > 0) {vn=(vn)(vname[0])("_")}
         printf("%s%s%s=\"%s\"\n", "'"$prefix"'",vn, $2, $3);
      }
   }'
}

if [ $# != 0 ];
then
  while getopts "a:A:b:B:cC:dD:e:f:F:g:G:hi:J:k:Kn:p:P:Q:q:r:R:s:S:t:T:u:U:vx:X:Zz:N:-" o
  do
    codecov_flags+=( "$o" )
    case "$o" in
      "-")
        echo -e "${r}Long options are not supported${x}"
        exit 2
        ;;
      "?")
        ;;
      "N")
        parent=$OPTARG
        ;;
      "a")
        gcov_arg=$OPTARG
        ;;
      "A")
        curlawsargs="$OPTARG"
        ;;
      "b")
        build_o="$OPTARG"
        ;;
      "B")
        branch_o="$OPTARG"
        ;;
      "c")
        clean="1"
        ;;
      "C")
        commit_o="$OPTARG"
        ;;
      "d")
        dump="1"
        ;;
      "D")
        ddp="$OPTARG"
        ;;
      "e")
        env="$env,$OPTARG"
        ;;
      "f")
        if [ "${OPTARG::1}" = "!" ];
        then
          exclude_cov="$exclude_cov -not -path '${OPTARG:1}'"

        elif [[ "$OPTARG" = *"*"* ]];
        then
          include_cov="$include_cov -or -path '$OPTARG'"

        else
          ft_search=0
          if [ "$files" = "" ];
          then
            files="$OPTARG"
          else
            files="$files
$OPTARG"
          fi
        fi
        ;;
      "F")
        if [ "$flags" = "" ];
        then
          flags="$OPTARG"
        else
          flags="$flags,$OPTARG"
        fi
        ;;
      "g")
        gcov_ignore="$gcov_ignore -not -path '$OPTARG'"
        ;;
      "G")
        gcov_include="$gcov_include -path '$OPTARG'"
        ;;
      "h")
        show_help
        exit 0;
        ;;
      "i")
        network_filter_o="$OPTARG"
        ;;
      "J")
        ft_xcodellvm="1"
        ft_xcodeplist="0"
        if [ "$xp" = "" ];
        then
          xp="$OPTARG"
        else
          xp="$xp\|$OPTARG"
        fi
        ;;
      "k")
        prefix_o=$(echo "$OPTARG" | sed -e 's:^/*::' -e 's:/*$::')
        ;;
      "K")
        b=""
        g=""
        r=""
        e=""
        x=""
        ;;
      "n")
        name="$OPTARG"
        ;;
      "p")
        proj_root="$OPTARG"
        ;;
      "P")
        pr_o="$OPTARG"
        ;;
      "Q")
        # this is only meant for Codecov packages to overwrite
        package="$OPTARG"
        ;;
      "q")
        save_to="$OPTARG"
        ;;
      "r")
        slug_o="$OPTARG"
        ;;
      "R")
        git_root="$OPTARG"
        ;;
      "s")
        if [ "$search_in_o" = "" ];
        then
          search_in_o="$OPTARG"
        else
          search_in_o="$search_in_o $OPTARG"
        fi
        ;;
      "S")
        # shellcheck disable=SC2089
        cacert="--cacert \"$OPTARG\""
        ;;
      "t")
        if [ "${OPTARG::1}" = "@" ];
        then
          token=$(< "${OPTARG:1}" tr -d ' \n')
        else
          token="$OPTARG"
        fi
        ;;
      "T")
        tag_o="$OPTARG"
        ;;
      "u")
        url_o=$(echo "$OPTARG" | sed -e 's/\/$//')
        ;;
      "U")
        curlargs="$OPTARG"
        ;;
      "v")
        set -x
        curl_s=""
        ;;
      "x")
        gcov_exe=$OPTARG
        ;;
      "X")
        if [ "$OPTARG" = "gcov" ];
        then
          ft_gcov="0"
        elif [ "$OPTARG" = "coveragepy" ] || [ "$OPTARG" = "py" ];
        then
          ft_coveragepy="0"
        elif [ "$OPTARG" = "gcovout" ];
        then
          ft_gcovout="0"
        elif [ "$OPTARG" = "xcodellvm" ];
        then
          ft_xcodellvm="1"
          ft_xcodeplist="0"
        elif [ "$OPTARG" = "fix" ] || [ "$OPTARG" = "fixes" ];
        then
          ft_fix="0"
        elif [ "$OPTARG" = "xcode" ];
        then
          ft_xcodellvm="0"
          ft_xcodeplist="0"
        elif [ "$OPTARG" = "search" ];
        then
          ft_search="0"
        elif [ "$OPTARG" = "xcodepartials" ];
        then
          beta_xcode_partials="-use-color"
        elif [ "$OPTARG" = "network" ];
        then
          ft_network="0"
        elif [ "$OPTARG" = "s3" ];
        then
          ft_s3="0"
        elif [ "$OPTARG" = "html" ];
        then
          ft_html="1"
        elif [ "$OPTARG" = "recursesubs" ];
        then
          git_ls_files_recurse_submodules_o="--recurse-submodules"
        elif [ "$OPTARG" = "yaml" ];
        then
          ft_yaml="1"
        fi
        ;;
      "Z")
        exit_with=1
        ;;
      "z")
        direct_file_upload="$OPTARG"
        ft_gcov="0"
        ft_coveragepy="0"
        ft_fix="0"
        ft_search="0"
        ft_network="0"
        ft_xcodellvm="0"
        ft_gcovout="0"
        include_cov=""
        ;;
      *)
        echo -e "${r}Unexpected flag not supported${x}"
        ;;
    esac
  done
fi

say "
  _____          _
 / ____|        | |
| |     ___   __| | ___  ___ _____   __
| |    / _ \\ / _\` |/ _ \\/ __/ _ \\ \\ / /
| |___| (_) | (_| |  __/ (_| (_) \\ V /
 \\_____\\___/ \\__,_|\\___|\\___\\___/ \\_/
                              Bash-$VERSION

"

# check for installed tools
# git/hg
if [ "$direct_file_upload" = "" ];
then
  if [ -x "$(command -v git)" ];
  then
    say "$b==>$x $(git --version) found"
  else
    say "$y==>$x git not installed, testing for mercurial"
    if [ -x "$(command -v hg)" ];
    then
      say "$b==>$x $(hg --version) found"
    else
      say "$r==>$x git nor mercurial are installed. Uploader may fail or have unintended consequences"
    fi
  fi
fi
# curl
if [ -x "$(command -v curl)" ];
then
  say "$b==>$x $(curl --version)"
else
  say "$r==>$x curl not installed. Exiting."
  exit ${exit_with};
fi

search_in="$proj_root"

#shellcheck disable=SC2154
if [ "$JENKINS_URL" != "" ];
then
  say "$e==>$x Jenkins CI detected."
  # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project
  # https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables
  service="jenkins"

  # shellcheck disable=SC2154
  if [ "$ghprbSourceBranch" != "" ];
  then
     branch="$ghprbSourceBranch"
  elif [ "$GIT_BRANCH" != "" ];
  then
     branch="$GIT_BRANCH"
  elif [ "$BRANCH_NAME" != "" ];
  then
    branch="$BRANCH_NAME"
  fi

  # shellcheck disable=SC2154
  if [ "$ghprbActualCommit" != "" ];
  then
    commit="$ghprbActualCommit"
  elif [ "$GIT_COMMIT" != "" ];
  then
    commit="$GIT_COMMIT"
  fi

  # shellcheck disable=SC2154
  if [ "$ghprbPullId" != "" ];
  then
    pr="$ghprbPullId"
  elif [ "$CHANGE_ID" != "" ];
  then
    pr="$CHANGE_ID"
  fi

  build="$BUILD_NUMBER"
  # shellcheck disable=SC2153
  build_url=$(urlencode "$BUILD_URL")

elif [ "$CI" = "true" ] && [ "$TRAVIS" = "true" ] && [ "$SHIPPABLE" != "true" ];
then
  say "$e==>$x Travis CI detected."
  # https://docs.travis-ci.com/user/environment-variables/
  service="travis"
  commit="${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}"
  build="$TRAVIS_JOB_NUMBER"
  pr="$TRAVIS_PULL_REQUEST"
  job="$TRAVIS_JOB_ID"
  slug="$TRAVIS_REPO_SLUG"
  env="$env,TRAVIS_OS_NAME"
  tag="$TRAVIS_TAG"
  if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ];
  then
    branch="${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
  fi

  language=$(compgen -A variable | grep "^TRAVIS_.*_VERSION$" | head -1)
  if [ "$language" != "" ];
  then
    env="$env,${!language}"
  fi

elif [ "$CODEBUILD_CI" = "true" ];
then
  say "$e==>$x AWS Codebuild detected."
  # https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
  service="codebuild"
  commit="$CODEBUILD_RESOLVED_SOURCE_VERSION"
  build="$CODEBUILD_BUILD_ID"
  branch="$(echo "$CODEBUILD_WEBHOOK_HEAD_REF" | sed 's/^refs\/heads\///')"
  if [ "${CODEBUILD_SOURCE_VERSION/pr}" = "$CODEBUILD_SOURCE_VERSION" ] ; then
    pr="false"
  else
    pr="$(echo "$CODEBUILD_SOURCE_VERSION" | sed 's/^pr\///')"
  fi
  job="$CODEBUILD_BUILD_ID"
  slug="$(echo "$CODEBUILD_SOURCE_REPO_URL" | sed 's/^.*:\/\/[^\/]*\///' | sed 's/\.git$//')"

elif [ "$CI" = "true" ] && [ "$CI_NAME" = "codeship" ];
then
  say "$e==>$x Codeship CI detected."
  # https://www.codeship.io/documentation/continuous-integration/set-environment-variables/
  service="codeship"
  branch="$CI_BRANCH"
  build="$CI_BUILD_NUMBER"
  build_url=$(urlencode "$CI_BUILD_URL")
  commit="$CI_COMMIT_ID"

elif [ -n "$CF_BUILD_URL" ] && [ -n "$CF_BUILD_ID" ];
then
  say "$e==>$x Codefresh CI detected."
  # https://docs.codefresh.io/v1.0/docs/variables
  service="codefresh"
  branch="$CF_BRANCH"
  build="$CF_BUILD_ID"
  build_url=$(urlencode "$CF_BUILD_URL")
  commit="$CF_REVISION"

elif [ "$TEAMCITY_VERSION" != "" ];
then
  say "$e==>$x TeamCity CI detected."
  # https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters
  # https://confluence.jetbrains.com/plugins/servlet/mobile#content/view/74847298
  if [ "$TEAMCITY_BUILD_BRANCH" = '' ];
  then
    echo "    Teamcity does not automatically make build parameters available as environment variables."
    echo "    Add the following environment parameters to the build configuration"
    echo "    env.TEAMCITY_BUILD_BRANCH = %teamcity.build.branch%"
    echo "    env.TEAMCITY_BUILD_ID = %teamcity.build.id%"
    echo "    env.TEAMCITY_BUILD_URL = %teamcity.serverUrl%/viewLog.html?buildId=%teamcity.build.id%"
    echo "    env.TEAMCITY_BUILD_COMMIT = %system.build.vcs.number%"
    echo "    env.TEAMCITY_BUILD_REPOSITORY = %vcsroot.<YOUR TEAMCITY VCS NAME>.url%"
  fi
  service="teamcity"
  branch="$TEAMCITY_BUILD_BRANCH"
  build="$TEAMCITY_BUILD_ID"
  build_url=$(urlencode "$TEAMCITY_BUILD_URL")
  if [ "$TEAMCITY_BUILD_COMMIT" != "" ];
  then
    commit="$TEAMCITY_BUILD_COMMIT"
  else
    commit="$BUILD_VCS_NUMBER"
  fi
  remote_addr="$TEAMCITY_BUILD_REPOSITORY"

elif [ "$CI" = "true" ] && [ "$CIRCLECI" = "true" ];
then
  say "$e==>$x Circle CI detected."
  # https://circleci.com/docs/environment-variables
  service="circleci"
  branch="$CIRCLE_BRANCH"
  build="$CIRCLE_BUILD_NUM"
  job="$CIRCLE_NODE_INDEX"
  if [ "$CIRCLE_PROJECT_REPONAME" != "" ];
  then
    slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
  else
    # git@github.com:owner/repo.git
    slug="${CIRCLE_REPOSITORY_URL##*:}"
    # owner/repo.git
    slug="${slug%%.git}"
  fi
  pr="${CIRCLE_PULL_REQUEST##*/}"
  commit="$CIRCLE_SHA1"
  search_in="$search_in $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS"

elif [ "$BUDDYBUILD_BRANCH" != "" ];
then
  say "$e==>$x buddybuild detected"
  # http://docs.buddybuild.com/v6/docs/custom-prebuild-and-postbuild-steps
  service="buddybuild"
  branch="$BUDDYBUILD_BRANCH"
  build="$BUDDYBUILD_BUILD_NUMBER"
  build_url="https://dashboard.buddybuild.com/public/apps/$BUDDYBUILD_APP_ID/build/$BUDDYBUILD_BUILD_ID"
  # BUDDYBUILD_TRIGGERED_BY
  if [ "$ddp" = "$HOME/Library/Developer/Xcode/DerivedData" ];
  then
    ddp="/private/tmp/sandbox/${BUDDYBUILD_APP_ID}/bbtest"
  fi

elif [ "${bamboo_planRepository_revision}" != "" ];
then
  say "$e==>$x Bamboo detected"
  # https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html#Bamboovariables-Build-specificvariables
  service="bamboo"
  commit="${bamboo_planRepository_revision}"
  # shellcheck disable=SC2154
  branch="${bamboo_planRepository_branch}"
  # shellcheck disable=SC2154
  build="${bamboo_buildNumber}"
  # shellcheck disable=SC2154
  build_url="${bamboo_buildResultsUrl}"
  # shellcheck disable=SC2154
  remote_addr="${bamboo_planRepository_repositoryUrl}"

elif [ "$CI" = "true" ] && [ "$BITRISE_IO" = "true" ];
then
  # http://devcenter.bitrise.io/faq/available-environment-variables/
  say "$e==>$x Bitrise CI detected."
  service="bitrise"
  branch="$BITRISE_GIT_BRANCH"
  build="$BITRISE_BUILD_NUMBER"
  build_url=$(urlencode "$BITRISE_BUILD_URL")
  pr="$BITRISE_PULL_REQUEST"
  if [ "$GIT_CLONE_COMMIT_HASH" != "" ];
  then
    commit="$GIT_CLONE_COMMIT_HASH"
  fi

elif [ "$CI" = "true" ] && [ "$SEMAPHORE" = "true" ];
then
  say "$e==>$x Semaphore CI detected."
# https://docs.semaphoreci.com/ci-cd-environment/environment-variables/#semaphore-related
  service="semaphore"
  branch="$SEMAPHORE_GIT_BRANCH"
  build="$SEMAPHORE_WORKFLOW_NUMBER"
  job="$SEMAPHORE_JOB_ID"
  pr="$PULL_REQUEST_NUMBER"
  slug="$SEMAPHORE_REPO_SLUG"
  commit="$REVISION"
  env="$env,SEMAPHORE_TRIGGER_SOURCE"

elif [ "$CI" = "true" ] && [ "$BUILDKITE" = "true" ];
then
  say "$e==>$x Buildkite CI detected."
  # https://buildkite.com/docs/guides/environment-variables
  service="buildkite"
  branch="$BUILDKITE_BRANCH"
  build="$BUILDKITE_BUILD_NUMBER"
  job="$BUILDKITE_JOB_ID"
  build_url=$(urlencode "$BUILDKITE_BUILD_URL")
  slug="$BUILDKITE_PROJECT_SLUG"
  commit="$BUILDKITE_COMMIT"
  if [[ "$BUILDKITE_PULL_REQUEST" != "false" ]]; then
    pr="$BUILDKITE_PULL_REQUEST"
  fi
  tag="$BUILDKITE_TAG"

elif [ "$CI" = "drone" ] || [ "$DRONE" = "true" ];
then
  say "$e==>$x Drone CI detected."
  # http://docs.drone.io/env.html
  # drone commits are not full shas
  service="drone.io"
  branch="$DRONE_BRANCH"
  build="$DRONE_BUILD_NUMBER"
  build_url=$(urlencode "${DRONE_BUILD_LINK}")
  pr="$DRONE_PULL_REQUEST"
  job="$DRONE_JOB_NUMBER"
  tag="$DRONE_TAG"

elif [ "$CI" = "true" ] && [ "$HEROKU_TEST_RUN_BRANCH" != "" ];
then
  say "$e==>$x Heroku CI detected."
  # https://devcenter.heroku.com/articles/heroku-ci#environment-variables
  service="heroku"
  branch="$HEROKU_TEST_RUN_BRANCH"
  build="$HEROKU_TEST_RUN_ID"
  commit="$HEROKU_TEST_RUN_COMMIT_VERSION"

elif [[ "$CI" = "true" || "$CI" = "True" ]] && [[ "$APPVEYOR" = "true" || "$APPVEYOR" = "True" ]];
then
  say "$e==>$x Appveyor CI detected."
  # http://www.appveyor.com/docs/environment-variables
  service="appveyor"
  branch="$APPVEYOR_REPO_BRANCH"
  build=$(urlencode "$APPVEYOR_JOB_ID")
  pr="$APPVEYOR_PULL_REQUEST_NUMBER"
  job="$APPVEYOR_ACCOUNT_NAME%2F$APPVEYOR_PROJECT_SLUG%2F$APPVEYOR_BUILD_VERSION"
  slug="$APPVEYOR_REPO_NAME"
  commit="$APPVEYOR_REPO_COMMIT"
  build_url=$(urlencode "${APPVEYOR_URL}/project/${APPVEYOR_REPO_NAME}/builds/$APPVEYOR_BUILD_ID/job/${APPVEYOR_JOB_ID}")

elif [ "$CI" = "true" ] && [ "$WERCKER_GIT_BRANCH" != "" ];
then
  say "$e==>$x Wercker CI detected."
  # http://devcenter.wercker.com/articles/steps/variables.html
  service="wercker"
  branch="$WERCKER_GIT_BRANCH"
  build="$WERCKER_MAIN_PIPELINE_STARTED"
  slug="$WERCKER_GIT_OWNER/$WERCKER_GIT_REPOSITORY"
  commit="$WERCKER_GIT_COMMIT"

elif [ "$CI" = "true" ] && [ "$MAGNUM" = "true" ];
then
  say "$e==>$x Magnum CI detected."
  # https://magnum-ci.com/docs/environment
  service="magnum"
  branch="$CI_BRANCH"
  build="$CI_BUILD_NUMBER"
  commit="$CI_COMMIT"

elif [ "$SHIPPABLE" = "true" ];
then
  say "$e==>$x Shippable CI detected."
  # http://docs.shippable.com/ci_configure/
  service="shippable"
  # shellcheck disable=SC2153
  branch=$([ "$HEAD_BRANCH" != "" ] && echo "$HEAD_BRANCH" || echo "$BRANCH")
  build="$BUILD_NUMBER"
  build_url=$(urlencode "$BUILD_URL")
  pr="$PULL_REQUEST"
  slug="$REPO_FULL_NAME"
  # shellcheck disable=SC2153
  commit="$COMMIT"

elif [ "$TDDIUM" = "true" ];
then
  say "Solano CI detected."
  # http://docs.solanolabs.com/Setup/tddium-set-environment-variables/
  service="solano"
  commit="$TDDIUM_CURRENT_COMMIT"
  branch="$TDDIUM_CURRENT_BRANCH"
  build="$TDDIUM_TID"
  pr="$TDDIUM_PR_ID"

elif [ "$GREENHOUSE" = "true" ];
then
  say "$e==>$x Greenhouse CI detected."
  # http://docs.greenhouseci.com/docs/environment-variables-files
  service="greenhouse"
  branch="$GREENHOUSE_BRANCH"
  build="$GREENHOUSE_BUILD_NUMBER"
  build_url=$(urlencode "$GREENHOUSE_BUILD_URL")
  pr="$GREENHOUSE_PULL_REQUEST"
  commit="$GREENHOUSE_COMMIT"
  search_in="$search_in $GREENHOUSE_EXPORT_DIR"

elif [ "$GITLAB_CI" != "" ];
then
  say "$e==>$x GitLab CI detected."
  # http://doc.gitlab.com/ce/ci/variables/README.html
  service="gitlab"
  branch="${CI_BUILD_REF_NAME:-$CI_COMMIT_REF_NAME}"
  build="${CI_BUILD_ID:-$CI_JOB_ID}"
  remote_addr="${CI_BUILD_REPO:-$CI_REPOSITORY_URL}"
  commit="${CI_BUILD_REF:-$CI_COMMIT_SHA}"
  slug="${CI_PROJECT_PATH}"

elif [ "$GITHUB_ACTIONS" != "" ];
then
  say "$e==>$x GitHub Actions detected."
  say "    Env vars used:"
  say "      -> GITHUB_ACTIONS:    ${GITHUB_ACTIONS}"
  say "      -> GITHUB_HEAD_REF:   ${GITHUB_HEAD_REF}"
  say "      -> GITHUB_REF:        ${GITHUB_REF}"
  say "      -> GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}"
  say "      -> GITHUB_RUN_ID:     ${GITHUB_RUN_ID}"
  say "      -> GITHUB_SHA:        ${GITHUB_SHA}"
  say "      -> GITHUB_WORKFLOW:   ${GITHUB_WORKFLOW}"

  # https://github.com/features/actions
  service="github-actions"

  # https://help.github.com/en/articles/virtual-environments-for-github-actions#environment-variables
  branch="${GITHUB_REF#refs/heads/}"
  if [  "$GITHUB_HEAD_REF" != "" ];
  then
    # PR refs are in the format: refs/pull/7/merge
    pr="${GITHUB_REF#refs/pull/}"
    pr="${pr%/merge}"
    branch="${GITHUB_HEAD_REF}"
  fi
  commit="${GITHUB_SHA}"
  slug="${GITHUB_REPOSITORY}"
  build="${GITHUB_RUN_ID}"
  build_url=$(urlencode "http://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}")
  job="$(urlencode "${GITHUB_WORKFLOW}")"

  # actions/checkout runs in detached HEAD
  mc=
  if [ -n "$pr" ] && [ "$pr" != false ] && [ "$commit_o" == "" ];
  then
    mc=$(git show --no-patch --format="%P" 2>/dev/null || echo "")

    if [[ "$mc" =~ ^[a-z0-9]{40}[[:space:]][a-z0-9]{40}$ ]];
    then
      mc=$(echo "$mc" | cut -d' ' -f2)
      say "    Fixing merge commit SHA $commit -> $mc"
      commit=$mc
    elif [[ "$mc" = "" ]];
    then
      say "$r->  Issue detecting commit SHA. Please run actions/checkout with fetch-depth > 1 or set to 0$x"
    fi
  fi

elif [ "$SYSTEM_TEAMFOUNDATIONSERVERURI" != "" ];
then
  say "$e==>$x Azure Pipelines detected."
  # https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=vsts
  # https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&viewFallbackFrom=vsts&tabs=yaml
  service="azure_pipelines"
  commit="$BUILD_SOURCEVERSION"
  build="$BUILD_BUILDNUMBER"
  if [  -z "$SYSTEM_PULLREQUEST_PULLREQUESTNUMBER" ];
  then
    pr="$SYSTEM_PULLREQUEST_PULLREQUESTID"
  else
    pr="$SYSTEM_PULLREQUEST_PULLREQUESTNUMBER"
  fi
  project="${SYSTEM_TEAMPROJECT}"
  server_uri="${SYSTEM_TEAMFOUNDATIONSERVERURI}"
  job="${BUILD_BUILDID}"
  branch="${BUILD_SOURCEBRANCH#"refs/heads/"}"
  build_url=$(urlencode "${SYSTEM_TEAMFOUNDATIONSERVERURI}${SYSTEM_TEAMPROJECT}/_build/results?buildId=${BUILD_BUILDID}")

  # azure/pipelines runs in detached HEAD
  mc=
  if [ -n "$pr" ] && [ "$pr" != false ];
  then
    mc=$(git show --no-patch --format="%P" 2>/dev/null || echo "")

    if [[ "$mc" =~ ^[a-z0-9]{40}[[:space:]][a-z0-9]{40}$ ]];
    then
      mc=$(echo "$mc" | cut -d' ' -f2)
      say "    Fixing merge commit SHA $commit -> $mc"
      commit=$mc
    fi
  fi

elif [ "$CI" = "true" ] && [ "$BITBUCKET_BUILD_NUMBER" != "" ];
then
  say "$e==>$x Bitbucket detected."
  # https://confluence.atlassian.com/bitbucket/variables-in-pipelines-794502608.html
  service="bitbucket"
  branch="$BITBUCKET_BRANCH"
  build="$BITBUCKET_BUILD_NUMBER"
  slug="$BITBUCKET_REPO_OWNER/$BITBUCKET_REPO_SLUG"
  job="$BITBUCKET_BUILD_NUMBER"
  pr="$BITBUCKET_PR_ID"
  commit="$BITBUCKET_COMMIT"
  # See https://jira.atlassian.com/browse/BCLOUD-19393
  if [ "${#commit}" = 12 ];
  then
    commit=$(git rev-parse "$BITBUCKET_COMMIT")
  fi

elif [ "$CI" = "true" ] && [ "$BUDDY" = "true" ];
then
  say "$e==>$x Buddy CI detected."
  # https://buddy.works/docs/pipelines/environment-variables
  service="buddy"
  branch="$BUDDY_EXECUTION_BRANCH"
  build="$BUDDY_EXECUTION_ID"
  build_url=$(urlencode "$BUDDY_EXECUTION_URL")
  commit="$BUDDY_EXECUTION_REVISION"
  pr="$BUDDY_EXECUTION_PULL_REQUEST_NO"
  tag="$BUDDY_EXECUTION_TAG"
  slug="$BUDDY_REPO_SLUG"

elif [ "$CIRRUS_CI" != "" ];
then
  say "$e==>$x Cirrus CI detected."
  # https://cirrus-ci.org/guide/writing-tasks/#environment-variables
  service="cirrus-ci"
  slug="$CIRRUS_REPO_FULL_NAME"
  branch="$CIRRUS_BRANCH"
  pr="$CIRRUS_PR"
  commit="$CIRRUS_CHANGE_IN_REPO"
  build="$CIRRUS_BUILD_ID"
  build_url=$(urlencode "https://cirrus-ci.com/task/$CIRRUS_TASK_ID")
  job="$CIRRUS_TASK_NAME"

elif [ "$DOCKER_REPO" != "" ];
then
  say "$e==>$x Docker detected."
  # https://docs.docker.com/docker-cloud/builds/advanced/
  service="docker"
  branch="$SOURCE_BRANCH"
  commit="$SOURCE_COMMIT"
  slug="$DOCKER_REPO"
  tag="$CACHE_TAG"
  env="$env,IMAGE_NAME"

else
  say "${r}x>${x} No CI provider detected."
  say "    Testing inside Docker? ${b}http://docs.codecov.io/docs/testing-with-docker${x}"
  say "    Testing with Tox? ${b}https://docs.codecov.io/docs/python#section-testing-with-tox${x}"

fi

say "    ${e}project root:${x} $git_root"

# find branch, commit, repo from git command
if [ "$GIT_BRANCH" != "" ];
then
  branch="$GIT_BRANCH"

elif [ "$branch" = "" ];
then
  branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || hg branch 2>/dev/null || echo "")
  if [ "$branch" = "HEAD" ];
  then
    branch=""
  fi
fi

if [ "$commit_o" = "" ];
then
  if [ "$GIT_COMMIT" != "" ];
  then
    commit="$GIT_COMMIT"
  elif [ "$commit" = "" ];
  then
    commit=$(git log -1 --format="%H" 2>/dev/null || hg id -i --debug 2>/dev/null | tr -d '+' || echo "")
  fi
else
  commit="$commit_o"
fi

if [ "$CODECOV_TOKEN" != "" ] && [ "$token" = "" ];
then
  say "${e}-->${x} token set from env"
  token="$CODECOV_TOKEN"
fi

if [ "$CODECOV_URL" != "" ] && [ "$url_o" = "" ];
then
  say "${e}-->${x} url set from env"
  url_o=$(echo "$CODECOV_URL" | sed -e 's/\/$//')
fi

if [ "$CODECOV_SLUG" != "" ];
then
  say "${e}-->${x} slug set from env"
  slug_o="$CODECOV_SLUG"

elif [ "$slug" = "" ];
then
  if [ "$remote_addr" = "" ];
  then
    remote_addr=$(git config --get remote.origin.url || hg paths default || echo '')
  fi
  if [ "$remote_addr" != "" ];
  then
    if echo "$remote_addr" | grep -q "//"; then
      # https
      slug=$(echo "$remote_addr" | cut -d / -f 4,5 | sed -e 's/\.git$//')
    else
      # ssh
      slug=$(echo "$remote_addr" | cut -d : -f 2 | sed -e 's/\.git$//')
    fi
  fi
  if [ "$slug" = "/" ];
  then
    slug=""
  fi
fi

yaml=$(cd "$git_root" && \
          git ls-files "*codecov.yml" "*codecov.yaml" 2>/dev/null \
       || hg locate "*codecov.yml" "*codecov.yaml" 2>/dev/null \
       || cd "$proj_root" && find . -maxdepth 1 -type f -name '*codecov.y*ml' 2>/dev/null \
       || echo '')
yaml=$(echo "$yaml" | head -1)

if [ "$yaml" != "" ];
then
  say "    ${e}Yaml found at:${x} $yaml"
  if [[ "$yaml" != /* ]]; then
    # relative path for yaml file given, assume relative to the repo root
    yaml="$git_root/$yaml"
  fi
  config=$(parse_yaml "$yaml" || echo '')

  # TODO validate the yaml here

  if [ "$(echo "$config" | grep 'codecov_token="')" != "" ] && [ "$token" = "" ];
  then
    say "${e}-->${x} token set from yaml"
    token="$(echo "$config" | grep 'codecov_token="' | sed -e 's/codecov_token="//' | sed -e 's/"\.*//')"
  fi

  if [ "$(echo "$config" | grep 'codecov_url="')" != "" ] && [ "$url_o" = "" ];
  then
    say "${e}-->${x} url set from yaml"
    url_o="$(echo "$config" | grep 'codecov_url="' | sed -e 's/codecov_url="//' | sed -e 's/"\.*//')"
  fi

  if [ "$(echo "$config" | grep 'codecov_slug="')" != "" ] && [ "$slug_o" = "" ];
  then
    say "${e}-->${x} slug set from yaml"
    slug_o="$(echo "$config" | grep 'codecov_slug="' | sed -e 's/codecov_slug="//' | sed -e 's/"\.*//')"
  fi
else
  say "    ${g}Yaml not found, that's ok! Learn more at${x} ${b}http://docs.codecov.io/docs/codecov-yaml${x}"
fi

if [ "$branch_o" != "" ];
then
  branch=$(urlencode "$branch_o")
else
  branch=$(urlencode "$branch")
fi

if [ "$slug_o" = "" ];
then
  urlencoded_slug=$(urlencode "$slug")
else
  urlencoded_slug=$(urlencode "$slug_o")
fi

query="branch=$branch\
       &commit=$commit\
       &build=$([ "$build_o" = "" ] && echo "$build" || echo "$build_o")\
       &build_url=$build_url\
       &name=$(urlencode "$name")\
       &tag=$([ "$tag_o" = "" ] && echo "$tag" || echo "$tag_o")\
       &slug=$urlencoded_slug\
       &service=$service\
       &flags=$flags\
       &pr=$([ "$pr_o" = "" ] && echo "${pr##\#}" || echo "${pr_o##\#}")\
       &job=$job\
       &cmd_args=$(IFS=,; echo "${codecov_flags[*]}")"

if [ -n "$project" ] && [ -n "$server_uri" ];
then
  query=$(echo "$query&project=$project&server_uri=$server_uri" | tr -d ' ')
fi

if [ "$parent" != "" ];
then
  query=$(echo "parent=$parent&$query" | tr -d ' ')
fi

if [ "$ft_search" = "1" ];
then
  # detect bower comoponents location
  bower_components="bower_components"
  bower_rc=$(cd "$git_root" && cat .bowerrc 2>/dev/null || echo "")
  if [ "$bower_rc" != "" ];
  then
    bower_components=$(echo "$bower_rc" | tr -d '\n' | grep '"directory"' | cut -d'"' -f4 | sed -e 's/\/$//')
    if [ "$bower_components" = "" ];
    then
      bower_components="bower_components"
    fi
  fi

  # Swift Coverage
  if [ "$ft_xcodellvm" = "1" ] && [ -d "$ddp" ];
  then
    say "${e}==>${x} Processing Xcode reports via llvm-cov"
    say "    DerivedData folder: $ddp"
    profdata_files=$(find "$ddp" -name '*.profdata' 2>/dev/null || echo '')
    if [ "$profdata_files" != "" ];
    then
      # xcode via profdata
      if [ "$xp" = "" ];
      then
        # xp=$(xcodebuild -showBuildSettings 2>/dev/null | grep -i "^\s*PRODUCT_NAME" | sed -e 's/.*= \(.*\)/\1/')
        # say " ${e}->${x} Speed up Xcode processing by adding ${e}-J '$xp'${x}"
        say "    ${g}hint${x} Speed up Swift processing by using use ${g}-J 'AppName'${x} (regexp accepted)"
        say "    ${g}hint${x} This will remove Pods/ from your report. Also ${b}https://docs.codecov.io/docs/ignoring-paths${x}"
      fi
      while read -r profdata;
      do
        if [ "$profdata" != "" ];
        then
          swiftcov "$profdata" "$xp"
        fi
      done <<< "$profdata_files"
    else
      say "    ${e}->${x} No Swift coverage found"
    fi

    # Obj-C Gcov Coverage
    if [ "$ft_gcov" = "1" ];
    then
      say "    ${e}->${x} Running $gcov_exe for Obj-C"
      if [ "$ft_gcovout" = "0" ];
      then
        # suppress gcov output
        bash -c "find $ddp -type f -name '*.gcda' $gcov_include $gcov_ignore -exec $gcov_exe -p $gcov_arg {} +" >/dev/null 2>&1 || true
      else
        bash -c "find $ddp -type f -name '*.gcda' $gcov_include $gcov_ignore -exec $gcov_exe -p $gcov_arg {} +" || true
      fi
    fi
  fi

  if [ "$ft_xcodeplist" = "1" ] && [ -d "$ddp" ];
  then
    say "${e}==>${x} Processing Xcode plists"
    plists_files=$(find "$ddp" -name '*.xccoverage' 2>/dev/null || echo '')
    if [ "$plists_files" != "" ];
    then
      while read -r plist;
      do
        if [ "$plist" != "" ];
        then
          say "    ${g}Found${x} plist file at $plist"
          plutil -convert xml1 -o "$(basename "$plist").plist" -- "$plist"
        fi
      done <<< "$plists_files"
    fi
  fi

  # Gcov Coverage
  if [ "$ft_gcov" = "1" ];
  then
    say "${e}==>${x} Running $gcov_exe in $proj_root ${e}(disable via -X gcov)${x}"
    if [ "$ft_gcovout" = "0" ];
    then
      # suppress gcov output
      bash -c "find $proj_root -type f -name '*.gcno' $gcov_include $gcov_ignore -exec $gcov_exe -pb $gcov_arg {} +" >/dev/null 2>&1 || true
    else
      bash -c "find $proj_root -type f -name '*.gcno' $gcov_include $gcov_ignore -exec $gcov_exe -pb $gcov_arg {} +" || true
    fi
  else
    say "${e}==>${x} gcov disabled"
  fi

  # Python Coverage
  if [ "$ft_coveragepy" = "1" ];
  then
    if [ ! -f coverage.xml ];
    then
      if command -v coverage >/dev/null 2>&1;
      then
        say "${e}==>${x} Python coveragepy exists ${e}disable via -X coveragepy${x}"

        dotcoverage=$(find "$git_root" -name '.coverage' -or -name '.coverage.*' | head -1 || echo '')
        if [ "$dotcoverage" != "" ];
        then
          cd "$(dirname "$dotcoverage")"
          if [ ! -f .coverage ];
          then
            say "    ${e}->${x} Running coverage combine"
            coverage combine -a
          fi
          say "    ${e}->${x} Running coverage xml"
          if [ "$(coverage xml -i)" != "No data to report." ];
          then
            files="$files
$PWD/coverage.xml"
          else
            say "    ${r}No data to report.${x}"
          fi
          cd "$proj_root"
        else
          say "    ${r}No .coverage file found.${x}"
        fi
      else
        say "${e}==>${x} Python coveragepy not found"
      fi
    fi
  else
    say "${e}==>${x} Python coveragepy disabled"
  fi

  if [ "$search_in_o" != "" ];
  then
    # location override
    search_in="$search_in_o"
  fi

  say "$e==>$x Searching for coverage reports in:"
  for _path in $search_in
  do
    say "    ${g}+${x} $_path"
  done

  patterns="find $search_in \( \
                        -name vendor \
                        -or -name '$bower_components' \
                        -or -name '.egg-info*' \
                        -or -name 'conftest_*.c.gcov' \
                        -or -name .env \
                        -or -name .envs \
                        -or -name .git \
                        -or -name .hg \
                        -or -name .tox \
                        -or -name .venv \
                        -or -name .venvs \
                        -or -name .virtualenv \
                        -or -name .virtualenvs \
                        -or -name .yarn-cache \
                        -or -name __pycache__ \
                        -or -name env \
                        -or -name envs \
                        -or -name htmlcov \
                        -or -name js/generated/coverage \
                        -or -name node_modules \
                        -or -name venv \
                        -or -name venvs \
                        -or -name virtualenv \
                        -or -name virtualenvs \
                    \) -prune -or \
                    -type f \( -name '*coverage*.*' \
                     -or -name '*.clover' \
                     -or -name '*.codecov.*' \
                     -or -name '*.gcov' \
                     -or -name '*.lcov' \
                     -or -name '*.lst' \
                     -or -name 'clover.xml' \
                     -or -name 'cobertura.xml' \
                     -or -name 'codecov.*' \
                     -or -name 'cover.out' \
                     -or -name 'codecov-result.json' \
                     -or -name 'coverage-final.json' \
                     -or -name 'excoveralls.json' \
                     -or -name 'gcov.info' \
                     -or -name 'jacoco*.xml' \
                     -or -name '*Jacoco*.xml' \
                     -or -name 'lcov.dat' \
                     -or -name 'lcov.info' \
                     -or -name 'luacov.report.out' \
                     -or -name 'naxsi.info' \
                     -or -name 'nosetests.xml' \
                     -or -name 'report.xml' \
                     $include_cov \) \
                    $exclude_cov \
                    -not -name '*.am' \
                    -not -name '*.bash' \
                    -not -name '*.bat' \
                    -not -name '*.bw' \
                    -not -name '*.cfg' \
                    -not -name '*.class' \
                    -not -name '*.cmake' \
                    -not -name '*.cmake' \
                    -not -name '*.conf' \
                    -not -name '*.coverage' \
                    -not -name '*.cp' \
                    -not -name '*.cpp' \
                    -not -name '*.crt' \
                    -not -name '*.css' \
                    -not -name '*.csv' \
                    -not -name '*.csv' \
                    -not -name '*.data' \
                    -not -name '*.db' \
                    -not -name '*.dox' \
                    -not -name '*.ec' \
                    -not -name '*.ec' \
                    -not -name '*.egg' \
                    -not -name '*.el' \
                    -not -name '*.env' \
                    -not -name '*.erb' \
                    -not -name '*.exe' \
                    -not -name '*.ftl' \
                    -not -name '*.gif' \
                    -not -name '*.gradle' \
                    -not -name '*.gz' \
                    -not -name '*.h' \
                    -not -name '*.html' \
                    -not -name '*.in' \
                    -not -name '*.jade' \
                    -not -name '*.jar*' \
                    -not -name '*.jpeg' \
                    -not -name '*.jpg' \
                    -not -name '*.js' \
                    -not -name '*.less' \
                    -not -name '*.log' \
                    -not -name '*.m4' \
                    -not -name '*.mak*' \
                    -not -name '*.md' \
                    -not -name '*.o' \
                    -not -name '*.p12' \
                    -not -name '*.pem' \
                    -not -name '*.png' \
                    -not -name '*.pom*' \
                    -not -name '*.profdata' \
                    -not -name '*.proto' \
                    -not -name '*.ps1' \
                    -not -name '*.pth' \
                    -not -name '*.py' \
                    -not -name '*.pyc' \
                    -not -name '*.pyo' \
                    -not -name '*.rb' \
                    -not -name '*.rsp' \
                    -not -name '*.rst' \
                    -not -name '*.ru' \
                    -not -name '*.sbt' \
                    -not -name '*.scss' \
                    -not -name '*.scss' \
                    -not -name '*.serialized' \
                    -not -name '*.sh' \
                    -not -name '*.snapshot' \
                    -not -name '*.sql' \
                    -not -name '*.svg' \
                    -not -name '*.tar.tz' \
                    -not -name '*.template' \
                    -not -name '*.whl' \
                    -not -name '*.xcconfig' \
                    -not -name '*.xcoverage.*' \
                    -not -name '*/classycle/report.xml' \
                    -not -name '*codecov.yml' \
                    -not -name '*~' \
                    -not -name '.*coveragerc' \
                    -not -name '.coverage*' \
                    -not -name 'coverage-summary.json' \
                    -not -name 'createdFiles.lst' \
                    -not -name 'fullLocaleNames.lst' \
                    -not -name 'include.lst' \
                    -not -name 'inputFiles.lst' \
                    -not -name 'phpunit-code-coverage.xml' \
                    -not -name 'phpunit-coverage.xml' \
                    -not -name 'remapInstanbul.coverage*.json' \
                    -not -name 'scoverage.measurements.*' \
                    -not -name 'test_*_coverage.txt' \
                    -not -name 'testrunner-coverage*' \
                    -print 2>/dev/null"
  files=$(eval "$patterns" || echo '')

elif [ "$include_cov" != "" ];
then
  files=$(eval "find $search_in -type f \( ${include_cov:5} \)$exclude_cov 2>/dev/null" || echo '')
elif [ "$direct_file_upload" != "" ];
then
  files=$direct_file_upload
fi

num_of_files=$(echo "$files" | wc -l | tr -d ' ')
if [ "$num_of_files" != '' ] && [ "$files" != '' ];
then
  say "    ${e}->${x} Found $num_of_files reports"
fi

# no files found
if [ "$files" = "" ];
then
  say "${r}-->${x} No coverage report found."
  say "    Please visit ${b}http://docs.codecov.io/docs/supported-languages${x}"
  exit ${exit_with};
fi

if [ "$ft_network" == "1" ];
then
  say "${e}==>${x} Detecting git/mercurial file structure"
  network=$(cd "$git_root" && git ls-files $git_ls_files_recurse_submodules_o 2>/dev/null || hg locate 2>/dev/null || echo "")
  if [ "$network" = "" ];
  then
    network=$(find "$git_root" \( \
                   -name virtualenv \
                   -name .virtualenv \
                   -name virtualenvs \
                   -name .virtualenvs \
                   -name '*.png' \
                   -name '*.gif' \
                   -name '*.jpg' \
                   -name '*.jpeg' \
                   -name '*.md' \
                   -name .env \
                   -name .envs \
                   -name env \
                   -name envs \
                   -name .venv \
                   -name .venvs \
                   -name venv \
                   -name venvs \
                   -name .git \
                   -name .egg-info \
                   -name shunit2-2.1.6 \
                   -name vendor \
                   -name __pycache__ \
                   -name node_modules \
                   -path "*/$bower_components/*" \
                   -path '*/target/delombok/*' \
                   -path '*/build/lib/*' \
                   -path '*/js/generated/coverage/*' \
                    \) -prune -or \
                    -type f -print 2>/dev/null || echo '')
  fi

  if [ "$network_filter_o" != "" ];
  then
      network=$(echo "$network" | grep -e "$network_filter_o/*")
  fi
  if [ "$prefix_o" != "" ];
  then
      network=$(echo "$network" | awk "{print \"$prefix_o/\"\$0}")
  fi
fi

upload_file=$(mktemp /tmp/codecov.XXXXXX)
adjustments_file=$(mktemp /tmp/codecov.adjustments.XXXXXX)

# shellcheck disable=2329
cleanup() {
    # shellcheck disable=2317
    rm -f "$upload_file" "$adjustments_file" "$upload_file.gz"
}

trap cleanup INT ABRT TERM


if [ "$env" != "" ];
then
  inc_env=""
  say "${e}==>${x} Appending build variables"
  for varname in $(echo "$env" | tr ',' ' ')
  do
    if [ "$varname" != "" ];
    then
      say "    ${g}+${x} $varname"
      inc_env="${inc_env}${varname}=$(eval echo "\$${varname}")
"
    fi
  done
  echo "$inc_env<<<<<< ENV" >> "$upload_file"
fi

# Append git file list
# write discovered yaml location
if [ "$direct_file_upload" = "" ];
then
  echo "$yaml" >> "$upload_file"
fi

if [ "$ft_network" == "1" ];
then
  i="woff|eot|otf"  # fonts
  i="$i|gif|png|jpg|jpeg|psd"  # images
  i="$i|ptt|pptx|numbers|pages|md|txt|xlsx|docx|doc|pdf|csv"  # docs
  i="$i|.gitignore"  # supporting docs

  if [ "$ft_html" != "1" ];
  then
    i="$i|html"
  fi

  if [ "$ft_yaml" != "1" ];
  then
    i="$i|yml|yaml"
  fi

  echo "$network" | grep -vwE "($i)$" >> "$upload_file"
fi
echo "<<<<<< network" >> "$upload_file"

if [ "$direct_file_upload" = "" ];
then
  fr=0
  say "${e}==>${x} Reading reports"
  while IFS='' read -r file;
  do
    # read the coverage file
    if [ "$(echo "$file" | tr -d ' ')" != '' ];
    then
      if [ -f "$file" ];
      then
        report_len=$(wc -c < "$file")
        if [ "$report_len" -ne 0 ];
        then
          say "    ${g}+${x} $file ${e}bytes=$(echo "$report_len" | tr -d ' ')${x}"
          # append to to upload
          _filename=$(basename "$file")
          if [ "${_filename##*.}" = 'gcov' ];
          then
            {
              echo "# path=$(echo "$file.reduced" | sed "s|^$git_root/||")";
              # get file name
              head -1 "$file";
            } >> "$upload_file"
            # 1. remove source code
            # 2. remove ending bracket lines
            # 3. remove whitespace
            # 4. remove contextual lines
            # 5. remove function names
            awk -F': *' '{print $1":"$2":"}' "$file" \
              | sed '\/: *} *$/d' \
              | sed 's/^ *//' \
              | sed '/^-/d' \
              | sed 's/^function.*/func/' >> "$upload_file"
          else
            {
              echo "# path=${file//^$git_root/||}";
              cat "$file";
            } >> "$upload_file"
          fi
          echo "<<<<<< EOF" >> "$upload_file"
          fr=1
          if [ "$clean" = "1" ];
          then
            rm "$file"
          fi
        else
          say "    ${r}-${x} Skipping empty file $file"
        fi
      else
        say "    ${r}-${x} file not found at $file"
      fi
    fi
  done <<< "$(echo -e "$files")"

  if [ "$fr" = "0" ];
  then
    say "${r}-->${x} No coverage data found."
    say "    Please visit ${b}http://docs.codecov.io/docs/supported-languages${x}"
    say "    search for your projects language to learn how to collect reports."
    exit ${exit_with};
  fi
else
  cp "$direct_file_upload" "$upload_file"
  if [ "$clean" = "1" ];
  then
    rm "$direct_file_upload"
  fi
fi

if [ "$ft_fix" = "1" ];
then
  say "${e}==>${x} Appending adjustments"
  say "    ${b}https://docs.codecov.io/docs/fixing-reports${x}"

  empty_line='^[[:space:]]*$'
  # //
  syntax_comment='^[[:space:]]*//.*'
  # /* or */
  syntax_comment_block='^[[:space:]]*(\/\*|\*\/)[[:space:]]*$'
  # { or }
  syntax_bracket='^[[:space:]]*[\{\}][[:space:]]*(//.*)?$'
  # [ or ]
  syntax_list='^[[:space:]]*[][][[:space:]]*(//.*)?$'
  # func ... {
  syntax_go_func='^[[:space:]]*[func].*[\{][[:space:]]*$'

  # shellcheck disable=SC2089
  skip_dirs="-not -path '*/$bower_components/*' \
             -not -path '*/node_modules/*'"

  cut_and_join() {
    awk 'BEGIN { FS=":" }
         $3 ~ /\/\*/ || $3 ~ /\*\// { print $0 ; next }
         $1!=key { if (key!="") print out ; key=$1 ; out=$1":"$2 ; next }
         { out=out","$2 }
         END { print out }' 2>/dev/null
  }

  if echo "$network" | grep -m1 '.kt$' 1>/dev/null;
  then
    # skip brackets and comments
    cd "$git_root" && \
      find . -type f \
             -name '*.kt' \
             -exec \
      grep -nIHE -e "$syntax_bracket" \
                 -e "$syntax_comment_block" {} \; \
      | cut_and_join \
      >> "$adjustments_file" \
      || echo ''

    # last line in file
    cd "$git_root" && \
      find . -type f \
             -name '*.kt' -exec \
      wc -l {} \; \
      | while read -r l; do echo "EOF: $l"; done \
      2>/dev/null \
      >> "$adjustments_file" \
      || echo ''
  fi

  if echo "$network" | grep -m1 '.go$' 1>/dev/null;
  then
    # skip empty lines, comments, and brackets
    cd "$git_root" && \
      find . -type f \
             -not -path '*/vendor/*' \
             -not -path '*/caches/*' \
             -name '*.go' \
             -exec \
      grep -nIHE \
           -e "$empty_line" \
           -e "$syntax_comment" \
           -e "$syntax_comment_block" \
           -e "$syntax_bracket" \
           -e "$syntax_go_func" \
           {} \; \
      | cut_and_join \
      >> "$adjustments_file" \
      || echo ''
  fi

  if echo "$network" | grep -m1 '.dart$' 1>/dev/null;
  then
    # skip brackets
    cd "$git_root" && \
      find . -type f \
             -name '*.dart' \
             -exec \
      grep -nIHE \
           -e "$syntax_bracket" \
           {} \; \
      | cut_and_join \
      >> "$adjustments_file" \
      || echo ''
  fi

  if echo "$network" | grep -m1 '.php$' 1>/dev/null;
  then
    # skip empty lines, comments, and brackets
    cd "$git_root" && \
      find . -type f \
             -not -path "*/vendor/*" \
             -name '*.php' \
             -exec \
      grep -nIHE \
           -e "$syntax_list" \
           -e "$syntax_bracket" \
           -e '^[[:space:]]*\);[[:space:]]*(//.*)?$' \
           {} \; \
      | cut_and_join \
      >> "$adjustments_file" \
      || echo ''
  fi

  if echo "$network" | grep -m1 '\(.c\.cpp\|.cxx\|.h\|.hpp\|.m\|.swift\|.vala\)$' 1>/dev/null;
  then
    # skip brackets
    # shellcheck disable=SC2086,SC2090
    cd "$git_root" && \
      find . -type f \
             $skip_dirs \
         \( \
           -name '*.c' \
           -or -name '*.cpp' \
           -or -name '*.cxx' \
           -or -name '*.h' \
           -or -name '*.hpp' \
           -or -name '*.m' \
           -or -name '*.swift' \
           -or -name '*.vala' \
         \) -exec \
      grep -nIHE \
           -e "$empty_line" \
           -e "$syntax_bracket" \
           -e '// LCOV_EXCL' \
           {} \; \
      | cut_and_join \
      >> "$adjustments_file" \
      || echo ''

    # skip brackets
    # shellcheck disable=SC2086,SC2090
    cd "$git_root" && \
      find . -type f \
             $skip_dirs \
         \( \
           -name '*.c' \
           -or -name '*.cpp' \
           -or -name '*.cxx' \
           -or -name '*.h' \
           -or -name '*.hpp' \
           -or -name '*.m' \
           -or -name '*.swift' \
           -or -name '*.vala' \
         \) -exec \
      grep -nIH '// LCOV_EXCL' \
           {} \; \
      >> "$adjustments_file" \
      || echo ''

  fi

  found=$(< "$adjustments_file" tr -d ' ')

  if [ "$found" != "" ];
  then
    say "    ${g}+${x} Found adjustments"
    {
      echo "# path=fixes";
      cat "$adjustments_file";
      echo "<<<<<< EOF";
    } >> "$upload_file"
    rm -rf "$adjustments_file"
  else
    say "    ${e}->${x} No adjustments found"
  fi
fi

if [ "$url_o" != "" ];
then
  url="$url_o"
fi

if [ "$dump" != "0" ];
then
  # trim whitespace from query
  say "    ${e}->${x} Dumping upload file (no upload)"
  echo "$url/upload/v4?$(echo "package=$package-$VERSION&token=$token&$query" | tr -d ' ')"
  cat "$upload_file"
else
  if [ "$save_to" != "" ];
  then
    say "${e}==>${x} Copying upload file to ${save_to}"
    mkdir -p "$(dirname "$save_to")"
    cp "$upload_file" "$save_to"
  fi

  say "${e}==>${x} Gzipping contents"
  gzip -nf9 "$upload_file"
  say "        $(du -h "$upload_file.gz")"

  query=$(echo "${query}" | tr -d ' ')
  say "${e}==>${x} Uploading reports"
  say "    ${e}url:${x} $url"
  say "    ${e}query:${x} $query"

  # Full query without token (to display on terminal output)
  queryNoToken=$(echo "package=$package-$VERSION&token=secret&$query" | tr -d ' ')
  # now add token to query
  query=$(echo "package=$package-$VERSION&token=$token&$query" | tr -d ' ')

  if [ "$ft_s3" = "1" ];
  then
    say "${e}->${x}  Pinging Codecov"
    say "$url/upload/v4?$queryNoToken"
    # shellcheck disable=SC2086,2090
    res=$(curl $curl_s -X POST $cacert \
          --retry 5 --retry-delay 2 --connect-timeout 2 \
          -H 'X-Reduced-Redundancy: false' \
          -H 'X-Content-Type: application/x-gzip' \
          -H 'Content-Length: 0' \
          --write-out "\n%{response_code}\n" \
          $curlargs \
          "$url/upload/v4?$query" || true)
    # a good reply is "https://codecov.io" + "\n" + "https://storage.googleapis.com/codecov/..."
    s3target=$(echo "$res" | sed -n 2p)
    status=$(tail -n1 <<< "$res")

    if [ "$status" = "200" ] && [ "$s3target" != "" ];
    then
      say "${e}->${x}  Uploading to"
      say "${s3target}"

      # shellcheck disable=SC2086
      s3=$(curl -fiX PUT \
          --data-binary @"$upload_file.gz" \
          -H 'Content-Type: application/x-gzip' \
          -H 'Content-Encoding: gzip' \
          $curlawsargs \
          "$s3target" || true)

      if [ "$s3" != "" ];
      then
        say "    ${g}->${x} Reports have been successfully queued for processing at ${b}$(echo "$res" | sed -n 1p)${x}"
        exit 0
      else
        say "    ${r}X>${x} Failed to upload"
      fi
    elif [ "$status" = "400" ];
    then
        # 400 Error
        say "${r}${res}${x}"
        exit ${exit_with}
    else
        say "${r}${res}${x}"
    fi
  fi

  say "${e}==>${x} Uploading to Codecov"

  # shellcheck disable=SC2086,2090
  res=$(curl -X POST $cacert \
        --data-binary @"$upload_file.gz" \
        --retry 5 --retry-delay 2 --connect-timeout 2 \
        -H 'Content-Type: text/plain' \
        -H 'Content-Encoding: gzip' \
        -H 'X-Content-Encoding: gzip' \
        -H 'Accept: text/plain' \
        $curlargs \
        "$url/upload/v2?$query&attempt=$i" || echo 'HTTP 500')
  # HTTP 200
  # http://....
  status=$(echo "$res" | head -1 | cut -d' ' -f2)
  if [ "$status" = "" ] || [ "$status" = "200" ];
  then
    say "    Reports have been successfully queued for processing at ${b}$(echo "$res" | head -2 | tail -1)${x}"
    exit 0
  else
    say "    ${g}${res}${x}"
    exit ${exit_with}
  fi

  # shellcheck disable=2317
  say "    ${r}X> Failed to upload coverage reports${x}"
fi

exit ${exit_with}
