github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/build/builder.sh (about)

     1  #!/usr/bin/env bash
     2  
     3  set -euo pipefail
     4  
     5  image=cockroachdb/builder
     6  version=20200421-180956
     7  
     8  function init() {
     9    docker build --tag="${image}" "$(dirname "${0}")/builder"
    10  }
    11  
    12  if [ "${1-}" = "pull" ]; then
    13    docker pull "${image}:${version}"
    14    exit 0
    15  fi
    16  
    17  if [ "${1-}" = "init" ]; then
    18    init
    19    exit 0
    20  fi
    21  
    22  if [ "${1-}" = "push" ]; then
    23    init
    24    tag=$(date +%Y%m%d-%H%M%S)
    25    docker tag "${image}" "${image}:${tag}"
    26    docker push "${image}:${tag}"
    27    exit 0
    28  fi
    29  
    30  if [ "${1-}" = "version" ]; then
    31    echo "${version}"
    32    exit 0
    33  fi
    34  
    35  cached_volume_mode=
    36  delegated_volume_mode=
    37  if [ "$(uname)" = "Darwin" ]; then
    38    # This boosts filesystem performance on macOS at the cost of some consistency
    39    # guarantees that are usually unnecessary in development.
    40    # For details: https://docs.docker.com/docker-for-mac/osxfs-caching/
    41    delegated_volume_mode=:delegated
    42    cached_volume_mode=:cached
    43  fi
    44  
    45  # We don't want this to emit -json output.
    46  GOPATH=$(GOFLAGS=; go env GOPATH)
    47  gopath0=${GOPATH%%:*}
    48  gocache=${GOCACHEPATH-$gopath0}
    49  
    50  if [ -t 0 ]; then
    51    tty=--tty
    52  fi
    53  
    54  # Absolute path to the toplevel cockroach directory.
    55  cockroach_toplevel=$(dirname "$(cd "$(dirname "${0}")"; pwd)")
    56  
    57  # Ensure the artifact sub-directory always exists and redirect
    58  # temporary file creation to it, so that CI always picks up temp files
    59  # (including stray log files).
    60  mkdir -p "${cockroach_toplevel}"/artifacts
    61  export TMPDIR=$cockroach_toplevel/artifacts
    62  
    63  # We'll mount a fresh directory owned by the invoking user as the container
    64  # user's home directory because various utilities (e.g. bash writing to
    65  # .bash_history) need to be able to write to there.
    66  container_home=/home/roach
    67  host_home=${cockroach_toplevel}/build/builder_home
    68  mkdir -p "${host_home}"
    69  
    70  # Since we're mounting both /root and its subdirectories in our container,
    71  # Docker will create the subdirectories on the host side under the directory
    72  # that we're mounting as /root, as the root user. This creates problems for CI
    73  # processes trying to clean up the working directory, so we create them here
    74  # as the invoking user to avoid root-owned paths.
    75  #
    76  # Note: this only happens on Linux. On Docker for Mac, the directories are
    77  # still created, but they're owned by the invoking user already. See
    78  # https://github.com/docker/docker/issues/26051.
    79  mkdir -p "${host_home}"/.yarn-cache
    80  
    81  # Run our build container with a set of volumes mounted that will
    82  # allow the container to store persistent build data on the host
    83  # computer.
    84  #
    85  # This script supports both circleci and development hosts, so it must
    86  # support cases where the architecture inside the container is
    87  # different from that outside the container. We can map /src/ directly
    88  # into the container because it is architecture-independent. We then
    89  # map certain subdirectories of ${GOPATH}/pkg into both ${GOPATH}/pkg
    90  # and ${GOROOT}/pkg. The ${GOROOT} mapping is needed so they can be
    91  # used to cache builds of the standard library. /bin/ is mapped
    92  # separately to avoid clobbering the host's binaries. Note that the
    93  # path used for the /bin/ mapping is also used in the defaultBinary
    94  # function of localcluster.go.
    95  #
    96  # We always map the cockroach source directory that contains this script into
    97  # the container's $GOPATH/src. By default, we also mount the host's $GOPATH/src
    98  # directory to the container's $GOPATH/src. That behavior can be turned off by
    99  # setting BUILDER_HIDE_GOPATH_SRC to 1, which results in only the cockroach
   100  # source code (and its vendored dependencies) being available within the
   101  # container. This setting is useful to prevent missing vendored dependencies
   102  # from being accidentally resolved to the hosts's copy of those dependencies.
   103  
   104  # Ensure that all directories to which the container must be able to write are
   105  # created as the invoking user. Docker would otherwise create them when
   106  # mounting, but that would deny write access to the invoking user since docker
   107  # runs as root.
   108  
   109  vols=
   110  # It would be cool to interact with Docker from inside the builder, but the
   111  # socket is owned by root, and our unpriviledged user can't access it. If we
   112  # could make this work, we could run our acceptance tests from inside the
   113  # builder, which would be cleaner and simpler than what we do now (which is to
   114  # build static binaries in the container and then run them on the host).
   115  #
   116  # vols="${vols} --volume=/var/run/docker.sock:/var/run/docker.sock"
   117  vols="${vols} --volume=${host_home}:${container_home}${cached_volume_mode}"
   118  
   119  mkdir -p "${HOME}"/.yarn-cache
   120  vols="${vols} --volume=${HOME}/.yarn-cache:${container_home}/.yarn-cache${cached_volume_mode}"
   121  
   122  # If we're running in an environment that's using git alternates, like TeamCity,
   123  # we must mount the path to the real git objects for git to work in the container.
   124  # alternates_file=${cockroach_toplevel}/.git/objects/info/alternates
   125  # if test -e "${alternates_file}"; then
   126  #   alternates_path=$(cat "${alternates_file}")
   127  #   vols="${vols} --volume=${alternates_path}:${alternates_path}${cached_volume_mode}"
   128  # fi
   129  
   130  teamcity_alternates="/home/agent/system/git/"
   131  if test -d "${teamcity_alternates}"; then
   132      vols="${vols} --volume=${teamcity_alternates}:${teamcity_alternates}${cached_volume_mode}"
   133  fi
   134  
   135  if [ "${BUILDER_HIDE_GOPATH_SRC:-}" != "1" ]; then
   136    vols="${vols} --volume=${gopath0}/src:/go/src${cached_volume_mode}"
   137  fi
   138  vols="${vols} --volume=${cockroach_toplevel}:/go/src/github.com/cockroachdb/cockroach${cached_volume_mode}"
   139  
   140  # If ${cockroach_toplevel}/bin doesn't exist on the host, Docker creates it as
   141  # root unless it already exists. Create it first as the invoking user.
   142  # (This is a bug in the Docker daemon that only occurs when bind-mounted volumes
   143  # are nested, as they are here.)
   144  mkdir -p "${cockroach_toplevel}"/bin{.docker_amd64,}
   145  vols="${vols} --volume=${cockroach_toplevel}/bin.docker_amd64:/go/src/github.com/cockroachdb/cockroach/bin${delegated_volume_mode}"
   146  mkdir -p "${cockroach_toplevel}"/lib{.docker_amd64,}
   147  vols="${vols} --volume=${cockroach_toplevel}/lib.docker_amd64:/go/src/github.com/cockroachdb/cockroach/lib${delegated_volume_mode}"
   148  
   149  mkdir -p "${gocache}"/docker/bin
   150  vols="${vols} --volume=${gocache}/docker/bin:/go/bin${delegated_volume_mode}"
   151  mkdir -p "${gocache}"/docker/native
   152  vols="${vols} --volume=${gocache}/docker/native:/go/native${delegated_volume_mode}"
   153  mkdir -p "${gocache}"/docker/pkg
   154  vols="${vols} --volume=${gocache}/docker/pkg:/go/pkg${delegated_volume_mode}"
   155  
   156  # Attempt to run in the container with the same UID/GID as we have on the host,
   157  # as this results in the correct permissions on files created in the shared
   158  # volumes. This isn't always possible, however, as IDs less than 100 are
   159  # reserved by Debian, and IDs in the low 100s are dynamically assigned to
   160  # various system users and groups. To be safe, if we see a UID/GID less than
   161  # 500, promote it to 501. This is notably necessary on macOS Lion and later,
   162  # where administrator accounts are created with a GID of 20. This solution is
   163  # not foolproof, but it works well in practice.
   164  uid=$(id -u)
   165  gid=$(id -g)
   166  [ "$uid" -lt 500 ] && uid=501
   167  [ "$gid" -lt 500 ] && gid=$uid
   168  
   169  # temporary disable immediate exit on failure, so that we could catch
   170  # the status of "docker run"
   171  set +e
   172  
   173  # -i causes some commands (including `git diff`) to attempt to use
   174  # a pager, so we override $PAGER to disable.
   175  
   176  # shellcheck disable=SC2086
   177  docker run --init --privileged -i ${tty-} --rm \
   178    -u "$uid:$gid" \
   179    ${vols} \
   180    --workdir="/go/src/github.com/cockroachdb/cockroach" \
   181    --env="TMPDIR=/go/src/github.com/cockroachdb/cockroach/artifacts" \
   182    --env="PAGER=cat" \
   183    --env="GOTRACEBACK=${GOTRACEBACK-all}" \
   184    --env="TZ=America/New_York" \
   185    --env=COCKROACH_BUILDER_CCACHE \
   186    --env=COCKROACH_BUILDER_CCACHE_MAXSIZE \
   187    "${image}:${version}" "$@"
   188  
   189  # Build container needs to have at least 4GB of RAM available to compile the project
   190  # successfully, which is not true in some cases (i.e. Docker for MacOS by default).
   191  # Check if it might be the case if "docker run" failed
   192  res=$?
   193  set -e
   194  
   195  if test $res -ne 0 -a \( ${1-x} = "make" -o ${1-x} = "xmkrelease" \) ; then
   196     ram=$(docker run -i --rm \
   197           -u "$uid:$gid" \
   198           "${image}:${version}" awk '/MemTotal/{print $2}' /proc/meminfo)
   199  
   200     if test $ram -lt 4000000; then
   201        ram_gb=`printf "%.2f" $(echo $ram/1024/1024 | bc -l)`
   202  
   203        ram_message="Note: if the build seems to terminate for unclear reasons, \
   204                  note that your container limits RAM to ${ram_gb}GB. This may be \
   205                  the cause of the failure. Try increasing the limit to 4GB or above."
   206  
   207        echo $ram_message >&2   # be mindful of printing to stderr, not stdout
   208     fi
   209  fi
   210  
   211  exit $res