1function refresh_docker_images {
2   # Arguments:
3   #   $1 - Path to top level Consul source
4   #   $2 - Which make target to invoke (optional)
5   #
6   # Return:
7   #   0 - success
8   #   * - failure
9
10   if ! test -d "$1"
11   then
12      err "ERROR: '$1' is not a directory. refresh_docker_images must be called with the path to the top level source as the first argument'"
13      return 1
14   fi
15
16   local sdir="$1"
17   local targets="$2"
18
19   test -n "${targets}" || targets="docker-images"
20
21   make -C "${sdir}" ${targets}
22   return $?
23}
24
25function build_ui {
26   # Arguments:
27   #   $1 - Path to the top level Consul source
28   #   $2 - The docker image to run the build within (optional)
29   #   $3 - Version override
30   #
31   # Returns:
32   #   0 - success
33   #   * - error
34   #
35   # Notes:
36   #   Use the GIT_COMMIT environment variable to pass off to the build
37   #   Use the GIT_COMMIT_YEAR environment variable to pass off to the build
38
39   if ! test -d "$1"
40   then
41      err "ERROR: '$1' is not a directory. build_ui must be called with the path to the top level source as the first argument'"
42      return 1
43   fi
44
45   local image_name=${UI_BUILD_CONTAINER_DEFAULT}
46   if test -n "$2"
47   then
48      image_name="$2"
49   fi
50
51   local sdir="$1"
52   local ui_dir="${1}/ui-v2"
53
54   # parse the version
55   version=$(parse_version "${sdir}")
56
57   if test -n "$3"
58   then
59      version="$3"
60   fi
61
62   local commit_hash="${GIT_COMMIT}"
63   if test -z "${commit_hash}"
64   then
65      commit_hash=$(git rev-parse --short HEAD)
66   fi
67
68   local commit_year="${GIT_COMMIT_YEAR}"
69   if test -z "${commit_year}"
70   then
71      commit_year=$(git show -s --format=%cd --date=format:%Y HEAD)
72   fi
73
74   local logo_type="${CONSUL_BINARY_TYPE}"
75   if test "$logo_type" != "oss"
76   then
77     logo_type="enterprise"
78   fi
79
80   # make sure we run within the ui dir
81   pushd ${ui_dir} > /dev/null
82
83   status "Creating the UI Build Container with image: ${image_name} and version '${version}'"
84   local container_id=$(docker create -it -e "CONSUL_GIT_SHA=${commit_hash}" -e "CONSUL_COPYRIGHT_YEAR=${commit_year}" -e "CONSUL_VERSION=${version}" -e "CONSUL_BINARY_TYPE=${CONSUL_BINARY_TYPE}" ${image_name})
85   local ret=$?
86   if test $ret -eq 0
87   then
88      status "Copying the source from '${ui_dir}' to /consul-src within the container"
89      (
90         tar -c $(ls -A | grep -v "^(node_modules\|dist\|tmp)") | docker cp - ${container_id}:/consul-src &&
91         status "Running build in container" && docker start -i ${container_id} &&
92         rm -rf ${1}/ui-v2/dist &&
93         status "Copying back artifacts" && docker cp ${container_id}:/consul-src/dist ${1}/ui-v2/dist
94      )
95      ret=$?
96      docker rm ${container_id} > /dev/null
97   fi
98
99   # Check the version is baked in correctly
100   if test ${ret} -eq 0
101   then
102      local ui_vers=$(ui_version "${1}/ui-v2/dist/index.html")
103      if test "${version}" != "${ui_vers}"
104      then
105         err "ERROR: UI version mismatch. Expecting: '${version}' found '${ui_vers}'"
106         ret=1
107      fi
108   fi
109
110   # Check the logo is baked in correctly
111   if test ${ret} -eq 0
112   then
113     local ui_logo_type=$(ui_logo_type "${1}/ui-v2/dist/index.html")
114     if test "${logo_type}" != "${ui_logo_type}"
115     then
116       err "ERROR: UI logo type mismatch. Expecting: '${logo_type}' found '${ui_logo_type}'"
117       ret=1
118     fi
119   fi
120
121   # Copy UI over ready to be packaged into the binary
122   if test ${ret} -eq 0
123   then
124      rm -rf ${1}/pkg/web_ui
125      mkdir -p ${1}/pkg
126      cp -r ${1}/ui-v2/dist ${1}/pkg/web_ui
127   fi
128
129   popd > /dev/null
130   return $ret
131}
132
133function build_assetfs {
134   # Arguments:
135   #   $1 - Path to the top level Consul source
136   #   $2 - The docker image to run the build within (optional)
137   #
138   # Returns:
139   #   0 - success
140   #   * - error
141   #
142   # Note:
143   #   The GIT_COMMIT and GIT_DIRTY environment variables will be used if present
144
145   if ! test -d "$1"
146   then
147      err "ERROR: '$1' is not a directory. build_assetfs must be called with the path to the top level source as the first argument'"
148      return 1
149   fi
150
151   local sdir="$1"
152   local image_name=${GO_BUILD_CONTAINER_DEFAULT}
153   if test -n "$2"
154   then
155      image_name="$2"
156   fi
157
158   pushd ${sdir} > /dev/null
159   status "Creating the Go Build Container with image: ${image_name}"
160   local container_id=$(docker create -it -e GIT_COMMIT=${GIT_COMMIT} -e GIT_DIRTY=${GIT_DIRTY} ${image_name} make static-assets ASSETFS_PATH=bindata_assetfs.go)
161   local ret=$?
162   if test $ret -eq 0
163   then
164      status "Copying the sources from '${sdir}/(pkg/web_ui|GNUmakefile)' to /consul/pkg"
165      (
166         tar -c pkg/web_ui GNUmakefile | docker cp - ${container_id}:/consul &&
167         status "Running build in container" && docker start -i ${container_id} &&
168         status "Copying back artifacts" && docker cp ${container_id}:/consul/bindata_assetfs.go ${sdir}/agent/bindata_assetfs.go
169      )
170      ret=$?
171      docker rm ${container_id} > /dev/null
172   fi
173   popd >/dev/null
174   return $ret
175}
176
177function build_consul_post {
178   # Arguments
179   #   $1 - Path to the top level Consul source
180   #   $2 - Subdirectory under pkg/bin (Optional)
181   #
182   # Returns:
183   #   0 - success
184   #   * - error
185   #
186   # Notes:
187   #   pkg/bin is where to place binary packages
188   #   pkg.bin.new is where the just built binaries are located
189   #   bin is where to place the local systems versions
190
191   if ! test -d "$1"
192   then
193      err "ERROR: '$1' is not a directory. build_consul_post must be called with the path to the top level source as the first argument'"
194      return 1
195   fi
196
197   local sdir="$1"
198
199   local extra_dir_name="$2"
200   local extra_dir=""
201
202   if test -n "${extra_dir_name}"
203   then
204      extra_dir="${extra_dir_name}/"
205   fi
206
207   pushd "${sdir}" > /dev/null
208
209   # recreate the pkg dir
210   rm -r pkg/bin/${extra_dir}* 2> /dev/null
211   mkdir -p pkg/bin/${extra_dir} 2> /dev/null
212
213   # move all files in pkg.new into pkg
214   cp -r pkg.bin.new/${extra_dir}* pkg/bin/${extra_dir}
215   rm -r pkg.bin.new
216
217   DEV_PLATFORM="./pkg/bin/${extra_dir}$(go env GOOS)_$(go env GOARCH)"
218   for F in $(find ${DEV_PLATFORM} -mindepth 1 -maxdepth 1 -type f 2>/dev/null)
219   do
220      # recreate the bin dir
221      rm -r bin/* 2> /dev/null
222      mkdir -p bin 2> /dev/null
223
224      cp ${F} bin/
225      cp ${F} ${MAIN_GOPATH}/bin
226   done
227
228   popd > /dev/null
229
230   return 0
231}
232
233function build_consul {
234   # Arguments:
235   #   $1 - Path to the top level Consul source
236   #   $2 - Subdirectory to put binaries in under pkg/bin (optional - must specify if needing to specify the docker image)
237   #   $3 - The docker image to run the build within (optional)
238   #
239   # Returns:
240   #   0 - success
241   #   * - error
242   #
243   # Note:
244   #   The GOLDFLAGS and GOTAGS environment variables will be used if set
245   #   If the CONSUL_DEV environment var is truthy only the local platform/architecture is built.
246   #   If the XC_OS or the XC_ARCH environment vars are present then only those platforms/architectures
247   #   will be built. Otherwise all supported platform/architectures are built
248
249   if ! test -d "$1"
250   then
251      err "ERROR: '$1' is not a directory. build_consul must be called with the path to the top level source as the first argument'"
252      return 1
253   fi
254
255   local sdir="$1"
256   local extra_dir_name="$2"
257   local extra_dir=""
258   local image_name=${GO_BUILD_CONTAINER_DEFAULT}
259   if test -n "$3"
260   then
261      image_name="$3"
262   fi
263
264   pushd ${sdir} > /dev/null
265   if is_set "${CONSUL_DEV}"
266   then
267      if test -z "${XC_OS}"
268      then
269         XC_OS=$(go env GOOS)
270      fi
271
272      if test -z "${XC_ARCH}"
273      then
274         XC_ARCH=$(go env GOARCH)
275      fi
276   fi
277   XC_OS=${XC_OS:-"solaris darwin freebsd linux windows"}
278   XC_ARCH=${XC_ARCH:-"386 amd64 arm arm64"}
279
280   if test -n "${extra_dir_name}"
281   then
282      extra_dir="${extra_dir_name}/"
283   fi
284
285   # figure out if the compiler supports modules
286   local use_modules=0
287   if go help modules >/dev/null 2>&1
288   then
289      use_modules=1
290   elif test -n "${GO111MODULE}"
291   then
292      use_modules=1
293   fi
294
295   local volume_mount=
296   if is_set "${use_modules}"
297   then
298      status "Ensuring Go modules are up to date"
299      # ensure our go module cache is correct
300      go_mod_assert || return 1
301      # setup to bind mount our hosts module cache into the container
302      volume_mount="--mount=type=bind,source=${MAIN_GOPATH}/pkg/mod,target=/go/pkg/mod"
303   fi
304
305   status "Creating the Go Build Container with image: ${image_name}"
306   local container_id=$(docker create -it \
307      ${volume_mount} \
308      -e CGO_ENABLED=0 \
309      -e GOLDFLAGS="${GOLDFLAGS}" \
310      -e GOTAGS="${GOTAGS}" \
311      ${image_name} \
312      ./build-support/scripts/build-local.sh -o "${XC_OS}" -a "${XC_ARCH}")
313   ret=$?
314
315   if test $ret -eq 0
316   then
317      status "Copying the source from '${sdir}' to /consul"
318      (
319         tar -c $(ls | grep -v "^(ui\|ui-v2\|website\|bin\|pkg\|.git)") | docker cp - ${container_id}:/consul &&
320         status "Running build in container" &&
321         docker start -i ${container_id} &&
322         status "Copying back artifacts" &&
323         docker cp ${container_id}:/consul/pkg/bin pkg.bin.new
324      )
325      ret=$?
326      docker rm ${container_id} > /dev/null
327
328      if test $ret -eq 0
329      then
330         build_consul_post "${sdir}" "${extra_dir_name}"
331         ret=$?
332      else
333         rm -r pkg.bin.new 2> /dev/null
334      fi
335   fi
336   popd > /dev/null
337   return $ret
338}
339
340function build_consul_local {
341   # Arguments:
342   #   $1 - Path to the top level Consul source
343   #   $2 - Space separated string of OSes to build. If empty will use env vars for determination.
344   #   $3 - Space separated string of architectures to build. If empty will use env vars for determination.
345   #   $4 - Subdirectory to put binaries in under pkg/bin (optional)
346   #
347   # Returns:
348   #   0 - success
349   #   * - error
350   #
351   # Note:
352   #   The GOLDFLAGS and GOTAGS environment variables will be used if set
353   #   If the CONSUL_DEV environment var is truthy only the local platform/architecture is built.
354   #   If the XC_OS or the XC_ARCH environment vars are present then only those platforms/architectures
355   #   will be built. Otherwise all supported platform/architectures are built
356   #   The GOXPARALLEL environment variable is used if set
357
358   if ! test -d "$1"
359   then
360      err "ERROR: '$1' is not a directory. build_consul must be called with the path to the top level source as the first argument'"
361      return 1
362   fi
363
364   local sdir="$1"
365   local build_os="$2"
366   local build_arch="$3"
367   local extra_dir_name="$4"
368   local extra_dir=""
369
370   if test -n "${extra_dir_name}"
371   then
372      extra_dir="${extra_dir_name}/"
373   fi
374
375   pushd ${sdir} > /dev/null
376   if is_set "${CONSUL_DEV}"
377   then
378      if test -z "${XC_OS}"
379      then
380         XC_OS=$(go env GOOS)
381      fi
382
383      if test -z "${XC_ARCH}"
384      then
385         XC_ARCH=$(go env GOARCH)
386      fi
387   fi
388   XC_OS=${XC_OS:-"solaris darwin freebsd linux windows"}
389   XC_ARCH=${XC_ARCH:-"386 amd64 arm arm64"}
390
391   if test -z "${build_os}"
392   then
393      build_os="${XC_OS}"
394   fi
395
396   if test -z "${build_arch}"
397   then
398      build_arch="${XC_ARCH}"
399   fi
400
401   status_stage "==> Building Consul - OSes: ${build_os}, Architectures: ${build_arch}"
402   mkdir pkg.bin.new 2> /dev/null
403
404   status "Building sequentially with go install"
405   for os in ${build_os}
406   do
407      for arch in ${build_arch}
408      do
409         outdir="pkg.bin.new/${extra_dir}${os}_${arch}"
410         osarch="${os}/${arch}"
411
412         case "${os}" in
413            "darwin" )
414               # Do not build ARM binaries for macOS
415               if test "${arch}" == "arm" -o "${arch}" == "arm64"
416               then
417                  continue
418               fi
419               ;;
420            "windows" )
421               # Do not build ARM binaries for Windows
422               if test "${arch}" == "arm" -o "${arch}" == "arm64"
423               then
424                  continue
425               fi
426               ;;
427            "freebsd" )
428               # Do not build ARM binaries for FreeBSD
429               if test "${arch}" == "arm" -o "${arch}" == "arm64"
430               then
431                  continue
432               fi
433               ;;
434            "solaris" )
435               # Only build amd64 for Solaris
436               if test "${arch}" != "amd64"
437               then
438                  continue
439               fi
440               ;;
441            "linux" )
442               # build all the binaries for Linux
443               ;;
444            *)
445               continue
446            ;;
447         esac
448
449         echo "--->   ${osarch}"
450
451         mkdir -p "${outdir}"
452         GOBIN_EXTRA=""
453         if test "${os}" != "$(go env GOHOSTOS)" -o "${arch}" != "$(go env GOHOSTARCH)"
454         then
455            GOBIN_EXTRA="${os}_${arch}/"
456         fi
457         binname="consul"
458         if [ $os == "windows" ];then
459               binname="consul.exe"
460         fi
461         debug_run env CGO_ENABLED=0 GOOS=${os} GOARCH=${arch} go install -ldflags "${GOLDFLAGS}" -tags "${GOTAGS}" && cp "${MAIN_GOPATH}/bin/${GOBIN_EXTRA}${binname}" "${outdir}/${binname}"
462         if test $? -ne 0
463         then
464            err "ERROR: Failed to build Consul for ${osarch}"
465            rm -r pkg.bin.new
466            return 1
467         fi
468      done
469   done
470
471   build_consul_post "${sdir}" "${extra_dir_name}"
472   if test $? -ne 0
473   then
474      err "ERROR: Failed postprocessing Consul binaries"
475      return 1
476   fi
477   return 0
478}
479