d2/ci/release/build.sh
2023-02-09 19:50:18 -08:00

301 lines
8.2 KiB
Bash
Executable file

#!/bin/sh
set -eu
if [ ! -e "$(dirname "$0")/../../ci/sub/.git" ]; then
set -x
git submodule update --init
set +x
fi
. "$(dirname "$0")/../../ci/sub/lib.sh"
cd -- "$(dirname "$0")/../.."
help() {
cat <<EOF
usage: $0 [--rebuild] [--local] [--dry-run] [--run=regex] [--host-only] [--lockfile-force]
[--install] [--uninstall]
$0 builds D2 release archives into ./ci/release/build/<version>/d2-<VERSION>-<OS>-<ARCH>.tar.gz
The version is detected via git describe which will use the git tag for the current
commit if available.
Flags:
--rebuild
By default build.sh will avoid rebuilding finished assets if they already exist but if you
changed something and need to force rebuild, use this flag.
--local
By default build.sh uses \$CI_D2_LINUX_AMD64, \$CI_D2_LINUX_ARM64,
\$CI_D2_MACOS_AMD64 and \$CI_D2_MACOS_ARM64 to build the release
archives. It's required for now due to the following issue:
https://github.com/terrastruct/d2/issues/31
With --local, build.sh will cross compile locally. warning: This is only for testing
purposes, do not use in production!
--host-only
Use to build the release archive for the host OS-ARCH only. All logging is done to stderr
so in a script you can read from stdout to get the path to the release archive.
--run=regex
Use to run only the OS-ARCH jobs that match the given regex. e.g. --run=linux only runs
the linux jobs. --run=linux-amd64 only runs the linux-amd64 job.
--version vX.X.X
Use to overwrite the version detected from git.
--lockfile-force
Forcefully take ownership of remote builder lockfiles.
--install
Ensure a release using --host-only and install it.
--uninstall
Ensure a release using --host-only and uninstall it.
--push-docker
Push the built docker image. Unfortunately dockerx requires the multi-arch images be
pushed if required in the same invocation as build. dockerx cannot load multi-arch
images into the daemon for push later. It's not slow though to use --push-docker after
building the image as nearly all artifacts are cached.
Automatically set if called from release.sh
--latest-docker
Mark the built image with the latest tag. Automatically set if called from release.sh
EOF
}
main() {
while flag_parse "$@"; do
case "$FLAG" in
h|help)
help
return 0
;;
rebuild)
flag_noarg && shift "$FLAGSHIFT"
REBUILD=1
;;
local)
flag_noarg && shift "$FLAGSHIFT"
LOCAL=1
;;
dry-run)
flag_noarg && shift "$FLAGSHIFT"
DRY_RUN=1
;;
run)
flag_reqarg && shift "$FLAGSHIFT"
JOBFILTER=$FLAGARG
;;
host-only)
flag_noarg && shift "$FLAGSHIFT"
HOST_ONLY=1
LOCAL=1
;;
version)
flag_nonemptyarg && shift "$FLAGSHIFT"
VERSION=$FLAGARG
;;
lockfile-force)
flag_noarg && shift "$FLAGSHIFT"
LOCKFILE_FORCE=1
;;
install)
flag_noarg && shift "$FLAGSHIFT"
INSTALL=1
HOST_ONLY=1
LOCAL=1
;;
uninstall)
flag_noarg && shift "$FLAGSHIFT"
UNINSTALL=1
HOST_ONLY=1
LOCAL=1
;;
push-docker)
flag_noarg && shift "$FLAGSHIFT"
PUSH_DOCKER=1
;;
latest-docker)
flag_noarg && shift "$FLAGSHIFT"
LATEST_DOCKER=1
;;
*)
flag_errusage "unrecognized flag $FLAGRAW"
;;
esac
done
shift "$FLAGSHIFT"
if [ $# -gt 0 ]; then
flag_errusage "no arguments are accepted"
fi
VERSION=${VERSION:-$(git_describe_ref)}
BUILD_DIR=ci/release/build/$VERSION
sh_c mkdir -p "$BUILD_DIR"
sh_c rm -f ci/release/build/latest
sh_c ln -s "$VERSION" ci/release/build/latest
if [ -n "${HOST_ONLY-}" ]; then
ensure_os
ensure_arch
runjob "$OS/$ARCH" "build"
if [ -n "${INSTALL-}" ]; then
sh_c make -sC "ci/release/build/$VERSION/$OS-$ARCH/d2-$VERSION" install
elif [ -n "${UNINSTALL-}" ]; then
sh_c make -sC "ci/release/build/$VERSION/$OS-$ARCH/d2-$VERSION" uninstall
fi
return 0
fi
runjob linux/amd64 'OS=linux ARCH=amd64 build' &
runjob linux/arm64 'OS=linux ARCH=arm64 build' &
runjob macos/amd64 'OS=macos ARCH=amd64 build' &
runjob macos/arm64 'OS=macos ARCH=arm64 build' &
runjob windows/amd64 'OS=windows ARCH=amd64 build' &
runjob windows/arm64 'OS=windows ARCH=arm64 build' &
waitjobs
runjob linux/docker build_docker &
runjob windows/amd64/msi 'OS=windows ARCH=amd64 build_windows_msi' &
waitjobs
}
build() {
HW_BUILD_DIR="$BUILD_DIR/$OS-$ARCH/d2-$VERSION"
ARCHIVE="$BUILD_DIR/d2-$VERSION-$OS-$ARCH.tar.gz"
if [ -e "$ARCHIVE" -a -z "${REBUILD-}" ]; then
log "skipping as already built at $ARCHIVE"
return 0
fi
if [ -n "${LOCAL-}" ]; then
build_local
return 0
fi
case $OS in
macos)
case $ARCH in
amd64)
REMOTE_HOST=$CI_D2_MACOS_AMD64 build_remote_macos
;;
arm64)
REMOTE_HOST=$CI_D2_MACOS_ARM64 build_remote_macos
;;
*)
warn "no builder for OS=$OS ARCH=$ARCH, building locally..."
build_local
;;
esac
;;
linux)
case $ARCH in
amd64)
REMOTE_HOST=$CI_D2_LINUX_AMD64 build_remote_linux
;;
arm64)
REMOTE_HOST=$CI_D2_LINUX_ARM64 build_remote_linux
;;
*)
warn "no builder for OS=$OS ARCH=$ARCH, building locally..."
build_local
;;
esac
;;
*)
warn "no builder for OS=$OS, building locally..."
build_local
;;
esac
}
build_local() {
export DRY_RUN \
HW_BUILD_DIR \
VERSION \
OS \
ARCH \
ARCHIVE
sh_c ./ci/release/_build.sh
}
build_remote_macos() {(
sh_c lockfile_ssh "$REMOTE_HOST" .d2-build-lock
sh_c gitsync "$REMOTE_HOST" src/d2
sh_c ssh "$REMOTE_HOST" "COLOR=${COLOR-} \
TERM=${TERM-} \
DRY_RUN=${DRY_RUN-} \
HW_BUILD_DIR=$HW_BUILD_DIR \
VERSION=$VERSION \
OS=$OS \
ARCH=$ARCH \
ARCHIVE=$ARCHIVE \
PATH=\\\"/usr/local/bin:/usr/local/sbin:/opt/homebrew/bin:/opt/homebrew/sbin\\\${PATH+:\\\$PATH}\\\" \
./src/d2/ci/release/_build.sh"
sh_c mkdir -p "$HW_BUILD_DIR"
sh_c rsync --archive --human-readable "$REMOTE_HOST:src/d2/$ARCHIVE" "$ARCHIVE"
)}
build_remote_linux() {(
sh_c lockfile_ssh "$REMOTE_HOST" .d2-build-lock
sh_c gitsync "$REMOTE_HOST" src/d2
sh_c ssh "$REMOTE_HOST" "COLOR=${COLOR-} \
TERM=${TERM-} \
DRY_RUN=${DRY_RUN-} \
HW_BUILD_DIR=$HW_BUILD_DIR \
VERSION=$VERSION \
OS=$OS \
ARCH=$ARCH \
ARCHIVE=$ARCHIVE \
./src/d2/ci/release/build_in_docker.sh"
sh_c mkdir -p "$HW_BUILD_DIR"
sh_c rsync --archive --human-readable "$REMOTE_HOST:src/d2/$ARCHIVE" "$ARCHIVE"
)}
build_docker() {
if [ -n "${LOCAL-}" ]; then
sh_c ./ci/release/docker/build.sh \
--version="$VERSION" \
${PUSH_DOCKER:+--push} \
${LATEST_DOCKER:+--latest}
return 0
fi
sh_c lockfile_ssh "$CI_D2_LINUX_AMD64" .d2-build-lock
sh_c gitsync "$CI_D2_LINUX_AMD64" src/d2
sh_c rsync --archive --human-readable \
"$BUILD_DIR/d2-$VERSION"-linux-*.tar.gz \
"$CI_D2_LINUX_AMD64:src/d2/$BUILD_DIR/"
sh_c ssh "$CI_D2_LINUX_AMD64" \
"D2_DOCKER_IMAGE=${D2_DOCKER_IMAGE-}" \
"RELEASE=${RELEASE-}" \
./src/d2/ci/release/docker/build.sh \
--version="$VERSION" \
${PUSH_DOCKER:+--push} \
${LATEST_DOCKER:+--latest}
}
build_windows_msi() {
REMOTE_HOST=$CI_D2_WINDOWS_AMD64
ln -sf "../build/$VERSION/windows-amd64/d2-$VERSION/bin/d2.exe" ./ci/release/windows/d2.exe
sh_c rsync --archive --human-readable --copy-links --delete ./ci/release/windows/ "'$REMOTE_HOST:windows/'"
if ! echo "$VERSION" | grep '[0-9]\.[0-9]\.[0-9]'; then
WIX_VERSION=0.0.0
else
WIX_VERSION=$VERSION
fi
sh_c ssh "$REMOTE_HOST" "'cd ./windows && wix build -arch x64 -d D2Version=$WIX_VERSION ./d2.wxs'"
# --files-from shouldn't be necessary but for some reason selecting d2.msi directly
# makes rsync error with:
# ERROR: rejecting unrequested file-list name: ./windows/d2.msi
# rsync error: requested action not supported (code 4) at flist.c(1027) [Receiver=3.2.7]
rsync_files=$(mktempd)/rsync-files
echo d2.msi >$rsync_files
sh_c rsync --archive --human-readable --files-from "$rsync_files" "'$REMOTE_HOST:windows/'" "./ci/release/build/$VERSION/d2-$VERSION-$OS-$ARCH.msi"
}
main "$@"