]> git.lizzy.rs Git - rust.git/blob - src/ci/docker/run.sh
b1dacf79d269598d593a3429f567c49b471e549c
[rust.git] / src / ci / docker / run.sh
1 #!/usr/bin/env bash
2
3 set -e
4
5 export MSYS_NO_PATHCONV=1
6
7 script=`cd $(dirname $0) && pwd`/`basename $0`
8
9 image=""
10 dev=0
11
12 while [[ $# -gt 0 ]]
13 do
14   case "$1" in
15     --dev)
16       dev=1
17       ;;
18     *)
19       if [ -n "$image" ]
20       then
21         echo "expected single argument for the image name"
22         exit 1
23       fi
24       image="$1"
25       ;;
26   esac
27   shift
28 done
29
30 script_dir="`dirname $script`"
31 docker_dir="${script_dir}/host-$(uname -m)"
32 ci_dir="`dirname $script_dir`"
33 src_dir="`dirname $ci_dir`"
34 root_dir="`dirname $src_dir`"
35
36 objdir=$root_dir/obj
37 dist=$objdir/build/dist
38
39 source "$ci_dir/shared.sh"
40
41 CACHE_DOMAIN="${CACHE_DOMAIN:-ci-caches.rust-lang.org}"
42
43 if [ -f "$docker_dir/$image/Dockerfile" ]; then
44     if [ "$CI" != "" ]; then
45       hash_key=/tmp/.docker-hash-key.txt
46       rm -f "${hash_key}"
47       echo $image >> $hash_key
48
49       cat "$docker_dir/$image/Dockerfile" >> $hash_key
50       # Look for all source files involves in the COPY command
51       copied_files=/tmp/.docker-copied-files.txt
52       rm -f "$copied_files"
53       for i in $(sed -n -e 's/^COPY \(.*\) .*$/\1/p' "$docker_dir/$image/Dockerfile"); do
54         # List the file names
55         find "$script_dir/$i" -type f >> $copied_files
56       done
57       # Sort the file names and cat the content into the hash key
58       sort $copied_files | xargs cat >> $hash_key
59
60       # Include the architecture in the hash key, since our Linux CI does not
61       # only run in x86_64 machines.
62       uname -m >> $hash_key
63
64       docker --version >> $hash_key
65       cksum=$(sha512sum $hash_key | \
66         awk '{print $1}')
67
68       url="https://$CACHE_DOMAIN/docker/$cksum"
69
70       echo "Attempting to download $url"
71       rm -f /tmp/rustci_docker_cache
72       set +e
73       retry curl --max-time 600 -y 30 -Y 10 --connect-timeout 30 -f -L -C - \
74         -o /tmp/rustci_docker_cache "$url"
75       echo "Loading images into docker"
76       # docker load sometimes hangs in the CI, so time out after 10 minutes with TERM,
77       # KILL after 12 minutes
78       loaded_images=$(/usr/bin/timeout -k 720 600 docker load -i /tmp/rustci_docker_cache \
79         | sed 's/.* sha/sha/')
80       set -e
81       echo "Downloaded containers:\n$loaded_images"
82     fi
83
84     dockerfile="$docker_dir/$image/Dockerfile"
85     if [ -x /usr/bin/cygpath ]; then
86         context="`cygpath -w $script_dir`"
87         dockerfile="`cygpath -w $dockerfile`"
88     else
89         context="$script_dir"
90     fi
91     retry docker \
92       build \
93       --rm \
94       -t rust-ci \
95       -f "$dockerfile" \
96       "$context"
97
98     if [ "$CI" != "" ]; then
99       s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
100       upload="aws s3 cp - $s3url"
101       digest=$(docker inspect rust-ci --format '{{.Id}}')
102       echo "Built container $digest"
103       if ! grep -q "$digest" <(echo "$loaded_images"); then
104         echo "Uploading finished image to $url"
105         set +e
106         docker history -q rust-ci | \
107           grep -v missing | \
108           xargs docker save | \
109           gzip | \
110           $upload
111         set -e
112       else
113         echo "Looks like docker image is the same as before, not uploading"
114       fi
115       # Record the container image for reuse, e.g. by rustup.rs builds
116       info="$dist/image-$image.txt"
117       mkdir -p "$dist"
118       echo "$url" >"$info"
119       echo "$digest" >>"$info"
120     fi
121 elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
122     if isCI; then
123         echo Cannot run disabled images on CI!
124         exit 1
125     fi
126     # Transform changes the context of disabled Dockerfiles to match the enabled ones
127     tar --transform 's#disabled/#./#' -C $script_dir -c . | docker \
128       build \
129       --rm \
130       -t rust-ci \
131       -f "host-$(uname -m)/$image/Dockerfile" \
132       -
133 else
134     echo Invalid image: $image
135
136     # Check whether the image exists for other architectures
137     for arch_dir in "${script_dir}"/host-*; do
138         # Avoid checking non-directories and the current host architecture directory
139         if ! [[ -d "${arch_dir}" ]]; then
140             continue
141         fi
142         if [[ "${arch_dir}" = "${docker_dir}" ]]; then
143             continue
144         fi
145
146         arch_name="$(basename "${arch_dir}" | sed 's/^host-//')"
147         if [[ -f "${arch_dir}/${image}/Dockerfile" ]]; then
148             echo "Note: the image exists for the ${arch_name} host architecture"
149         elif [[ -f "${arch_dir}/disabled/${image}/Dockerfile" ]]; then
150             echo "Note: the disabled image exists for the ${arch_name} host architecture"
151         else
152             continue
153         fi
154         echo "Note: the current host architecture is $(uname -m)"
155     done
156
157     exit 1
158 fi
159
160 mkdir -p $HOME/.cargo
161 mkdir -p $objdir/tmp
162 mkdir -p $objdir/cores
163 mkdir -p /tmp/toolstate
164
165 args=
166 if [ "$SCCACHE_BUCKET" != "" ]; then
167     args="$args --env SCCACHE_BUCKET"
168     args="$args --env SCCACHE_REGION"
169     args="$args --env AWS_ACCESS_KEY_ID"
170     args="$args --env AWS_SECRET_ACCESS_KEY"
171 else
172     mkdir -p $HOME/.cache/sccache
173     args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
174 fi
175
176 # Run containers as privileged as it should give them access to some more
177 # syscalls such as ptrace and whatnot. In the upgrade to LLVM 5.0 it was
178 # discovered that the leak sanitizer apparently needs these syscalls nowadays so
179 # we'll need `--privileged` for at least the `x86_64-gnu` builder, so this just
180 # goes ahead and sets it for all builders.
181 args="$args --privileged"
182
183 # Things get a little weird if this script is already running in a docker
184 # container. If we're already in a docker container then we assume it's set up
185 # to do docker-in-docker where we have access to a working `docker` command.
186 #
187 # If this is the case (we check via the presence of `/.dockerenv`)
188 # then we can't actually use the `--volume` argument. Typically we use
189 # `--volume` to efficiently share the build and source directory between this
190 # script and the container we're about to spawn. If we're inside docker already
191 # though the `--volume` argument maps the *host's* folder to the container we're
192 # about to spawn, when in fact we want the folder in this container itself. To
193 # work around this we use a recipe cribbed from
194 # https://circleci.com/docs/2.0/building-docker-images/#mounting-folders to
195 # create a temporary container with a volume. We then copy the entire source
196 # directory into this container, and then use that copy in the container we're
197 # about to spawn. Finally after the build finishes we re-extract the object
198 # directory.
199 #
200 # Note that none of this is necessary if we're *not* in a docker-in-docker
201 # scenario. If this script is run on a bare metal host then we share a bunch of
202 # data directories to share as much data as possible. Note that we also use
203 # `LOCAL_USER_ID` (recognized in `src/ci/run.sh`) to ensure that files are all
204 # read/written as the same user as the bare-metal user.
205 if [ -f /.dockerenv ]; then
206   docker create -v /checkout --name checkout alpine:3.4 /bin/true
207   docker cp . checkout:/checkout
208   args="$args --volumes-from checkout"
209 else
210   args="$args --volume $root_dir:/checkout:ro"
211   args="$args --volume $objdir:/checkout/obj"
212   args="$args --volume $HOME/.cargo:/cargo"
213   args="$args --volume $HOME/rustsrc:$HOME/rustsrc"
214   args="$args --volume /tmp/toolstate:/tmp/toolstate"
215   args="$args --env LOCAL_USER_ID=`id -u`"
216 fi
217
218 if [ "$dev" = "1" ]
219 then
220   # Interactive + TTY
221   args="$args -it"
222   command="/bin/bash"
223 else
224   command="/checkout/src/ci/run.sh"
225 fi
226
227 if [ "$CI" != "" ]; then
228   # Get some needed information for $BASE_COMMIT
229   #
230   # This command gets the last merge commit which we'll use as base to list
231   # deleted files since then.
232   BASE_COMMIT="$(git log --author=bors@rust-lang.org -n 2 --pretty=format:%H | tail -n 1)"
233 else
234   BASE_COMMIT=""
235 fi
236
237 docker \
238   run \
239   --workdir /checkout/obj \
240   --env SRC=/checkout \
241   $args \
242   --env CARGO_HOME=/cargo \
243   --env DEPLOY \
244   --env DEPLOY_ALT \
245   --env CI \
246   --env TF_BUILD \
247   --env BUILD_SOURCEBRANCHNAME \
248   --env GITHUB_ACTIONS \
249   --env GITHUB_REF \
250   --env TOOLSTATE_REPO_ACCESS_TOKEN \
251   --env TOOLSTATE_REPO \
252   --env TOOLSTATE_PUBLISH \
253   --env RUST_CI_OVERRIDE_RELEASE_CHANNEL \
254   --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \
255   --env BASE_COMMIT="$BASE_COMMIT" \
256   --init \
257   --rm \
258   rust-ci \
259   $command
260
261 if [ -f /.dockerenv ]; then
262   rm -rf $objdir
263   docker cp checkout:/checkout/obj $objdir
264 fi