Skip to content

Commit 1d96e69

Browse files
alwxclaude
andcommitted
chore(ios): Address itaybre review comments
- sentry_utils.rb: replace system('curl',…) with URI.open from stdlib open-uri. Same net behavior, no shell escaping to worry about, pure Ruby. - sentry_utils.rb + RNSentry.podspec: drop the runtime slice-enumeration helpers. Sentry.xcframework's layout has been stable across releases, so hardcode the slice → SDK map into a frozen constant (SENTRY_XCFRAMEWORK_SLICES_BY_SDK) and iterate it directly in the podspec. Less code, no filesystem scan on every pod install. If sentry-cocoa ever ships a new platform slice, add a line to the constant. - scripts/update-cocoa.sh: extend set-version to also refresh the Sentry.xcframework.zip SHA256 checksum in sentry_utils.rb. Before this, bumping sentry-cocoa required editing the checksum by hand — a silent recipe for typos that would break every user's pod install with a checksum-mismatch error. Now the script downloads the new archive, computes SHA256, and rewrites both the version key and the Sentry value in place with a sanity-check. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 83a6fcc commit 1d96e69

3 files changed

Lines changed: 87 additions & 70 deletions

File tree

packages/core/RNSentry.podspec

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,12 @@ Pod::Spec.new do |s|
110110
# SDK selector so `#import <Sentry/…>` resolves against exactly one
111111
# slice per build. An unconditional search-path list would let Xcode's
112112
# Swift module precompiler stumble into a slice for a different arch
113-
# and fail with "unsupported Swift architecture". New slices in future
114-
# sentry-cocoa releases are picked up automatically at pod-install.
113+
# and fail with "unsupported Swift architecture".
114+
#
115+
# We hardcode the slice → SDK map in `SENTRY_XCFRAMEWORK_SLICES_BY_SDK`
116+
# (see `sentry_utils.rb`) rather than scanning the extracted bundle —
117+
# sentry-cocoa's `Sentry.xcframework` layout is stable across releases.
118+
# Add a slice there if a future release ships one.
115119
#
116120
# Point the search paths at the pod-install-time absolute path to the
117121
# xcframework. `${PODS_TARGET_SRCROOT}` is only defined in per-pod
@@ -121,13 +125,9 @@ Pod::Spec.new do |s|
121125
# different depth from RNSentryCocoaTester). Using the absolute path
122126
# avoids the layout-detection dance — the path is regenerated on
123127
# every `pod install`, so it's not something anyone commits.
124-
xcframework_search_paths = {}
125-
sentry_xcframework_slices_by_sdk(sentry_xcframework_dir).each do |sdk, slice_ids|
126-
paths = slice_ids.map do |slice|
127-
%("#{File.join(sentry_xcframework_dir, slice)}")
128-
end
129-
xcframework_search_paths["FRAMEWORK_SEARCH_PATHS[sdk=#{sdk}*]"] =
130-
(['$(inherited)'] + paths).join(' ')
128+
xcframework_search_paths = SENTRY_XCFRAMEWORK_SLICES_BY_SDK.each_with_object({}) do |(sdk, slice_ids), acc|
129+
paths = slice_ids.map { |slice| %("#{File.join(sentry_xcframework_dir, slice)}") }
130+
acc["FRAMEWORK_SEARCH_PATHS[sdk=#{sdk}*]"] = (['$(inherited)'] + paths).join(' ')
131131
end
132132

133133
pod_target_xcconfig.merge!(xcframework_search_paths)

packages/core/scripts/sentry_utils.rb

Lines changed: 36 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,46 @@ def is_new_hermes_runtime(rn_version)
4343

4444
require 'digest'
4545
require 'fileutils'
46+
require 'open-uri'
4647

4748
# SHA256 checksums of `<product>.xcframework.zip` assets published in
4849
# sentry-cocoa GitHub releases (same value as the SPM binary target checksum
4950
# in sentry-cocoa's `Package.swift`). Register the checksum for each
5051
# sentry-cocoa version we ship a prebuilt xcframework for.
52+
#
53+
# Kept in sync with `sentry_cocoa_version` in `RNSentry.podspec` by
54+
# `scripts/update-cocoa.sh set-version <new>`, which downloads the new
55+
# release archive, computes its SHA256, and rewrites the entry below.
5156
SENTRY_COCOA_XCFRAMEWORK_CHECKSUMS = {
57+
# `Sentry.xcframework.zip` — the static product. Its enclosing xcframework
58+
# name matches the framework name inside (both `Sentry`), which CocoaPods
59+
# requires to generate `-framework Sentry` correctly and to resolve the
60+
# `Sentry` module. `Sentry-Dynamic.xcframework` would ship the same
61+
# `Sentry.framework` inside but under a mismatched enclosing name, so
62+
# CocoaPods generates `-framework Sentry-Dynamic` and fails at link.
5263
'9.19.1' => {
53-
# `Sentry.xcframework.zip` — the static product. Its enclosing xcframework
54-
# name matches the framework name inside (both `Sentry`), which CocoaPods
55-
# requires to generate `-framework Sentry` correctly and to resolve the
56-
# `Sentry` module. `Sentry-Dynamic.xcframework` would ship the same
57-
# `Sentry.framework` inside but under a mismatched enclosing name, so
58-
# CocoaPods generates `-framework Sentry-Dynamic` and fails at link.
5964
'Sentry' => 'd6d545af17e49851cda2747b0f45cde78ce08ea37709dde5a956c6b4671224e8',
6065
},
6166
}.freeze
6267

68+
# Static map from xcframework slice directory name to the Xcode SDK selector
69+
# it should be attached to. `sentry-cocoa`'s `Sentry.xcframework` layout is
70+
# stable across releases — same slice names come out of every build — so we
71+
# hardcode the mapping rather than scanning the extracted bundle. Add a
72+
# new entry here if `sentry-cocoa` ever ships a new platform slice.
73+
SENTRY_XCFRAMEWORK_SLICES_BY_SDK = {
74+
'iphoneos' => %w[ios-arm64_arm64e],
75+
'iphonesimulator' => %w[ios-arm64_x86_64-simulator],
76+
'maccatalyst' => %w[ios-arm64_arm64e_x86_64-maccatalyst],
77+
'macosx' => %w[macos-arm64_arm64e_x86_64],
78+
'appletvos' => %w[tvos-arm64_arm64e],
79+
'appletvsimulator' => %w[tvos-arm64_x86_64-simulator],
80+
'watchos' => %w[watchos-arm64_arm64_32_arm64e_armv7k],
81+
'watchsimulator' => %w[watchos-arm64_x86_64-simulator],
82+
'xros' => %w[xros-arm64_arm64e],
83+
'xrsimulator' => %w[xros-arm64_x86_64-simulator],
84+
}.freeze
85+
6386
# Ensures `<sdk_root>/ios/Vendor/<product>.xcframework` exists.
6487
#
6588
# On first invocation, downloads the prebuilt xcframework zip from
@@ -96,8 +119,13 @@ def ensure_sentry_xcframework(version, product = 'Sentry')
96119
"#{version}/#{product}.xcframework.zip"
97120

98121
Pod::UI.puts "[Sentry] Downloading #{product} #{version} from GitHub Releases…" if defined?(Pod::UI)
99-
unless system('curl', '-sSfL', '-o', zip_path, url)
100-
raise "Failed to download #{url}"
122+
begin
123+
URI.open(url, redirect: true) do |remote|
124+
File.open(zip_path, 'wb') { |f| IO.copy_stream(remote, f) }
125+
end
126+
rescue OpenURI::HTTPError, SocketError, StandardError => e
127+
FileUtils.rm_f(zip_path)
128+
raise "Failed to download #{url}: #{e.class}: #{e.message}"
101129
end
102130

103131
actual_checksum = Digest::SHA256.file(zip_path).hexdigest
@@ -125,50 +153,3 @@ def ensure_sentry_xcframework(version, product = 'Sentry')
125153
target_dir
126154
end
127155

128-
# Returns a hash of `<xcconfig SDK name> => [slice_id, ...]` for the slice
129-
# directories inside an xcframework bundle.
130-
#
131-
# Xcode's `-F <dir>` does not descend into an `.xcframework` bundle at
132-
# search-path lookup time — it only sees `Sentry.xcframework` as a directory
133-
# and doesn't find `Sentry.framework` inside. Callers use these groupings
134-
# to emit SDK-conditional `FRAMEWORK_SEARCH_PATHS[sdk=…*]` xcconfig entries
135-
# so each SDK build only sees its own slice — putting all slices under a
136-
# single unconditional search path lets Xcode's Swift module precompiler
137-
# stumble into an incompatible slice and fail with
138-
# "unsupported Swift architecture".
139-
#
140-
# Slice-name convention is stable across the xcframeworks Apple has ever
141-
# published:
142-
# ios-*-simulator -> iphonesimulator
143-
# ios-*-maccatalyst -> maccatalyst
144-
# ios-… -> iphoneos
145-
# tvos-*-simulator -> appletvsimulator
146-
# tvos-… -> appletvos
147-
# watchos-*-simulator -> watchsimulator
148-
# watchos-… -> watchos
149-
# xros-*-simulator -> xrsimulator
150-
# xros-… -> xros
151-
# macos-… -> macosx
152-
def sentry_xcframework_slices_by_sdk(xcframework_dir)
153-
slice_ids = Dir.children(xcframework_dir).select do |name|
154-
File.directory?(File.join(xcframework_dir, name)) && name != '_CodeSignature'
155-
end.sort
156-
157-
slice_ids.each_with_object({}) do |slice, groups|
158-
sdk = _sentry_sdk_for_slice(slice)
159-
next unless sdk # unknown platform prefix — skip rather than mis-attach
160-
(groups[sdk] ||= []) << slice
161-
end
162-
end
163-
164-
def _sentry_sdk_for_slice(slice_id)
165-
return 'maccatalyst' if slice_id.include?('-maccatalyst')
166-
simulator = slice_id.end_with?('-simulator')
167-
case
168-
when slice_id.start_with?('ios-') then simulator ? 'iphonesimulator' : 'iphoneos'
169-
when slice_id.start_with?('tvos-') then simulator ? 'appletvsimulator' : 'appletvos'
170-
when slice_id.start_with?('watchos-') then simulator ? 'watchsimulator' : 'watchos'
171-
when slice_id.start_with?('xros-') then simulator ? 'xrsimulator' : 'xros'
172-
when slice_id.start_with?('macos-') then 'macosx'
173-
end
174-
end

scripts/update-cocoa.sh

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,60 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
file="$(dirname "$0")/../packages/core/RNSentry.podspec"
5-
content=$(cat $file)
4+
script_dir="$(cd "$(dirname "$0")" && pwd)"
5+
podspec="$script_dir/../packages/core/RNSentry.podspec"
6+
utils="$script_dir/../packages/core/scripts/sentry_utils.rb"
7+
8+
content=$(cat "$podspec")
69
regex="(sentry_cocoa_version *= *)'([0-9\.]+)'"
710
if ! [[ $content =~ $regex ]]; then
8-
echo "Failed to find the plugin version in $file"
11+
echo "Failed to find the plugin version in $podspec"
912
exit 1
1013
fi
1114

1215
case $1 in
1316
get-version)
14-
echo ${BASH_REMATCH[2]}
17+
echo "${BASH_REMATCH[2]}"
1518
;;
1619
get-repo)
1720
echo "https://github.com/getsentry/sentry-cocoa.git"
1821
;;
1922
set-version)
20-
newValue="${BASH_REMATCH[1]}'$2'"
21-
echo "${content/${BASH_REMATCH[0]}/$newValue}" >$file
23+
new_version="$2"
24+
25+
# 1. Update `sentry_cocoa_version` in the podspec.
26+
newValue="${BASH_REMATCH[1]}'$new_version'"
27+
printf '%s\n' "${content/${BASH_REMATCH[0]}/$newValue}" >"$podspec"
28+
29+
# 2. Refresh the `Sentry.xcframework.zip` SHA256 checksum in
30+
# `sentry_utils.rb`. The checksum table has a single version key
31+
# that we rewrite in place — download the new archive, compute
32+
# its SHA256, then patch the version key and the `'Sentry'` line.
33+
# `pod install` verifies against this checksum on every fresh
34+
# install so a stale value here breaks every user's build with a
35+
# loud mismatch error rather than a silent corruption.
36+
zip_url="https://github.com/getsentry/sentry-cocoa/releases/download/${new_version}/Sentry.xcframework.zip"
37+
tmp_dir=$(mktemp -d)
38+
trap 'rm -rf "$tmp_dir"' EXIT
39+
echo "Fetching ${zip_url}..."
40+
curl -fsSL --retry 3 -o "$tmp_dir/Sentry.xcframework.zip" "$zip_url"
41+
new_sha=$(shasum -a 256 "$tmp_dir/Sentry.xcframework.zip" | awk '{print $1}')
42+
echo "Sentry.xcframework.zip SHA256: ${new_sha}"
43+
44+
# Update the version key (any semver-shaped key opening the hash).
45+
perl -i -pe "s|'\\d+\\.\\d+\\.\\d+' => \\{|'${new_version}' => {|" "$utils"
46+
# Update the `Sentry` checksum (a 64-char lowercase hex string).
47+
perl -i -pe "s|'Sentry' => '[a-f0-9]{64}'|'Sentry' => '${new_sha}'|" "$utils"
48+
49+
# Sanity-check: both lines got rewritten with the new values.
50+
if ! grep -q "'${new_version}' =>" "$utils"; then
51+
echo "Failed to rewrite the checksum version key in $utils"
52+
exit 1
53+
fi
54+
if ! grep -q "'Sentry' => '${new_sha}'" "$utils"; then
55+
echo "Failed to rewrite the Sentry checksum in $utils"
56+
exit 1
57+
fi
2258
;;
2359
*)
2460
echo "Unknown argument $1"

0 commit comments

Comments
 (0)