diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index fce31e7..7398f1b 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -26,63 +26,139 @@ on: required: true default: '3.1.2' type: string + swift_version_linux: + description: 'The Swift toolchain version to install on the Linux runner' + required: true + default: '6.2' + type: string + +# Surface inputs as env vars so shell bodies can read them as `$VARS` +# rather than `${{ ... }}` (Semgrep flags context-var expansion in `run:`). +env: + RELEASE_TAG: ${{ inputs.tag }}${{ inputs.build_number != '' && format('+{0}', inputs.build_number) || '' }} + SWIFT_SYNTAX_VERSION: ${{ inputs.tag }} + BUILD_NUMBER: ${{ inputs.build_number }} + XCODE_VERSION: ${{ inputs.xcode_version }} + MACOS_VERSION: ${{ inputs.macos_version }} + RULES_SWIFT_VERSION: ${{ inputs.rules_swift_version }} + SWIFT_VERSION_LINUX: ${{ inputs.swift_version_linux }} + +# Read-only by default; publish job opts in to contents:write. +permissions: + contents: read jobs: - build-publish: + build-macos-arm64: runs-on: macos-latest env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - XCODE_VERSION: ${{ github.event.inputs.xcode_version }} - RULES_SWIFT_VERSION: ${{ github.event.inputs.rules_swift_version }} - MACOS_VERSION: ${{ github.event.inputs.macos_version }} + TARGET_PLATFORM: macos-arm64 steps: - name: Install brew dependencies - run: | - brew install buildozer + run: brew install buildozer - name: Select Xcode ${{ env.XCODE_VERSION }} run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app - name: Clone repo uses: actions/checkout@v4 - name: Clone SwiftSyntax + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh repo clone apple/swift-syntax -- \ --depth 1 \ - --branch ${{ github.event.inputs.tag }} \ + --branch "$SWIFT_SYNTAX_VERSION" \ --single-branch - - name: Build & Publish SwiftSyntax prebuilt binary + - name: Build SwiftSyntax for macos-arm64 + run: ./build.sh build + - name: Upload per-platform staging artifact + uses: actions/upload-artifact@v4 + with: + name: staging-macos-arm64 + path: staging/macos-arm64.tar.gz + if-no-files-found: error + + build-linux-x86_64: + runs-on: ubuntu-latest + env: + TARGET_PLATFORM: linux-x86_64 + # rules_swift's Linux toolchain requires clang; ubuntu-latest defaults to gcc. + CC: clang + CXX: clang++ + steps: + - name: Install Swift ${{ env.SWIFT_VERSION_LINUX }} + uses: swift-actions/setup-swift@7ca6abe6b3b0e8b5421b88be48feee39cbf52c6a # v2.4.0 + with: + swift-version: ${{ env.SWIFT_VERSION_LINUX }} + - name: Install clang + buildozer + jq run: | set -euo pipefail + sudo apt-get update + sudo apt-get install -y clang jq + curl -sSL -o /tmp/buildozer \ + https://github.com/bazelbuild/buildtools/releases/latest/download/buildozer-linux-amd64 + chmod +x /tmp/buildozer + sudo mv /tmp/buildozer /usr/local/bin/buildozer + - name: Clone repo + uses: actions/checkout@v4 + - name: Clone SwiftSyntax + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh repo clone apple/swift-syntax -- \ + --depth 1 \ + --branch "$SWIFT_SYNTAX_VERSION" \ + --single-branch + - name: Build SwiftSyntax for linux-x86_64 + run: ./build.sh build + - name: Upload per-platform staging artifact + uses: actions/upload-artifact@v4 + with: + name: staging-linux-x86_64 + path: staging/linux-x86_64.tar.gz + if-no-files-found: error - release_tag="${{ github.event.inputs.tag }}" - if [ -n "${{ github.event.inputs.build_number }}" ]; then - release_tag="$release_tag+${{ github.event.inputs.build_number }}" - fi - - archive_name="swift-syntax-$release_tag" + publish: + needs: + - build-macos-arm64 + - build-linux-x86_64 + runs-on: ubuntu-latest + permissions: + contents: write # gh release create + steps: + - name: Clone repo + uses: actions/checkout@v4 + - name: Download per-platform staging artifacts + uses: actions/download-artifact@v4 + with: + path: staging + pattern: staging-* + merge-multiple: true + - name: Package SwiftSyntax prebuilt archive + run: ./build.sh package + - name: Build & Publish SwiftSyntax prebuilt binary + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail - # Run the build and create the archive - SWIFT_SYNTAX_VERSION=${{ github.event.inputs.tag }} \ - RULES_SWIFT_VERSION=${{ env.RULES_SWIFT_VERSION }} \ - MACOS_VERSION=${{ env.MACOS_VERSION }} \ - BUILD_NUMBER=${{ github.event.inputs.build_number }} \ - ./build.sh + archive_name="swift-syntax-${RELEASE_TAG}" bzlmod_sha256=$(cat "${archive_name}.tar.gz.sha256") - # Make the release notes cat > release-notes.md <.tar.gz. +SWIFT_SYNTAX_VERSION=602.0.0 \ +RULES_SWIFT_VERSION=3.1.2 \ +TARGET_PLATFORM=macos-arm64 \ + ./build.sh build + +# Phase 2: combine all per-platform staging tarballs into the final release +# archive. Generates a BUILD.bazel that uses select() over (os, cpu) plus a +# top-level MODULE.bazel. +SWIFT_SYNTAX_VERSION=602.0.0 \ +RULES_SWIFT_VERSION=3.1.2 \ + ./build.sh package +``` + +The GitHub Actions workflows (`dry-run.yml`, `build-publish.yml`) wire these phases into a fan-out / fan-in pipeline: one build job per platform, then a single packaging job that downloads each platform's staging artifact and produces the released tarball. diff --git a/build.sh b/build.sh index d9f970b..eacf1b7 100755 --- a/build.sh +++ b/build.sh @@ -2,37 +2,321 @@ set -euo pipefail -# This script builds the SwiftSyntax prebuilt binaries and outputs the SHA256 checksum for the archive. -# NOTE: this script expects that the swift-syntax repository is checked out in the same directory as this script. +# Builds and packages the SwiftSyntax prebuilt archive in two phases so the +# work can fan out across heterogeneous CI runners: # -# Required environment variables: -# - SWIFT_SYNTAX_VERSION: The version of SwiftSyntax to build. -# - RULES_SWIFT_VERSION: The version of rules_swift to use for the archive MODULE.bazel file and override in the swift-syntax MODULE.bazel file. -# - MACOS_VERSION: The minimum macOS version to target. +# ./build.sh build Per-TARGET_PLATFORM. Emits staging/.tar.gz. +# ./build.sh package Combines all per-platform staging tarballs into the +# final release archive with a select()'d BUILD.bazel. # -# Optional environment variables: -# - APPLE_SUPPORT_VERSION: The version of apple_support to use to override in the swift-syntax MODULE.bazel file. -# - RULES_APPLE_VERSION: The version of rules_apple to use to override in the swift-syntax MODULE.bazel file. -# - BUILD_NUMBER: The build number to append to the release tag. +# Required env (build): SWIFT_SYNTAX_VERSION, RULES_SWIFT_VERSION, TARGET_PLATFORM +# Required env (package): SWIFT_SYNTAX_VERSION, RULES_SWIFT_VERSION +# Optional env: BUILD_NUMBER, APPLE_SUPPORT_VERSION, RULES_APPLE_VERSION, MACOS_VERSION +# +# Build phase expects apple/swift-syntax checked out at ./swift-syntax. -# Default values for optional environment variables. APPLE_SUPPORT_VERSION="${APPLE_SUPPORT_VERSION:-1.23.1}" RULES_APPLE_VERSION="${RULES_APPLE_VERSION:-4.2.0}" +MACOS_VERSION="${MACOS_VERSION:-13.0}" -# NOTE: required to workaround issues in macOS 26+ (https://github.com/bazelbuild/bazel/pull/27014) +# Workaround for https://github.com/bazelbuild/bazel/pull/27014 on macOS 26+. export USE_BAZEL_VERSION="${USE_BAZEL_VERSION:-8.4.2}" +mode="${1:-}" +case "$mode" in +build | package) ;; +*) + echo "usage: $0 " >&2 + exit 64 + ;; +esac + +if [ -z "${SWIFT_SYNTAX_VERSION:-}" ]; then + echo "error: SWIFT_SYNTAX_VERSION is required" >&2 + exit 64 +fi + +if [ -z "${RULES_SWIFT_VERSION:-}" ]; then + echo "error: RULES_SWIFT_VERSION is required" >&2 + exit 64 +fi + release_tag="$SWIFT_SYNTAX_VERSION" if [ -n "${BUILD_NUMBER:-}" ]; then release_tag="$release_tag+$BUILD_NUMBER" fi archive_name="swift-syntax-$release_tag" +staging_root="$PWD/staging" + +bazel_cpu_for_target() { + case "$1" in + macos-arm64) echo "darwin_arm64" ;; + macos-x86_64) echo "darwin_x86_64" ;; + linux-x86_64) echo "k8" ;; + linux-arm64) echo "aarch64" ;; + *) + echo "error: unsupported TARGET_PLATFORM '$1'" >&2 + exit 64 + ;; + esac +} + +os_family_for_target() { + case "$1" in + macos-*) echo "darwin" ;; + linux-*) echo "linux" ;; + *) + echo "error: unsupported TARGET_PLATFORM '$1'" >&2 + exit 64 + ;; + esac +} + +# Echoes the @platforms//os constraint name for a platform dir. The archive +# ships one slice per OS, so the generated select()s key on OS alone -- this +# matches any cpu within an OS (e.g. a macos_x86_64 target gets the macOS +# slice), mirroring the single-archive behavior consumers relied on before. +os_constraint_for_platform() { + case "$1" in + macos-*) echo "macos" ;; + linux-*) echo "linux" ;; + *) + echo "error: unsupported platform '$1'" >&2 + exit 64 + ;; + esac +} + +do_build() { + if [ -z "${TARGET_PLATFORM:-}" ]; then + echo "error: TARGET_PLATFORM is required for build mode" >&2 + exit 64 + fi + + local cpu os_family platform_dir + cpu=$(bazel_cpu_for_target "$TARGET_PLATFORM") + os_family=$(os_family_for_target "$TARGET_PLATFORM") + platform_dir="$staging_root/$TARGET_PLATFORM" + + rm -rf "$platform_dir" + mkdir -p "$platform_dir" + + pushd swift-syntax >/dev/null + + # Stash the upstream config; idempotent for repeat runs. + [ -f .bazelrc ] && mv .bazelrc .bazelrc.original + [ -f MODULE.bazel ] && mv MODULE.bazel MODULE.bazel.original + + cat >./MODULE.bazel <&2 + exit 1 + fi + local -a labels + labels=() + while IFS= read -r line; do + [ -z "$line" ] || labels+=("$line") + done <<<"$query_out" + + query_out=$(bazel query "kind(cc_library, //...)") + if [ -z "$query_out" ]; then + echo "error: query for cc_library targets returned no results" >&2 + exit 1 + fi + local -a c_deps + c_deps=() + while IFS= read -r line; do + [ -z "$line" ] || c_deps+=("$line") + done <<<"$query_out" + + # swift-corelibs-foundation isn't compiled with library evolution support, + # so swift_libraries that import Foundation (notably _SwiftSyntaxTestSupport) + # fail under `swift.enable_library_evolution` on Linux. Drop TestSupport + # from the Linux prebuilt; consumers needing it can build from source. + if [ "$os_family" = "linux" ]; then + local -a filtered_labels filtered_c_deps + filtered_labels=() + for label in "${labels[@]}"; do + case "$label" in + *TestSupport*) ;; + *) filtered_labels+=("$label") ;; + esac + done + labels=("${filtered_labels[@]}") + filtered_c_deps=() + for dep in "${c_deps[@]}"; do + case "$dep" in + *TestSupport*) ;; + *) filtered_c_deps+=("$dep") ;; + esac + done + c_deps=("${filtered_c_deps[@]}") + fi + + # Build swift_library and cc_library targets separately; combining them + # exposes a transition mismatch where cc_library outputs land under iOS + # configs inherited from upstream's ios_unit_test rules. + bazel build "${labels[@]}" "${build_flags[@]}" + bazel build "${c_deps[@]}" "${build_flags[@]}" + + local meta_file="$platform_dir/_targets.tsv" + : >"$meta_file" + local label non_opt_label module_name dependencies + for label in "${labels[@]}"; do + non_opt_label="${label%_opt}" + module_name=$(buildozer "print name" "$non_opt_label") + dependencies=$(buildozer "print deps" "$non_opt_label" | sed 's/^\[//' | sed 's/\]$//') + if [ "$dependencies" = "(missing)" ]; then + dependencies="" + fi + printf 'swift_import\t%s\t%s\n' "$module_name" "$dependencies" >>"$meta_file" + done + + # `cquery --output=files` lists files for every config a target appears in, + # including iOS transitions from upstream's ios_unit_test / ios_xctestrun_runner; + # those paths are never produced by our `bazel build` above, so skip them. + local outputs output + outputs=$(bazel cquery "set(${labels[*]})" --output=files "${build_flags[@]}") + outputs+=$'\n'$(bazel cquery "set(${c_deps[*]})" --output=files "${build_flags[@]}") + for output in $outputs; do + [ -f "$output" ] || continue + case "$output" in + # Drop the position-independent variant Linux toolchains emit alongside + # `libX.a`; we only need the static archive for consumer linking. + *.pic.a) ;; + *.swiftinterface | *.a | *.swiftdoc) + cp -R "$output" "$platform_dir/$(basename "$output")" + ;; + esac + done + + # Same cquery feeds the metadata row and the staged include/ tree. + local hdrs_dir="$platform_dir/_headers" + rm -rf "$hdrs_dir" + local dep name hdr hdr_path target_hdrs_dir + for dep in "${c_deps[@]}"; do + name=$(buildozer "print name" "$dep") + local -a hdrs=() + while IFS= read -r hdr; do + [ -z "$hdr" ] || hdrs+=("$hdr") + done < <(bazel cquery "$dep" --output=jsonproto "${build_flags[@]}" | + jq -rc '.results[0].target.rule.attribute[] | select(.name == "hdrs").stringListValue | .[]?') + + printf 'cc_import\t%s\t%s\n' "$name" "${hdrs[*]}" >>"$meta_file" + + if [ "${#hdrs[@]}" -gt 0 ]; then + target_hdrs_dir="$hdrs_dir/$name/include" + mkdir -p "$target_hdrs_dir" + for hdr in "${hdrs[@]}"; do + hdr_path="${hdr#//:}" + cp "$hdr_path" "$target_hdrs_dir/$(basename "$hdr_path")" + done + fi + done + + popd >/dev/null + + # Fail fast if nothing landed; an empty staging tar breaks the package + # phase in confusing ways downstream. + if ! find "$platform_dir" -maxdepth 1 -type f \ + \( -name '*.a' -o -name '*.swiftinterface' -o -name '*.swiftdoc' \) \ + | grep -q .; then + echo "error: no .a / .swiftinterface / .swiftdoc outputs landed in $platform_dir" >&2 + exit 1 + fi + + local platform_tar="$staging_root/${TARGET_PLATFORM}.tar.gz" + tar -czf "$platform_tar" -C "$staging_root" "$TARGET_PLATFORM" + echo "build: wrote $platform_tar" +} + +# Echoes a Starlark `select({...})` mapping each platform to /. +# kind "list" wraps each value in [] (list attrs like swift_import.archives); +# kind "scalar" emits a bare string (single-label attrs like swiftdoc, +# swiftinterface, cc_import.static_library). +emit_select_for_basename() { + local kind="$1" basename="$2" + shift 2 + local plat os + printf 'select({\n' + for plat in "$@"; do + os=$(os_constraint_for_platform "$plat") + if [ "$kind" = "list" ]; then + printf ' "@platforms//os:%s": ["%s/%s"],\n' "$os" "$plat" "$basename" + else + printf ' "@platforms//os:%s": "%s/%s",\n' "$os" "$plat" "$basename" + fi + done + printf ' })' +} + +do_package() { + if [ ! -d "$staging_root" ]; then + echo "error: $staging_root not found; run './build.sh build' on each TARGET_PLATFORM first" >&2 + exit 64 + fi + + local tar_file platform + for tar_file in "$staging_root"/*.tar.gz; do + [ -e "$tar_file" ] || continue + platform=$(basename "$tar_file" .tar.gz) + if [ ! -d "$staging_root/$platform" ]; then + tar -xzf "$tar_file" -C "$staging_root" + fi + done + + local -a platforms + platforms=() + while IFS= read -r dir; do + [ -z "$dir" ] && continue + platforms+=("$(basename "$dir")") + done < <(find "$staging_root" -mindepth 1 -maxdepth 1 -type d | sort) + if [ ${#platforms[@]} -eq 0 ]; then + echo "error: no per-platform staging directories found in $staging_root" >&2 + exit 64 + fi -mkdir -p "$archive_name" + # Dep graph is platform-invariant; any platform's manifest works. + local meta_file="$staging_root/${platforms[0]}/_targets.tsv" + if [ ! -f "$meta_file" ]; then + echo "error: missing metadata file $meta_file" >&2 + exit 64 + fi -# Create the MODULE.bazel file which will be used to include SwiftSyntax as a bazel_dep via archive_override. -cat >"$archive_name/MODULE.bazel" <"$archive_name/MODULE.bazel" <"$archive_name/BUILD.bazel" <"$archive_name/BUILD.bazel" <<'EOF' load("@build_bazel_rules_swift//swift:swift.bzl", "swift_import") load("@rules_cc//cc:cc_import.bzl", "cc_import") -EOF - -# -- start swift-syntax build -- -pushd swift-syntax -# Move the .bazelrc and MODULE.bazel files as we set our own versions and build flags in this script. -mv .bazelrc .bazelrc.original -mv MODULE.bazel MODULE.bazel.original - -# Create our own `MODULE.bazel` file to override the versions defined in swift-syntax. -cat >"./MODULE.bazel" </dev/null 2>&1 - buildozer "set module_name \"${module_name}\"" //:${module_name} >/dev/null 2>&1 - buildozer "set visibility \"//visibility:public\"" //:${module_name} >/dev/null 2>&1 - buildozer "set archives \"lib${module_name}.a\"" //:${module_name} >/dev/null 2>&1 - buildozer "set swiftdoc \"${module_name}.swiftdoc\"" //:${module_name} >/dev/null 2>&1 - buildozer "set swiftinterface \"${module_name}.swiftinterface\"" //:${module_name} >/dev/null 2>&1 - - if [ -n "$dependencies" ]; then - buildozer "set deps ${dependencies[*]}" //:${module_name} >/dev/null 2>&1 - fi - - # Create the alias `_opt` for the `swift_import` target that is used by some other modules. - # Since these are prebuilt in a release configuration, they are always in "opt" mode. - buildozer "new alias ${module_name}_opt" //:__pkg__ >/dev/null 2>&1 - buildozer "set actual :${module_name}" //:${module_name}_opt >/dev/null 2>&1 - buildozer "set visibility \"//visibility:public\"" //:${module_name}_opt >/dev/null 2>&1 - - popd -done - -# Create the `cc_import` targets for each of the support targets. -for dep in ${c_deps[@]}; do - name="$(buildozer "print name" ${dep})" - hdrs=() - while read -r hdr; do - hdrs+=("$hdr") - done < <(bazel cquery "${dep}" --output=jsonproto | jq -rc '.results[0].target.rule.attribute[] | select(.name == "hdrs").stringListValue | .[]') - - # Copy any headers to the archive directory and set the header path relative to the archive directory. - hdrs_base_path="${name}/include" - hdrs_dir="../$archive_name/${hdrs_base_path}" - if [ ${#hdrs[@]} -gt 0 ]; then - mkdir -p "$hdrs_dir" - for i in "${!hdrs[@]}"; do - hdrs[$i]=${hdrs[$i]#//:} - header_name=$(basename "${hdrs[$i]}") - cp "${hdrs[$i]}" "${hdrs_dir}/${header_name}" - hdrs[$i]="${hdrs_base_path}/${header_name}" - done - fi - - echo -e "\nGenerating BUILD file content for support target: $dep" - echo -e "\tName: $name" - echo -e "\tHeaders count: ${#hdrs[@]}" - - pushd "../$archive_name" - buildozer "new cc_import ${name}" //:__pkg__ >/dev/null 2>&1 - buildozer "set visibility \"//visibility:public\"" "${dep}" >/dev/null 2>&1 - buildozer "set static_library \"lib${name}.a\"" "${dep}" >/dev/null 2>&1 - if [ ${#hdrs[@]} -gt 0 ]; then - buildozer "set hdrs glob([\"${hdrs_base_path}/*.h\"])" "${dep}" >/dev/null 2>&1 - fi - popd -done - -# Build each of the Swift library targets. -outputs=$(bazel cquery "set(${labels[@]})" --output=files "${build_flags[@]}") -bazel build "${labels[@]}" "${build_flags[@]}" -# Copy the build product files to the archive directory. -for output in $outputs; do - if [[ $output == *.swiftinterface || $output == *.a || $output == *.swiftdoc ]]; then - output_name=$(basename "$output") - cp -R "$output" "../${archive_name}/${output_name}" - fi -done - -# Build the support targets. -outputs=$(bazel cquery "set(${c_deps[@]})" --output=files "${build_flags[@]}") -bazel build "${c_deps[@]}" "${build_flags[@]}" -# Copy the build product files to the archive directory. -for output in $outputs; do - if [[ -f "$output" ]]; then - output_name=$(basename "$output") - cp -R "$output" "../${archive_name}/${output_name}" - fi -done - -popd -# -- end swift-syntax build -- - -# Package the outputs into a tarball. -tar -czf "${archive_name}.tar.gz" "$archive_name" - -# Generate the expected sha256 checksum for the tarball. -openssl dgst -sha256 -binary "${archive_name}.tar.gz" | openssl base64 -A | sed 's/^/sha256-/' >"${archive_name}.tar.gz.sha256" -sha256_checksum=$(cat "${archive_name}.tar.gz.sha256") - -echo "Dry-run completed successfully, SHA256 checksum for the archive is: $sha256_checksum" + local kind name deps + while IFS=$'\t' read -r kind name deps; do + case "$kind" in + swift_import) + { + printf '\nswift_import(\n' + printf ' name = "%s",\n' "$name" + printf ' module_name = "%s",\n' "$name" + printf ' archives = ' + emit_select_for_basename list "lib${name}.a" "${platforms[@]}" + printf ',\n' + printf ' swiftdoc = ' + emit_select_for_basename scalar "${name}.swiftdoc" "${platforms[@]}" + printf ',\n' + printf ' swiftinterface = ' + emit_select_for_basename scalar "${name}.swiftinterface" "${platforms[@]}" + printf ',\n' + if [ -n "$deps" ]; then + # buildozer emits bare, space-separated labels (`:X :Y`); convert + # to Starlark string list (`":X", ":Y"`). + local quoted_deps + # shellcheck disable=SC2086 # intentional word split on $deps + quoted_deps=$(printf '"%s", ' $deps) + quoted_deps=${quoted_deps%, } + printf ' deps = [%s],\n' "$quoted_deps" + fi + printf ' visibility = ["//visibility:public"],\n' + printf ')\n' + printf '\nalias(\n name = "%s_opt",\n actual = ":%s",\n visibility = ["//visibility:public"],\n)\n' "$name" "$name" + } >>"$archive_name/BUILD.bazel" + ;; + cc_import) + # Headers are platform-agnostic; merge once at archive root. + local src_hdrs="$staging_root/${platforms[0]}/_headers/$name/include" + if [ -d "$src_hdrs" ]; then + mkdir -p "$archive_name/$name/include" + cp -R "$src_hdrs/." "$archive_name/$name/include/" + fi + { + printf '\ncc_import(\n' + printf ' name = "%s",\n' "$name" + printf ' static_library = ' + emit_select_for_basename scalar "lib${name}.a" "${platforms[@]}" + printf ',\n' + if [ -d "$src_hdrs" ]; then + printf ' hdrs = glob(["%s/include/*.h"]),\n' "$name" + fi + printf ' visibility = ["//visibility:public"],\n' + printf ')\n' + } >>"$archive_name/BUILD.bazel" + ;; + esac + done <"$meta_file" + + local plat + for plat in "${platforms[@]}"; do + mkdir -p "$archive_name/$plat" + find "$staging_root/$plat" -maxdepth 1 -type f \ + \( -name '*.a' -o -name '*.swiftinterface' -o -name '*.swiftdoc' \) \ + -exec cp {} "$archive_name/$plat/" \; + done + + tar -czf "${archive_name}.tar.gz" "$archive_name" + + openssl dgst -sha256 -binary "${archive_name}.tar.gz" | + openssl base64 -A | + sed 's/^/sha256-/' >"${archive_name}.tar.gz.sha256" + local sha256_checksum + sha256_checksum=$(cat "${archive_name}.tar.gz.sha256") + + echo "package: wrote ${archive_name}.tar.gz (${sha256_checksum}) covering platforms: ${platforms[*]}" +} + +case "$mode" in +build) do_build ;; +package) do_package ;; +esac