diff --git a/.github/scripts/nitroSQLiteDatabaseLocation/HybridNitroSQLite.hpp b/.github/scripts/nitroSQLiteDatabaseLocation/HybridNitroSQLite.hpp new file mode 100644 index 000000000000..b3d59db537e3 --- /dev/null +++ b/.github/scripts/nitroSQLiteDatabaseLocation/HybridNitroSQLite.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +// OnLoad.mm only needs these storage paths from the HybridObject implementation. +namespace margelo::nitro::rnnitrosqlite { +class HybridNitroSQLite { +public: + static inline std::string docPath; + static inline std::string migrationDocPath; +}; +} // namespace margelo::nitro::rnnitrosqlite diff --git a/.github/scripts/nitroSQLiteDatabaseLocation/RNNitroSQLite-Swift-Cxx-Umbrella.hpp b/.github/scripts/nitroSQLiteDatabaseLocation/RNNitroSQLite-Swift-Cxx-Umbrella.hpp new file mode 100644 index 000000000000..f045b8704496 --- /dev/null +++ b/.github/scripts/nitroSQLiteDatabaseLocation/RNNitroSQLite-Swift-Cxx-Umbrella.hpp @@ -0,0 +1,3 @@ +#pragma once + +// The directory selector does not call any generated Swift bindings. diff --git a/.github/scripts/nitroSQLiteDatabaseLocation/verifyLocation.mm b/.github/scripts/nitroSQLiteDatabaseLocation/verifyLocation.mm new file mode 100644 index 000000000000..a0e64aff914a --- /dev/null +++ b/.github/scripts/nitroSQLiteDatabaseLocation/verifyLocation.mm @@ -0,0 +1,28 @@ +#import +#import +#include + +// Execute the iOS branch on the existing macOS CI runner. NitroSQLite's macOS +// default can differ from iOS and must not conceal a broken iOS plist setting. +#undef TARGET_OS_OSX +#define TARGET_OS_OSX 0 +#import NITRO_SQLITE_ONLOAD_PATH + +using margelo::nitro::rnnitrosqlite::HybridNitroSQLite; + +int main() { + @autoreleasepool { + // Given the host plist, when the installed native library runs +load. + NSString *expectedDirectory = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES).firstObject; + NSString *actualDirectory = [NSString stringWithUTF8String:HybridNitroSQLite::docPath.c_str()]; + // Then its database directory must remain Application Support. + if (actualDirectory == nil || ![actualDirectory.stringByResolvingSymlinksInPath isEqualToString:expectedDirectory.stringByResolvingSymlinksInPath]) { + fprintf(stderr, "NitroSQLite selected %s instead of Application Support. Check the installed dependency and the host plist.\n", + HybridNitroSQLite::docPath.c_str()); + return 1; + } + + puts("Native database location is Application Support."); + return 0; + } +} diff --git a/.github/scripts/verifyNitroSQLiteDatabaseLocation.sh b/.github/scripts/verifyNitroSQLiteDatabaseLocation.sh new file mode 100644 index 000000000000..37d8d851a1db --- /dev/null +++ b/.github/scripts/verifyNitroSQLiteDatabaseLocation.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +TEST_DIR="$ROOT_DIR/.github/scripts/nitroSQLiteDatabaseLocation" +NITRO_SQLITE_DIR="${NITRO_SQLITE_DIR:-$ROOT_DIR/node_modules/react-native-nitro-sqlite}" +WORK_DIR="$(mktemp -d)" +trap 'rm -rf "$WORK_DIR"' EXIT + +# Run the installed iOS directory selector, rather than copying its plist logic. +# Only the bridge headers are replaced; the native selector runs unchanged. +xcrun clang++ -std=c++20 -fobjc-arc -framework Foundation \ + -I "$TEST_DIR" \ + -DNITRO_SQLITE_ONLOAD_PATH="\"$NITRO_SQLITE_DIR/ios/OnLoad.mm\"" \ + "$TEST_DIR/verifyLocation.mm" -o "$WORK_DIR/verifyLocation" + +PLISTS=( + "$ROOT_DIR/ios/NewExpensify/Info.plist" +) +if [[ "$#" -gt 0 ]]; then + PLISTS=("$@") +fi + +for PLIST in "${PLISTS[@]}"; do + # Each plist runs in a fresh process because NitroSQLite selects its directory + # in Objective-C +load, before main() and before Onyx opens the database. + APP_DIR="$WORK_DIR/DatabaseLocation.app" + mkdir -p "$APP_DIR/Contents/MacOS" + cp "$WORK_DIR/verifyLocation" "$APP_DIR/Contents/MacOS/verifyLocation" + python3 - "$PLIST" "$APP_DIR/Contents/Info.plist" <<'PY' +import plistlib +import sys +from pathlib import Path + +info = plistlib.loads(Path(sys.argv[1]).read_bytes()) +# Bundle metadata contains build substitutions in the source host plists. +# Keep every database setting as supplied by the host, including unknown keys. +info.update(CFBundleExecutable='verifyLocation', CFBundleIdentifier='com.expensify.database-location-test', CFBundlePackageType='APPL') +Path(sys.argv[2]).write_bytes(plistlib.dumps(info)) +PY + echo "Checking native database location for $PLIST" + "$APP_DIR/Contents/MacOS/verifyLocation" +done diff --git a/.github/workflows/verifyPodfile.yml b/.github/workflows/verifyPodfile.yml index b9978711a9c3..e806fa0b1317 100644 --- a/.github/workflows/verifyPodfile.yml +++ b/.github/workflows/verifyPodfile.yml @@ -1,4 +1,4 @@ -name: Verify Podfile +name: Verify iOS native configuration on: pull_request: @@ -8,6 +8,10 @@ on: - ios/** - 'package.json' - 'package-lock.json' + - 'patches/react-native-nitro-sqlite/**' + - '.github/scripts/verifyNitroSQLiteDatabaseLocation.sh' + - '.github/scripts/nitroSQLiteDatabaseLocation/**' + - '.github/workflows/verifyPodfile.yml' jobs: verify: @@ -21,5 +25,8 @@ jobs: - name: Setup Node uses: ./.github/actions/composite/setupNode + - name: Verify native NitroSQLite database location + run: bash ./.github/scripts/verifyNitroSQLiteDatabaseLocation.sh + - name: Verify podfile run: ./.github/scripts/verifyPodfile.sh