#!/bin/bash # Regenerates GoLib/AtircGo.xcframework for the AT-IRC app. # # The framework must contain a SINGLE Go runtime: it is built from the atircgo # package in the kcp fork, which combines the app's IRC helpers with the kcp # bridge (kcpios). Never add a second gomobile framework to the app. # # Requires gomobile/gobind on PATH, Xcode and git. The kcp fork (branch kcp-ios # of github.com/johnandersen777/kcp) and socialweb-computer-kcp are fetched at # the pinned commits below; KCP_IOS_REPO / SOCIALWEB_SRC point at local # checkouts instead (docs/plans/0001). set -euo pipefail cd "$(dirname "$0")" # The pinned commit of the kcp fork's kcp-ios branch the framework embeds. KCP_COMMIT="${KCP_COMMIT:-f233e4f2c3daa21f6cee39e6c5f12e679e2d58e9}" KCP_FORK_URL="${KCP_FORK_URL:-https://github.com/johnandersen777/kcp}" SOCIALWEB_URL="${SOCIALWEB_URL:-https://github.com/publicdomainrelay/socialweb-computer-kcp}" SOCIALWEB_SRC_GIVEN="${SOCIALWEB_SRC:-}" KCP_REPO="${KCP_IOS_REPO:-/tmp/kcp-ios-src}" SOCIALWEB_SRC="${SOCIALWEB_SRC:-/tmp/socialweb-ios-src}" # The pinned socialweb-computer-kcp commit the framework embeds. SOCIALWEB_COMMIT="${SOCIALWEB_COMMIT:-5e6c4e3d6efb3779064f8ae5d64341dffbdb76af}" SOCIALWEB_MIRROR="${SOCIALWEB_MIRROR:-/tmp/socialweb-ios-mirror}" export PATH="$(go env GOPATH)/bin:$PATH" if ! command -v gomobile >/dev/null || ! command -v gobind >/dev/null; then echo "Missing gomobile/gobind. Install with:" >&2 echo " go install golang.org/x/mobile/cmd/gomobile@latest golang.org/x/mobile/cmd/gobind@latest" >&2 exit 1 fi # fetch_pin : a checkout of exactly that commit. fetch_pin() { if [[ "$(git -C "$1" rev-parse HEAD 2>/dev/null)" != "$3" ]]; then echo "fetching $2 at $3 into $1..." rm -rf "$1" git init -q "$1" git -C "$1" fetch -q --depth 1 "$2" "$3" git -C "$1" checkout -q --detach FETCH_HEAD fi } if [[ -z "${KCP_IOS_REPO:-}" ]]; then fetch_pin "${KCP_REPO}" "${KCP_FORK_URL}" "${KCP_COMMIT}" fi if [[ -z "${SOCIALWEB_SRC_GIVEN}" ]]; then fetch_pin "${SOCIALWEB_SRC}" "${SOCIALWEB_URL}" "${SOCIALWEB_COMMIT}" fi # socialweb (pkg/embedded) is the pinned commit, archived from git objects # into a stable mirror, like the wasm build does. if [[ "${SOCIALWEB_REFRESH:-1}" == "1" || ! -f "${SOCIALWEB_MIRROR}/go.mod" ]]; then echo "mirroring socialweb source to ${SOCIALWEB_MIRROR}..." rm -rf "${SOCIALWEB_MIRROR}" mkdir -p "${SOCIALWEB_MIRROR}" git -C "${SOCIALWEB_SRC}" -c safe.directory="${SOCIALWEB_SRC}" archive "${SOCIALWEB_COMMIT}" | tar -x -C "${SOCIALWEB_MIRROR}" fi # The apiserver factory must come from the patched memory:// copy. The fork's # go.mod replaces k8s.io/apiserver with /tmp/kcp-patched-modules-native/apiserver # (produced by this script); gomobile reads go.mod, so keep both in sync. # The fork's go.mod replaces k8s.io/apiserver with the patched copy under /tmp, # which does not survive a reboot. Seed it from the module cache: the kcp-dev # kubernetes staging apiserver at the version the fork's other k8s.io replaces use. PATCHED_APISERVER=/tmp/kcp-patched-modules-native/apiserver if [[ ! -d "${PATCHED_APISERVER}" ]]; then KUBE_FORK_VERSION="$(cd "${KCP_REPO}" && go mod edit -json | python3 -c 'import json,sys; print(next(r["New"]["Version"] for r in json.load(sys.stdin)["Replace"] if r["Old"]["Path"] == "k8s.io/apimachinery"))')" echo "seeding ${PATCHED_APISERVER} from kcp-dev kubernetes ${KUBE_FORK_VERSION}..." APISERVER_DIR="$(cd "$(mktemp -d)" && GOFLAGS=-mod=mod go mod download -json "github.com/kcp-dev/kubernetes/staging/src/k8s.io/apiserver@${KUBE_FORK_VERSION}" | python3 -c 'import json,sys; print(json.load(sys.stdin)["Dir"])')" mkdir -p "$(dirname "${PATCHED_APISERVER}")" cp -a "${APISERVER_DIR}" "${PATCHED_APISERVER}" chmod -R u+w "${PATCHED_APISERVER}" fi ( cd "${KCP_REPO}" KCP_PATCH_MODE=native ./scripts/prepare-kcp-patched-modules.sh \ /tmp/kcp-patched-modules-native .go.memory.mod >/dev/null grep -q 'k8s.io/apiserver => /tmp/kcp-patched-modules-native/apiserver' go.mod || { echo "go.mod must replace k8s.io/apiserver with the native patched copy" >&2 echo "see docs/plans/0001-ios-embedded-kcp.md" >&2 exit 1 } GOLIB="$(cd - >/dev/null && pwd)" # GOLIB_REMOTE_CACHE (default hat-8, empty for none) is an ssh host that # compiles the pure-Go packages (remote-warm.sh); this build reads them # from its cache over ssh (cacheprog), so only cgo and the link run here. # An unreachable host means a local build. Either way GOCACHE is a scratch # dir deleted afterwards: this Mac keeps no Go build cache. REMOTE="${GOLIB_REMOTE_CACHE-hat-8}" RDIR="${GOLIB_REMOTE_DIR:-.tmp/golib-remote}" SSH=(ssh -o BatchMode=yes -o ConnectTimeout=5) if [[ -n "${REMOTE}" ]] && ! "${SSH[@]}" "${REMOTE}" true; then echo "${REMOTE} unreachable; building locally" >&2 REMOTE="" fi SCRATCH="$(mktemp -d)" trap 'rm -rf "${SCRATCH}"' EXIT export GOCACHE="${SCRATCH}/gocache" if [[ -n "${REMOTE}" ]]; then "${SSH[@]}" "${REMOTE}" mkdir -p "${RDIR}/src" rsync -a --delete --exclude .git -e "${SSH[*]}" "${KCP_REPO}/" "${REMOTE}:${RDIR}/src/kcp/" rsync -a --delete -e "${SSH[*]}" /tmp/kcp-patched-modules-native/ "${REMOTE}:${RDIR}/src/patched/" rsync -a --delete --exclude .git -e "${SSH[*]}" "${SOCIALWEB_MIRROR}/" "${REMOTE}:${RDIR}/src/mirror/" rsync -a --delete -e "${SSH[*]}" "${GOLIB}/cacheprog/" "${REMOTE}:${RDIR}/src/cacheprog/" "${SSH[@]}" "${REMOTE}" "cd ${RDIR} && sed -i \"s#/tmp/kcp-patched-modules-native#\$PWD/src/patched#; s#${SOCIALWEB_MIRROR}#\$PWD/src/mirror#\" src/kcp/go.mod" MOBILE="$(go version -m "$(command -v gomobile)" | awk '$1 == "mod" && $2 == "golang.org/x/mobile" {print $3}')" "${SSH[@]}" "${REMOTE}" bash -s -- "${RDIR}" "$(go env GOVERSION)" "${MOBILE}" < "${GOLIB}/remote-warm.sh" (cd "${GOLIB}/cacheprog" && go build -o "${SCRATCH}/cacheprog" .) export GOCACHEPROG="${SCRATCH}/cacheprog -dir ${SCRATCH}/objs -- ${SSH[*]} ${REMOTE} ${RDIR}/bin/cacheprog -serve ${RDIR}/gocache" fi # -trimpath: cache keys and the framework do not depend on local paths. gomobile bind -trimpath -target=ios,iossimulator -ldflags="-s -w" \ -o "${GOLIB}/AtircGo.xcframework" \ github.com/kcp-dev/kcp/contrib/wasm/ios/atircgo )