-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.sh
More file actions
executable file
·175 lines (155 loc) · 5.76 KB
/
build.sh
File metadata and controls
executable file
·175 lines (155 loc) · 5.76 KB
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
#!/usr/bin/env bash
# Build the durable-workflow CLI as a PHAR and optionally as a standalone
# static binary (PHAR embedded in phpmicro).
#
# Usage:
# scripts/build.sh phar # Build the PHAR only (requires system PHP)
# scripts/build.sh binary # Build the PHAR + standalone native binary
# scripts/build.sh clean # Remove build artifacts
#
# Outputs land in ./build/.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
BUILD_DIR="$ROOT/build"
TOOLS_DIR="$ROOT/build/.tools"
PHAR_OUT="$BUILD_DIR/dw.phar"
# Extensions required by the CLI at runtime. Keep this list in sync with the
# CI matrix in .github/workflows/release.yml.
SPC_EXTENSIONS="curl,mbstring,openssl,phar,tokenizer,ctype,filter,fileinfo,iconv,sockets"
SPC_DOWNLOAD_RETRY="${SPC_DOWNLOAD_RETRY:-5}"
SPC_DOWNLOAD_OUTER_ATTEMPTS="${SPC_DOWNLOAD_OUTER_ATTEMPTS:-4}"
BOX_VERSION="${BOX_VERSION:-4.6.6}"
BOX_URL="https://github.com/box-project/box/releases/download/${BOX_VERSION}/box.phar"
detect_platform() {
local os arch
case "$(uname -s)" in
Linux) os="linux" ;;
Darwin) os="macos" ;;
*) echo "Unsupported OS: $(uname -s)" >&2; exit 1 ;;
esac
case "$(uname -m)" in
x86_64|amd64) arch="x86_64" ;;
arm64|aarch64) arch="aarch64" ;;
*) echo "Unsupported arch: $(uname -m)" >&2; exit 1 ;;
esac
echo "${os}-${arch}"
}
ensure_tools() {
mkdir -p "$TOOLS_DIR"
if [[ ! -x "$TOOLS_DIR/box" ]]; then
echo ">> Downloading Box ${BOX_VERSION}"
curl -fsSL -o "$TOOLS_DIR/box" "$BOX_URL"
chmod +x "$TOOLS_DIR/box"
fi
}
ensure_spc() {
local platform
platform="$(detect_platform)"
if [[ ! -x "$TOOLS_DIR/spc" ]]; then
echo ">> Downloading spc (static-php-cli) for ${platform}"
curl -fsSL -o "$TOOLS_DIR/spc" \
"https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-${platform}"
chmod +x "$TOOLS_DIR/spc"
fi
}
install_composer_deps() {
echo ">> Installing production Composer dependencies"
composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
}
ensure_source_date_epoch() {
# Reproducible builds (https://reproducible-builds.org/specs/source-date-epoch/):
# default SOURCE_DATE_EPOCH to the current commit timestamp so the same
# source tree always produces the same PHAR bytes. Callers can override.
if [[ -z "${SOURCE_DATE_EPOCH:-}" ]]; then
if [[ -d "$ROOT/.git" ]] && command -v git >/dev/null 2>&1; then
local commit_time
commit_time="$(git -C "$ROOT" log -1 --pretty=%ct 2>/dev/null || true)"
if [[ "$commit_time" =~ ^[0-9]+$ ]]; then
export SOURCE_DATE_EPOCH="$commit_time"
fi
fi
fi
if [[ -n "${SOURCE_DATE_EPOCH:-}" ]]; then
echo ">> SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
fi
}
normalize_mtimes() {
# Pin mtimes on every input that ends up inside the PHAR so Box's
# archive entries hash identically across builds. Box also reads
# SOURCE_DATE_EPOCH directly, but normalizing the filesystem first
# protects us from compactor differences and ext-phar timestamps.
[[ -n "${SOURCE_DATE_EPOCH:-}" ]] || return 0
if ! command -v find >/dev/null 2>&1; then
return 0
fi
local epoch="$SOURCE_DATE_EPOCH"
local target
for target in src schemas bin vendor; do
[[ -e "$ROOT/$target" ]] || continue
find "$ROOT/$target" -exec touch -h -d "@$epoch" {} + 2>/dev/null || true
done
[[ -e "$ROOT/src/GeneratedBuildInfo.php" ]] && \
touch -h -d "@$epoch" "$ROOT/src/GeneratedBuildInfo.php" 2>/dev/null || true
}
spc_download_with_retry() {
if [[ ! "$SPC_DOWNLOAD_OUTER_ATTEMPTS" =~ ^[0-9]+$ ]] || [[ "$SPC_DOWNLOAD_OUTER_ATTEMPTS" -lt 1 ]]; then
echo "SPC_DOWNLOAD_OUTER_ATTEMPTS must be a positive integer" >&2
exit 1
fi
local attempt delay
for ((attempt = 1; attempt <= SPC_DOWNLOAD_OUTER_ATTEMPTS; attempt++)); do
if ./spc download "$@"; then
return 0
fi
if [[ "$attempt" -lt "$SPC_DOWNLOAD_OUTER_ATTEMPTS" ]]; then
delay=$((attempt * 30))
echo ">> spc dependency download attempt ${attempt}/${SPC_DOWNLOAD_OUTER_ATTEMPTS} failed; retrying in ${delay}s" >&2
sleep "$delay"
fi
done
echo "spc dependency download failed after ${SPC_DOWNLOAD_OUTER_ATTEMPTS} attempts" >&2
return 1
}
build_phar() {
ensure_tools
ensure_source_date_epoch
php scripts/generate-build-info.php
install_composer_deps
mkdir -p "$BUILD_DIR"
normalize_mtimes
echo ">> Building PHAR via Box"
php -d phar.readonly=0 "$TOOLS_DIR/box" compile --no-parallel
echo ">> PHAR built: $PHAR_OUT"
}
build_binary() {
build_phar
ensure_spc
local php_version="${PHP_VERSION:-8.4}"
local platform
platform="$(detect_platform)"
local out_name="dw-${platform}"
pushd "$TOOLS_DIR" >/dev/null
echo ">> Downloading PHP ${php_version} source + extension deps"
spc_download_with_retry --with-php="$php_version" --for-extensions="$SPC_EXTENSIONS" \
--prefer-pre-built --without-suggestions --retry="$SPC_DOWNLOAD_RETRY"
echo ">> Compiling phpmicro with required extensions"
./spc build "$SPC_EXTENSIONS" --build-micro
echo ">> Embedding PHAR into micro SAPI"
./spc micro:combine "$PHAR_OUT" --output="$BUILD_DIR/$out_name"
popd >/dev/null
chmod +x "$BUILD_DIR/$out_name"
echo ">> Standalone binary: $BUILD_DIR/$out_name"
}
clean() {
rm -rf "$BUILD_DIR"
rm -f "$ROOT/src/GeneratedBuildInfo.php"
echo ">> Cleaned $BUILD_DIR"
}
cmd="${1:-phar}"
case "$cmd" in
phar) build_phar ;;
binary) build_binary ;;
clean) clean ;;
*) echo "Usage: $0 {phar|binary|clean}" >&2; exit 1 ;;
esac