diff --git a/CHANGELOG.md b/CHANGELOG.md index a9e708fddb..ffd75a5626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ > make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first. +## Unreleased + +### Fixes + +- Make the `RNSentry` SPEC CHECKSUM in `Podfile.lock` machine-independent ([#6474](https://github.com/getsentry/sentry-react-native/pull/6474)) + + The prebuilt `Sentry.xcframework` is now referenced through a `$(PODS_ROOT)/sentry-xcframeworks/…` symlink instead of the absolute per-user cache path, so `Podfile.lock` no longer churns between developers and CI. Expect a one-time `RNSentry` checksum change on the next `pod install`; the `SENTRY_XCFRAMEWORK_CACHE_DIR=/tmp/…` workaround is no longer needed. + ## 8.19.0 ### Features diff --git a/packages/core/RNSentry.podspec b/packages/core/RNSentry.podspec index 0b6ee4e414..7285b21721 100644 --- a/packages/core/RNSentry.podspec +++ b/packages/core/RNSentry.podspec @@ -122,16 +122,24 @@ Pod::Spec.new do |s| # sentry-cocoa's `Sentry.xcframework` layout is stable across releases. # Add a slice there if a future release ships one. # - # Point the search paths at the pod-install-time absolute path to the - # xcframework. `${PODS_TARGET_SRCROOT}` is only defined in per-pod - # xcconfigs, not in aggregate/user-target xcconfigs, and a - # `${PODS_ROOT}`-relative fallback works for one Podfile layout but - # breaks for another (e.g. the RN sample apps put node_modules at a - # different depth from RNSentryCocoaTester). Using the absolute path - # avoids the layout-detection dance — the path is regenerated on - # every `pod install`, so it's not something anyone commits. + # Reference the xcframework through a `Pods/sentry-xcframeworks/…` + # symlink so the search paths are machine-independent (see + # `stage_sentry_xcframework_in_pods`) — the values below feed the + # `RNSentry` SPEC CHECKSUM in `Podfile.lock`, so an absolute + # `~/Library/Caches/…` path here made the lockfile churn between + # machines (#6467). `${PODS_TARGET_SRCROOT}` can't be used instead: it + # is only defined in per-pod xcconfigs, not in aggregate/user-target + # xcconfigs, and a `${PODS_ROOT}`-relative path to node_modules works + # for one Podfile layout but breaks for another (e.g. the RN sample + # apps put node_modules at a different depth from RNSentryCocoaTester). + # If the symlink can't be created, fall back to the absolute + # pod-install-time path — functional, but with a machine-specific + # checksum. + sentry_xcframework_ref = + stage_sentry_xcframework_in_pods(sentry_xcframework_dir, sentry_cocoa_version, 'Sentry') || + sentry_xcframework_dir xcframework_search_paths = SENTRY_XCFRAMEWORK_SLICES_BY_SDK.each_with_object({}) do |(sdk, slice_ids), acc| - paths = slice_ids.map { |slice| %("#{File.join(sentry_xcframework_dir, slice)}") } + paths = slice_ids.map { |slice| %("#{File.join(sentry_xcframework_ref, slice)}") } acc["FRAMEWORK_SEARCH_PATHS[sdk=#{sdk}*]"] = (['$(inherited)'] + paths).join(' ') end diff --git a/packages/core/scripts/sentry_utils.rb b/packages/core/scripts/sentry_utils.rb index 43a778c019..90c535556a 100644 --- a/packages/core/scripts/sentry_utils.rb +++ b/packages/core/scripts/sentry_utils.rb @@ -165,3 +165,52 @@ def ensure_sentry_xcframework(version, product = 'Sentry') target_dir end +# Stage the cached xcframework behind a machine-independent `$(PODS_ROOT)` +# reference. +# +# Everything assigned to `pod_target_xcconfig`/`user_target_xcconfig` is part +# of the evaluated spec, and CocoaPods derives the pod's `SPEC CHECKSUM` in +# `Podfile.lock` from exactly that evaluated spec. Pointing +# `FRAMEWORK_SEARCH_PATHS` at the per-user cache directory +# (`~/Library/Caches/…`) therefore leaked `$HOME` into the checksum: two +# machines installing the same SDK version produced different `RNSentry` +# checksums and `Podfile.lock` churned on every `pod install` (#6467). +# +# Instead, symlink `Pods/sentry-xcframeworks//.xcframework` +# to the cached bundle and reference it as +# `$(PODS_ROOT)/sentry-xcframeworks/…` — a string that is identical on every +# machine (including ones overriding `SENTRY_XCFRAMEWORK_CACHE_DIR`). +# `$(PODS_ROOT)` is defined by CocoaPods in both the per-pod and the +# user/aggregate xcconfigs, unlike `$(PODS_TARGET_SRCROOT)`, and the link +# lives inside `Pods/` so no Podfile-layout detection is needed. +# +# Returns the `$(PODS_ROOT)`-based path, or nil when the symlink cannot be +# created — callers should fall back to the absolute cache path (previous +# behaviour, functional but with a machine-specific checksum). +def stage_sentry_xcframework_in_pods(xcframework_dir, version, product = 'Sentry') + pods_root = if defined?(Pod::Config) && Pod::Config.instance.respond_to?(:sandbox_root) + Pod::Config.instance.sandbox_root.to_s + else + File.join(Dir.pwd, 'Pods') + end + staging_dir = File.join(pods_root, 'sentry-xcframeworks', version) + link_path = File.join(staging_dir, "#{product}.xcframework") + + FileUtils.mkdir_p(staging_dir) + # Recreate the link when it's missing or points at a stale location + # (e.g. `SENTRY_XCFRAMEWORK_CACHE_DIR` changed between installs). + unless File.symlink?(link_path) && File.readlink(link_path) == xcframework_dir + FileUtils.rm_rf(link_path) + File.symlink(xcframework_dir, link_path) + end + + "$(PODS_ROOT)/sentry-xcframeworks/#{version}/#{product}.xcframework" +rescue StandardError, NotImplementedError => e + if defined?(Pod::UI) + Pod::UI.warn "[Sentry] Could not link the #{product} xcframework into Pods/ " \ + "(#{e.class}: #{e.message}). Falling back to the absolute cache path; " \ + "the RNSentry checksum in Podfile.lock will be machine-specific." + end + nil +end +