iop/bin/build/field-binaries.sh
toki 0d83ef378e 기능: bootstrap 명령을 positional token 방식의 한 줄 UX로 변경한다
사용자가 artifact URL, Edge 주소, token을 환경변수로 직접 설정하던
IOP_* named parameter 방식을 제거하고, curl | bash -s <token> 형태의
단일 positional token UX로 변경한다.

- bootstrap script에서 NODE_TOKEN을 첫 번째 인자로 받도록 변경
- token 누락 시 명확한 에러 메시지 출력
- artifact HTTP를 127.0.0.1 바인딩으로 변경
- docs, rules, roadmap에 one-line bootstrap UX 기준 기록
2026-05-27 17:56:27 +09:00

200 lines
5.6 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
DIST_DIR="${DIST_DIR:-"$ROOT_DIR/dist/field"}"
TARGETS="${TARGETS:-}"
APPS="${APPS:-"edge node"}"
CGO_ENABLED="${CGO_ENABLED:-0}"
GOFLAGS="${GOFLAGS:-"-trimpath"}"
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
cat <<'USAGE'
Build field-deployable IOP edge/node binaries.
Usage:
bin/build/field-binaries.sh
Environment:
APPS="edge node" apps to build
TARGETS="linux/amd64 linux/arm64" GOOS/GOARCH target list
DIST_DIR=dist/field output directory
VERSION=<value> release version label
COMMIT=<value> commit label
BUILD_DATE=<value> build date label
ARTIFACT_BASE_URL=<url> default bootstrap artifact base URL
BOOTSTRAP_EDGE_ADDR=<host:port> default Edge address written to node.yaml
BOOTSTRAP_NODE_TOKEN=<token> optional fallback token baked into bootstrap script
CGO_ENABLED=0 Go CGO setting
GOFLAGS="-trimpath" extra go build flags
LDFLAGS="-s -w" linker flags
USAGE
exit 0
fi
VERSION="${VERSION:-"$(git -C "$ROOT_DIR" describe --tags --always --dirty 2>/dev/null || echo dev)"}"
COMMIT="${COMMIT:-"$(git -C "$ROOT_DIR" rev-parse --short=12 HEAD 2>/dev/null || echo unknown)"}"
BUILD_DATE="${BUILD_DATE:-"$(date -u +%Y%m%dT%H%M%SZ)"}"
LDFLAGS="${LDFLAGS:-"-s -w"}"
if [[ -z "$TARGETS" ]]; then
TARGETS="$(go env GOOS)/$(go env GOARCH)"
fi
checksum() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$@"
return
fi
shasum -a 256 "$@"
}
app_enabled() {
local wanted="$1"
local app
for app in $APPS; do
if [[ "$app" == "$wanted" ]]; then
return 0
fi
done
return 1
}
build_one() {
local app="$1"
local goos="$2"
local goarch="$3"
local output_dir="$DIST_DIR/$VERSION/$goos-$goarch"
local output="$output_dir/iop-$app"
mkdir -p "$output_dir"
echo "building $app for $goos/$goarch -> $output"
(
cd "$ROOT_DIR"
GOOS="$goos" GOARCH="$goarch" CGO_ENABLED="$CGO_ENABLED" \
go build $GOFLAGS -ldflags "$LDFLAGS" -o "$output" "./apps/$app/cmd/$app"
)
(
cd "$output_dir"
checksum "iop-$app" > "iop-$app.sha256"
)
}
write_node_bootstrap() {
local goos="$1"
local goarch="$2"
local target_dir="$goos-$goarch"
local bootstrap_dir="$DIST_DIR/$VERSION/bootstrap"
local script="$bootstrap_dir/node-$target_dir.sh"
local default_base_url="${ARTIFACT_BASE_URL:-"http://toki-labs.com:18080"}"
local default_edge_addr="${BOOTSTRAP_EDGE_ADDR:-"toki-labs.com:19090"}"
local default_node_token="${BOOTSTRAP_NODE_TOKEN:-}"
mkdir -p "$bootstrap_dir"
cat > "$script" <<EOF
#!/usr/bin/env bash
set -euo pipefail
VERSION="$VERSION"
TARGET="$target_dir"
DEFAULT_ARTIFACT_BASE_URL="$default_base_url"
DEFAULT_EDGE_ADDR="$default_edge_addr"
DEFAULT_NODE_TOKEN="$default_node_token"
POSITIONAL_NODE_TOKEN="\${1:-}"
ARTIFACT_BASE_URL="\$DEFAULT_ARTIFACT_BASE_URL"
EDGE_ADDR="\$DEFAULT_EDGE_ADDR"
NODE_TOKEN="\${POSITIONAL_NODE_TOKEN:-\$DEFAULT_NODE_TOKEN}"
INSTALL_DIR="\${IOP_HOME:-\$HOME/iop-field}"
CONFIG_FILE="\${IOP_NODE_CONFIG:-\$INSTALL_DIR/node.yaml}"
BIN_FILE="\$INSTALL_DIR/iop-node"
TMP_DIR="\$(mktemp -d "\${TMPDIR:-/tmp}/iop-node-bootstrap.XXXXXX")"
cleanup() {
rm -rf "\$TMP_DIR"
}
trap cleanup EXIT
ARTIFACT_BASE_URL="\${ARTIFACT_BASE_URL%/}"
if [[ -z "\$NODE_TOKEN" ]]; then
echo "[iop-bootstrap] missing node token" >&2
echo "[iop-bootstrap] usage: curl -fsSL <artifact-base-url>/bootstrap/node-\$TARGET.sh | bash -s TOKEN" >&2
exit 2
fi
echo "[iop-bootstrap] version=\$VERSION target=\$TARGET"
echo "[iop-bootstrap] install_dir=\$INSTALL_DIR"
mkdir -p "\$INSTALL_DIR"
curl -fsSL "\$ARTIFACT_BASE_URL/\$TARGET/iop-node" -o "\$TMP_DIR/iop-node"
curl -fsSL "\$ARTIFACT_BASE_URL/\$TARGET/SHA256SUMS" -o "\$TMP_DIR/SHA256SUMS"
if command -v sha256sum >/dev/null 2>&1; then
(cd "\$TMP_DIR" && grep -E '[ *]iop-node$' SHA256SUMS | sha256sum -c -)
elif command -v shasum >/dev/null 2>&1; then
(cd "\$TMP_DIR" && grep -E '[ *]iop-node$' SHA256SUMS | shasum -a 256 -c -)
else
echo "[iop-bootstrap] warning: no sha256 checker found; skipping checksum verification" >&2
fi
cp "\$TMP_DIR/iop-node" "\$BIN_FILE"
chmod +x "\$BIN_FILE"
if command -v xattr >/dev/null 2>&1; then
xattr -d com.apple.quarantine "\$BIN_FILE" 2>/dev/null || true
fi
cat > "\$CONFIG_FILE" <<YAML
transport:
edge_addr: "\$EDGE_ADDR"
token: "\$NODE_TOKEN"
logging:
level: "\${IOP_LOG_LEVEL:-info}"
pretty: true
metrics:
port: \${IOP_NODE_METRICS_PORT:-9091}
YAML
echo "[iop-bootstrap] config=\$CONFIG_FILE"
echo "[iop-bootstrap] starting node against \$EDGE_ADDR"
exec "\$BIN_FILE" serve --config "\$CONFIG_FILE"
EOF
chmod +x "$script"
}
for target in $TARGETS; do
IFS=/ read -r goos goarch extra <<< "$target"
if [[ -z "${goos:-}" || -z "${goarch:-}" || -n "${extra:-}" ]]; then
echo "invalid target '$target'; expected GOOS/GOARCH" >&2
exit 1
fi
for app in $APPS; do
case "$app" in
edge|node) build_one "$app" "$goos" "$goarch" ;;
*)
echo "unsupported app '$app'; expected edge or node" >&2
exit 1
;;
esac
done
output_dir="$DIST_DIR/$VERSION/$goos-$goarch"
{
echo "version=$VERSION"
echo "commit=$COMMIT"
echo "build_date=$BUILD_DATE"
echo "target=$goos/$goarch"
echo "apps=$APPS"
} > "$output_dir/manifest.env"
(
cd "$output_dir"
checksum iop-* | grep -v '\.sha256$' > SHA256SUMS
)
if app_enabled node; then
write_node_bootstrap "$goos" "$goarch"
fi
done
echo "field binaries written to $DIST_DIR/$VERSION"