Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.git
.task
.cache
build
**/target
packages
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.task/
/.cache/
/build/
/packages/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ one of the tasks in the table below.

## Building installable packages

For details about the `.deb`, `.rpm`, and `.tar.gz` artifacts built in CI, see [tools/build-packages/README.md](tools/build-packages/README.md).
For details about the `.deb`, `.rpm`, and `.tar.gz` artifacts built in CI, and to build them locally, see [tools/build-packages/README.md](tools/build-packages/README.md).

[Task]: https://taskfile.dev
10 changes: 9 additions & 1 deletion taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ includes:

vars:
DEFAULT_CLP_PLUGIN_BUILD_DIR: "{{.ROOT_DIR}}/build"
G_BUILD_DIR: '{{env "CLP_PLUGIN_BUILD_DIR" | default .DEFAULT_CLP_PLUGIN_BUILD_DIR}}'
G_BUILD_DIR: '{{.CLP_PLUGIN_BUILD_DIR | default .DEFAULT_CLP_PLUGIN_BUILD_DIR}}'

tasks:
clean:
Expand All @@ -22,3 +22,11 @@ tasks:
run: "once"
cmds:
- "mkdir -p '{{.G_BUILD_DIR}}'"

package:
desc: "Build .deb/.rpm/.tar.gz packages."
preconditions:
- sh: "docker buildx version >/dev/null 2>&1"
msg: "docker (with buildx) is required for local package builds."
Comment thread
coderabbitai[bot] marked this conversation as resolved.
cmds:
- "'{{.ROOT_DIR}}/tools/build-packages/build-packages.sh' {{.CLI_ARGS}}"
6 changes: 5 additions & 1 deletion taskfiles/velox-connector/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ includes:

vars:
G_VELOX_CONNECTOR_BUILD_DIR: "{{.G_BUILD_DIR}}/velox-connector"
G_DEPS_CPP_DIR: "{{.G_VELOX_CONNECTOR_BUILD_DIR}}/deps/cpp"
DEFAULT_DEPS_CPP_DIR: "{{.G_VELOX_CONNECTOR_BUILD_DIR}}/deps/cpp"
G_DEPS_CPP_DIR: '{{.CLP_PLUGIN_DEPS_CPP_DIR | default .DEFAULT_DEPS_CPP_DIR}}'
DEFAULT_FETCHCONTENT_BASE_DIR: "{{.G_VELOX_CONNECTOR_BUILD_DIR}}/_deps"
G_FETCHCONTENT_BASE_DIR: '{{.FETCHCONTENT_BASE_DIR | default .DEFAULT_FETCHCONTENT_BASE_DIR}}'

tasks:
build:
Expand Down Expand Up @@ -41,5 +44,6 @@ tasks:
EXTRA_ARGS:
- "-DLIBCLP_PLUGIN_VELOX_CONNECTOR_DEPS_CMAKE_SETTINGS=\
{{.G_DEPS_CPP_CMAKE_SETTINGS_DIR}}/all-deps.cmake"
- "-DFETCHCONTENT_BASE_DIR={{.G_FETCHCONTENT_BASE_DIR}}"
- "-DPRESTO_GIT_TAG={{.G_PRESTO_GIT_TAG}}"
SOURCE_DIR: "{{.ROOT_DIR}}/velox-connector"
36 changes: 34 additions & 2 deletions tools/build-packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ This directory builds installable `.deb`, `.rpm`, and `.tar.gz` artifacts for th
Presto connector (coordinator + worker) on `amd64` and `arm64`.

CI packaging runs `tools/build-packages/internal/container/build-artifacts.sh`
through `.github/workflows/build-packages.yaml`. A follow-up adds a local
entrypoint that reuses the same container implementation.
through `.github/workflows/build-packages.yaml`. Local builds use
`build-packages.sh`, which resolves the build-env image and invokes the same
container-side script.

Supported package version format: must start with a digit and use only
`[0-9A-Za-z.+~-]`.
Expand All @@ -15,3 +16,34 @@ For command options, run `--help` on the relevant entry point.
Default outputs are written to `./packages`.
`coordinator/` contains `clp-plugin-presto-connector.jar`; `worker/` contains
`libclp-plugin-velox-connector.so` and bundled non-system runtime `.so` files.

## Local usage
Comment thread
jackluo923 marked this conversation as resolved.

```bash
task package
```

A thin wrapper over `./tools/build-packages/build-packages.sh` (call that
directly if `go-task` isn't installed). Both accept `--output DIR` and
`--version VER`; with the task, put `--` before the flags:
`task package -- --output DIR`.

The build runs inside a hash-tagged **build-env image** (`env-<hash>`) based on
`manylinux_2_28`. `build-dependency-image.sh` resolves it from the local Docker
cache, this repository's GHCR package, or a local build, reusing the cached
image on later runs.

Build state is cached under `.cache/` (`maven/`, `ccache/`,
`fetchcontent/<hash>/`, and `build/<hash>/` for persisted CMake/build state),
shared across build-env revisions. `.cache/build/<hash>/` is the container's
build output directory and is distinct from the repository's separate top-level
`build/` directory used by non-container local dev builds. The local wrapper
runs the container with the invoking host UID/GID, so it does not create
root-owned files; any root-owned files in `.cache/`, `build/`, or
`presto-connector/target/` are leftovers from earlier privileged or CI builds,
while `packages/` is owned by the invoking user.

### Prerequisites

Docker with buildx (usable without `sudo`), git, `sha256sum` or `shasum`, and
~10 GB free disk for the build-env image.
2 changes: 1 addition & 1 deletion tools/build-packages/build-dependency-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# docker run --rm -v "$(pwd):/src" -w /src "${image}" \
# task velox-connector:build-with-installed-deps
#
# Requires: docker (with buildx), git, sha256sum.
# Requires: docker (with buildx), git, and sha256sum or shasum.

set -o errexit
set -o nounset
Expand Down
122 changes: 122 additions & 0 deletions tools/build-packages/build-packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bash

# User-facing entry point for packaging. Resolves the build-env image, then runs
# internal/container/build-artifacts.sh inside it.
#
# Requires: docker (with buildx), git, and sha256sum or shasum.

set -o errexit
set -o nounset
set -o pipefail

src="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." &>/dev/null && pwd)"
# shellcheck source=tools/build-packages/internal/build-cache/host.sh
source "${src}/tools/build-packages/internal/build-cache/host.sh"

show_help() {
cat <<'EOF'
Usage: ./tools/build-packages/build-packages.sh [OPTIONS]

User-facing entry point for packaging. Resolves the build-env image, then runs
internal/container/build-artifacts.sh inside it.

Options are forwarded to internal/container/build-artifacts.sh:
--output DIR Output directory for built packages (default: ./packages)
--version VER Override package version
(default: derived from presto-connector/pom.xml)
VER must start with a digit and use [0-9A-Za-z.+~-]
--help Show this help

See tools/build-packages/README.md for details.
EOF
}

# Resolve the output directory on the host before copying completed artifacts
# into it. Other arguments are forwarded unchanged to build-artifacts.sh.
output_dir="${src}/packages"
build_args=()
while [[ $# -gt 0 ]]; do
case $1 in
--output)
[[ -n "${2:-}" ]] || { echo >&2 "ERROR: --output requires a value"; exit 1; }
output_dir="$2"
shift 2
;;
--help)
show_help
exit 0
;;
*)
build_args+=("$1")
shift
;;
esac
done

# Run the wrapper as the intended artifact owner. Using sudo would make the
# staging directories and copied artifacts root-owned.
if (( EUID == 0 )); then
echo >&2 "ERROR: build-packages.sh must run as a non-root user; do not invoke it with sudo."
exit 1
fi

if [[ "${output_dir}" != /* ]]; then
output_dir="${src}/${output_dir}"
fi
mkdir -p "${output_dir}"
output_dir="$(cd "${output_dir}" && pwd)"

# Initialize submodules on the host so the source tree is complete before it is
# bind-mounted into the build container.
echo "==> Initializing submodules..."
git -C "${src}" submodule update --init --recursive

echo "==> Resolving build-env image..."
image=$("${src}/tools/build-packages/build-dependency-image.sh")
# FetchContent build state is compatible only with the image inputs identified
# by this hash.
image_hash="${image##*:env-}"
if [[ "${image_hash}" == "${image}" ]]; then
echo >&2 "ERROR: build-env image lacks an env-<hash> tag: ${image}"
exit 1
fi

# Keep container output in temporary staging, then copy it to the requested
# directory after the build succeeds.
stage_dir=$(mktemp -d)
trap 'rm -rf "${stage_dir}"' EXIT
artifact_stage="${stage_dir}/artifacts"
mkdir -p "${artifact_stage}"
prepare_build_cache "${src}/.cache" "${image_hash}"
host_uid=$(id -u)
host_gid=$(id -g)

# Run as the host user so staged files and artifacts aren't root-owned. Bind the
# repo at a stable /repo path so cached CMake state doesn't embed the host
# checkout path. The --env flags below wire the build cache and point HOME /
# TASK_TEMP_DIR at disposable in-container scratch (the non-root user can't
# write to the image's defaults); build-artifacts.sh activates that setup only
# when BUILD_CACHE_DIR is present, so CI (which calls it directly) is unaffected.
echo "==> Running internal/container/build-artifacts.sh inside ${image}..."
docker run --rm \
--user "${host_uid}:${host_gid}" \
--mount "type=bind,src=${src},dst=/repo" \
--mount "type=bind,src=${artifact_stage},dst=/output" \
--env "BUILD_CACHE_KEY=${image_hash}" \
--env "BUILD_CACHE_DIR=/repo/.cache" \
--env "CLP_PLUGIN_BUILD_DIR=/repo/.cache/build/${image_hash}" \
--env "HOME=/tmp/clp-plugin-presto-connector-home" \
--env "TASK_TEMP_DIR=/tmp/clp-plugin-presto-connector-task" \
-w /repo \
"${image}" \
bash /repo/tools/build-packages/internal/container/build-artifacts.sh \
--output /output ${build_args[@]+"${build_args[@]}"}

echo "==> Copying package artifacts to ${output_dir}..."
# Fail clearly when the build produced no artifacts, instead of passing a
# literal '*' to cp (which happens when the glob has no matches).
if ! compgen -G "${artifact_stage}/*" > /dev/null; then
echo >&2 "ERROR: no package artifacts were produced under ${artifact_stage}"
exit 1
fi
cp -f "${artifact_stage}"/* "${output_dir}/"
3 changes: 2 additions & 1 deletion tools/build-packages/dependency-image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ RUN --mount=type=bind,from=host-ca,source=host-ca,target=${HOST_CA_BUNDLE} \
dnf_sslcacert_opt="--setopt=sslcacert=${HOST_CA_BUNDLE}"; \
fi \
&& dnf install -y --setopt=install_weak_deps=False ${dnf_sslcacert_opt} \
dpkg gettext git java-17-openjdk-devel libcurl-devel libevent-devel \
ccache dpkg gettext git java-17-openjdk-devel libcurl-devel libevent-devel \
libunwind-devel ninja-build openssl-devel patchelf python3-pip rpm-build \
&& dnf clean all

Expand All @@ -41,6 +41,7 @@ RUN --mount=type=bind,from=host-ca,source=host-ca,target=${HOST_CA_BUNDLE} \
ENV PATH=/opt/go-task/bin:${PATH}

ENV CLP_PLUGIN_BUILD_DIR=/opt/clp-plugin-presto-connector/build
ENV CLP_PLUGIN_DEPS_CPP_DIR=/opt/clp-plugin-presto-connector/build/velox-connector/deps/cpp
ENV TASK_TEMP_DIR=/opt/clp-plugin-presto-connector/.task

# Build one dependency at a time to avoid excessive memory usage from parallel builds.
Expand Down
14 changes: 11 additions & 3 deletions tools/build-packages/dependency-image/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,23 @@ _BUILD_ENV_HASH_INPUTS=(

# Computes the 16-hex-char hash used in the image tag.
#
# Requires: git, sha256sum
# Requires: git, and either sha256sum (Linux) or shasum -a 256 (macOS).
derive_build_env_hash() {
(
cd "${_REPO_ROOT}" || exit
ensure_yscope_dev_utils_submodule >&2

# macOS ships `shasum` rather than `sha256sum`; pick whichever exists.
# Both emit the same `<hash> <file>` format, so the pipeline is unchanged.
local sha256_cmd=(sha256sum)
if ! command -v sha256sum &>/dev/null; then
sha256_cmd=(shasum -a 256)
fi

git ls-files -z --recurse-submodules -- "${_BUILD_ENV_HASH_INPUTS[@]}" \
| LC_ALL=C sort -z \
| xargs -0 sha256sum \
| sha256sum \
| xargs -0 "${sha256_cmd[@]}" \
| "${sha256_cmd[@]}" \
| cut -c1-16
)
}
Expand Down
23 changes: 23 additions & 0 deletions tools/build-packages/internal/build-cache/container.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env sh

# Container-side configuration for consuming a prepared build cache.

if [ -n "${BUILD_CACHE_DIR:-}" ]; then
if [ -z "${BUILD_CACHE_KEY:-}" ]; then
echo >&2 "ERROR: BUILD_CACHE_KEY must be set when BUILD_CACHE_DIR is set"
return 1
fi

export CCACHE_DIR="${CCACHE_DIR:-${BUILD_CACHE_DIR}/ccache}"
export CCACHE_MAXSIZE="${CCACHE_MAXSIZE:-1G}"
export CMAKE_C_COMPILER_LAUNCHER="${CMAKE_C_COMPILER_LAUNCHER:-ccache}"
export CMAKE_CXX_COMPILER_LAUNCHER="${CMAKE_CXX_COMPILER_LAUNCHER:-ccache}"
export FETCHCONTENT_BASE_DIR="${FETCHCONTENT_BASE_DIR:-${BUILD_CACHE_DIR}/fetchcontent/${BUILD_CACHE_KEY}}"
export MAVEN_USER_HOME="${MAVEN_USER_HOME:-${BUILD_CACHE_DIR}/maven}"

mkdir -p \
"${BUILD_CACHE_DIR}/build/${BUILD_CACHE_KEY}" \
"${CCACHE_DIR}" \
"${FETCHCONTENT_BASE_DIR}" \
"${MAVEN_USER_HOME}"
fi
26 changes: 26 additions & 0 deletions tools/build-packages/internal/build-cache/host.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash

# Host-side preparation for persistent container build caches.

if [[ "${_BUILD_CACHE_HOST_SH_LOADED:-}" == "1" ]]; then
return 0
fi
readonly _BUILD_CACHE_HOST_SH_LOADED=1

# Creates the shared tool caches and a namespaced FetchContent cache.
#
# Args: <cache-directory> <cache-key>
prepare_build_cache() {
if (( $# != 2 )) || [[ -z "$1" || -z "$2" ]]; then
echo >&2 "ERROR: prepare_build_cache requires a cache directory and key"
return 2
fi

local cache_dir="$1"
local cache_key="$2"
mkdir -p \
"${cache_dir}/build/${cache_key}" \
"${cache_dir}/ccache" \
"${cache_dir}/fetchcontent/${cache_key}" \
"${cache_dir}/maven"
}
Loading
Loading