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