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