From cc6ed815546fb4ae45b1e0f00478dc4e5e810f34 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Sat, 17 Oct 2026 22:55:19 +0700 Subject: [PATCH] chore: delete history comments in release and plugin code --- .../Menu/AppDelegate+MainMenuActions.swift | 10 +----- .../Plugins/Registry/RegistryModels.swift | 14 +------- .../Infrastructure/MacAnalyticsProvider.swift | 10 ------ .../Infrastructure/PostLaunchWork.swift | 7 ---- .../Core/Storage/AppSettingsManager.swift | 4 +-- .../Views/Settings/GeneralSettingsView.swift | 12 +------ .../Views/Welcome/WelcomeActionsPanel.swift | 10 +----- TablePro/Views/WhatsNew/WhatsNewView.swift | 14 -------- .../WhatsNew/WhatsNewWindowController.swift | 12 ------- scripts/build-cassandra.sh | 6 ++-- scripts/build-duckdb.sh | 17 ++++----- scripts/build-hiredis.sh | 6 ---- scripts/build-libmongoc.sh | 9 ++--- scripts/build-libpq.sh | 12 ++----- scripts/build-libssh2.sh | 3 -- scripts/ci/check-deployment-target.sh | 8 ++--- scripts/ci/check-lib-sourcing.py | 13 ++----- scripts/ci/verify-plugin-loads.sh | 12 +++---- scripts/export-cloudkit-schema.sh | 16 ++------- scripts/ios/build-libpq-ios.sh | 5 ++- scripts/ios/build-mariadb-ios.sh | 8 ++--- scripts/lib/deployment-target.sh | 6 ---- scripts/lib/macos.sh | 35 +++---------------- 23 files changed, 37 insertions(+), 212 deletions(-) diff --git a/TablePro/Core/Menu/AppDelegate+MainMenuActions.swift b/TablePro/Core/Menu/AppDelegate+MainMenuActions.swift index 2ad2285068..352d9e93a3 100644 --- a/TablePro/Core/Menu/AppDelegate+MainMenuActions.swift +++ b/TablePro/Core/Menu/AppDelegate+MainMenuActions.swift @@ -1,8 +1,3 @@ -// -// AppDelegate+MainMenuActions.swift -// TablePro -// - import AppKit /// Commands that belong to the app rather than to any one window. They sit on the @@ -109,8 +104,6 @@ extension AppDelegate: NSMenuItemValidation { open(MainMenuLink.integrations) } - /// Opens the in-app notes rather than the browser. The window's own button reaches the full - /// changelog for anyone who wants every entry. @objc func openChangelog(_ sender: Any?) { WhatsNewWindowController.present() } @@ -144,8 +137,7 @@ extension AppDelegate: NSMenuItemValidation { case #selector(switchToRecentTab(_:)), #selector(switchToLeastRecentTab(_:)): return (NSApp.keyWindow?.tabbedWindows?.count ?? 0) > 1 case #selector(checkForUpdates(_:)): - /// Menu validation is the one moment AppKit gives an already-built item, and a - /// deferred update has no other way to reach this title. + // A deferred update reaches this title only through menu validation. menuItem.title = SoftwareUpdater.shared.checkForUpdatesTitle return SoftwareUpdater.shared.canCheckForUpdates case #selector(reopenClosedTab(_:)): diff --git a/TablePro/Core/Plugins/Registry/RegistryModels.swift b/TablePro/Core/Plugins/Registry/RegistryModels.swift index a23a917ab5..992a462690 100644 --- a/TablePro/Core/Plugins/Registry/RegistryModels.swift +++ b/TablePro/Core/Plugins/Registry/RegistryModels.swift @@ -1,8 +1,3 @@ -// -// RegistryModels.swift -// TablePro -// - import Foundation enum PluginArchitecture: String, Codable, Sendable { @@ -78,10 +73,7 @@ struct RegistryPlugin: Codable, Sendable, Identifiable { if let decodedBinaries = try container.decodeIfPresent([RegistryBinary].self, forKey: .binaries) { binaries = decodedBinaries } else if let url = legacyDownloadURL, let hash = legacySha256 { - // v1 manifests carried a single downloadURL with no architecture. - // Historically those ZIPs shipped a universal binary, so we synthesize - // entries for both architectures. Code signature verification will - // reject mismatched arch at install time. + // A v1 entry has one universal ZIP and no architecture. binaries = [ RegistryBinary( architecture: .arm64, @@ -122,10 +114,6 @@ extension RegistryPlugin { return highestInRange.binary } - // Every published binary being above this app's PluginKit version is a stale app, not a - // missing architecture, and saying "architecture" sends the user looking at their CPU. - // It is the ordinary outcome of the registry's retention policy: once the two newest kit - // versions are both above what an app ships, that app can install nothing at all. let publishedKits = forThisArchitecture.compactMap(\.pluginKitVersion) if let oldest = publishedKits.min(), oldest > currentKitVersion { throw PluginError.appTooOldForPlugin(oldestPublishedKit: oldest, appKit: currentKitVersion) diff --git a/TablePro/Core/Services/Infrastructure/MacAnalyticsProvider.swift b/TablePro/Core/Services/Infrastructure/MacAnalyticsProvider.swift index 74f9d89e20..5801d13f9d 100644 --- a/TablePro/Core/Services/Infrastructure/MacAnalyticsProvider.swift +++ b/TablePro/Core/Services/Infrastructure/MacAnalyticsProvider.swift @@ -1,8 +1,3 @@ -// -// MacAnalyticsProvider.swift -// TablePro -// - import Foundation import os import TableProAnalytics @@ -107,11 +102,6 @@ final class MacAnalyticsProvider: AnalyticsEnvironmentProvider { Self.logger.info("Recorded \(label, privacy: .public) for first time") } - /// Read from Sparkle rather than from a stored setting, because Sparkle owns these and a - /// managed preference or its own permission prompt can set them without the app involved. - /// - /// This is the only measure of whether a default that was flipped for every existing install - /// was accepted. It carries nothing about a person, a host or a query. var updateInstallMode: String? { let updater = SoftwareUpdater.shared guard updater.automaticallyChecksForUpdates else { return "off" } diff --git a/TablePro/Core/Services/Infrastructure/PostLaunchWork.swift b/TablePro/Core/Services/Infrastructure/PostLaunchWork.swift index feed0df108..68e3bead5f 100644 --- a/TablePro/Core/Services/Infrastructure/PostLaunchWork.swift +++ b/TablePro/Core/Services/Infrastructure/PostLaunchWork.swift @@ -1,8 +1,3 @@ -// -// PostLaunchWork.swift -// TablePro -// - import Foundation import os import TableProUtilities @@ -40,8 +35,6 @@ internal enum PostLaunchWork { guard !AppStorageEnvironment.shared.isIsolated else { return } - /// The registry manifest only feeds the plugin-install UI, and fetching it is a network - /// call. A sandboxed run has no user plugins directory to install into anyway. Task { await RegistryClient.shared.ensureManifest(.ifStale) } /// The retired per-tab split name left one permanent defaults record per query tab ever diff --git a/TablePro/Core/Storage/AppSettingsManager.swift b/TablePro/Core/Storage/AppSettingsManager.swift index 9306c4145a..798646aefb 100644 --- a/TablePro/Core/Storage/AppSettingsManager.swift +++ b/TablePro/Core/Storage/AppSettingsManager.swift @@ -248,9 +248,7 @@ final class AppSettingsManager: ObservableObject { await queryHistoryManager.applySettingsChange() } - /// The update preferences belong to Sparkle rather than to the structs reassigned above, so - /// they are cleared here and not by the caller: the alert promises every section, and a second - /// reset entry point would otherwise skip them silently. + /// Resets Sparkle's update preferences here too: the reset alert promises every section. func resetToDefaults() { general = .default appearance = .default diff --git a/TablePro/Views/Settings/GeneralSettingsView.swift b/TablePro/Views/Settings/GeneralSettingsView.swift index db2ece423d..a07909a525 100644 --- a/TablePro/Views/Settings/GeneralSettingsView.swift +++ b/TablePro/Views/Settings/GeneralSettingsView.swift @@ -1,17 +1,9 @@ -// -// GeneralSettingsView.swift -// TablePro -// - import AppKit import SwiftUI struct GeneralSettingsView: View { @Binding var settings: GeneralSettings @Binding var tabSettings: TabSettings - /// Observed, because this view reads `canCheckForUpdates`, `lastUpdateCheckDate` and the button - /// title off it. Held as a plain property, Last checked and Check for Updates… kept whatever they - /// said when Settings opened, however many checks ran behind them. @ObservedObject var updater: SoftwareUpdater var onResetAll: () -> Void @@ -21,9 +13,7 @@ struct GeneralSettingsView: View { private static let standardTimeouts = [10, 20, 30, 40, 50, 60, 90, 120, 180, 300, 600] - /// Bindings straight onto Sparkle's own properties. Nothing about the update section is stored - /// in `GeneralSettings`, so there is no second copy to fall out of step and nothing for a - /// synced settings blob to overwrite on another Mac. + /// Sparkle owns these, so `GeneralSettings` holds no copy for settings sync to overwrite. private var automaticallyChecksForUpdates: Binding { Binding( get: { updater.automaticallyChecksForUpdates }, diff --git a/TablePro/Views/Welcome/WelcomeActionsPanel.swift b/TablePro/Views/Welcome/WelcomeActionsPanel.swift index 2d3ce72383..dec4dd316c 100644 --- a/TablePro/Views/Welcome/WelcomeActionsPanel.swift +++ b/TablePro/Views/Welcome/WelcomeActionsPanel.swift @@ -1,8 +1,3 @@ -// -// WelcomeActionsPanel.swift -// TablePro -// - import Combine import SwiftUI @@ -25,8 +20,7 @@ struct WelcomeActionsPanel: View { .map(\.showWelcomeVersionInfo) .removeDuplicates() - /// Captured once, because the stored value is overwritten on the same appearance that reads - /// it. Without the capture the line would replace itself with nothing on the next redraw. + /// Captured once: the same appearance that reads the stored value overwrites it. @State private var lastSeenAppVersion = "" var body: some View { @@ -129,8 +123,6 @@ struct WelcomeActionsPanel: View { defaults.set(current, forKey: key) } - /// Updates install on quit with no dialog, so the release notes stop passing in front of - /// anyone. This is the pull-shaped replacement, shown on the window the user chose to open. private var showsWhatsNew: Bool { !lastSeenAppVersion.isEmpty && lastSeenAppVersion != Bundle.main.appVersion } diff --git a/TablePro/Views/WhatsNew/WhatsNewView.swift b/TablePro/Views/WhatsNew/WhatsNewView.swift index f0f4036ed7..0650fd4837 100644 --- a/TablePro/Views/WhatsNew/WhatsNewView.swift +++ b/TablePro/Views/WhatsNew/WhatsNewView.swift @@ -1,15 +1,5 @@ -// -// WhatsNewView.swift -// TablePro -// - import SwiftUI -/// What the running version brought, rendered from the bundled `WhatsNew.md`. -/// -/// Markdown through `AttributedString(markdown:)` rather than a web view, per the native-only -/// rule. The file is generated from the same CHANGELOG lead block the Sparkle feed carries, so -/// the window and the update dialog cannot disagree about what a release contained. struct WhatsNewView: View { private let content: WhatsNewContent private let onViewFullChangelog: () -> Void @@ -69,10 +59,6 @@ struct WhatsNewView: View { } } -/// The bundled notes, parsed once. -/// -/// A missing or unreadable file is not a failure worth showing: the window still opens, says so -/// plainly and offers the changelog button, which is the route that always works. struct WhatsNewContent { let title: String let paragraphs: [AttributedString] diff --git a/TablePro/Views/WhatsNew/WhatsNewWindowController.swift b/TablePro/Views/WhatsNew/WhatsNewWindowController.swift index 45b57bce15..d25d483bc5 100644 --- a/TablePro/Views/WhatsNew/WhatsNewWindowController.swift +++ b/TablePro/Views/WhatsNew/WhatsNewWindowController.swift @@ -1,18 +1,6 @@ -// -// WhatsNewWindowController.swift -// TablePro -// - import AppKit import SwiftUI -/// Hosts the What's New notes in an ordinary `NSWindowController`, like every other window in the -/// app. One instance for the app's lifetime, so reopening from the menu raises the same window -/// rather than stacking copies. -/// -/// Pull-only. Nothing opens this on launch or after an update installs: updates now apply on quit -/// with no dialog, and a window that appeared after each one would be more than a hundred -/// interruptions a year spent on exactly what background installs remove. @MainActor internal final class WhatsNewWindowController: NSWindowController { private static var shared: WhatsNewWindowController? diff --git a/scripts/build-cassandra.sh b/scripts/build-cassandra.sh index 3c0886769c..9463bde403 100755 --- a/scripts/build-cassandra.sh +++ b/scripts/build-cassandra.sh @@ -6,10 +6,8 @@ set -euo pipefail # # Dependencies: cmake, libuv (built automatically), OpenSSL (from Libs/) # -# Always rebuilds. It used to skip any artifact already present in Libs/, but download-libs.sh -# vendors all eight of them, so the guards were satisfied on every machine and the script did -# nothing: a CASSANDRA_VERSION bump produced no new binary. Publish the result with -# scripts/publish-libs.sh, which is what makes it the version everyone else gets. +# Always rebuilds: download-libs.sh fills Libs/, so a skip-if-present guard would never build. +# Publish the result with scripts/publish-libs.sh. CASSANDRA_VERSION="2.17.1" CASSANDRA_SHA256="e6ab5f5c60a916dd6c0dd9a19a883a4a1ab3d6b4e95cab925a186fecff08344e" diff --git a/scripts/build-duckdb.sh b/scripts/build-duckdb.sh index f7dcc2ebe2..cb041a5482 100755 --- a/scripts/build-duckdb.sh +++ b/scripts/build-duckdb.sh @@ -6,12 +6,9 @@ set -euo pipefail # Usage: ./scripts/build-duckdb.sh [arm64|x86_64|both] # # This compiles DuckDB from source with CMake so the extensions in -# scripts/duckdb-macos-extensions.cmake link in statically. The previous version -# compiled the single-file amalgamation with plain clang++, and the amalgamation -# carries no extensions: `sum`, `avg`, `round`, `date_trunc`, `current_database` -# and most of the rest live in core_functions, which DuckDB then downloaded from -# extensions.duckdb.org on first use. On a Mac that could not reach the registry -# every one of them failed and a DuckDB connection was unusable. +# scripts/duckdb-macos-extensions.cmake link in statically. The amalgamation carries +# none, so core_functions (`sum`, `avg`, `date_trunc` and most of the rest) would +# download from extensions.duckdb.org on first use and fail offline. # # Runtime autoloading stays on, unlike the iOS build, so httpfs and quack still # download on demand for remote Quack connections. @@ -144,11 +141,9 @@ build_arch() { fi echo "Verified $core_symbols core_functions symbol(s) in $(basename "$out_lib")" - # The plugin links this with -force_load, which pulls in every member rather than letting - # the linker pick a winner, so a duplicated symbol is a hard link failure. Merging one - # archive too many produced 1821 of them and `libtool -static` reported nothing at all, - # so the only honest check is to link the way the plugin links. Member names are not the - # test: brotli and DuckDB core both ship a `platform.cpp.o` and coexist fine. + # The plugin links this with -force_load, so a duplicated symbol is a hard link failure + # that `libtool -static` never reports: link the way the plugin links. Member names are + # not the test: brotli and DuckDB core both ship a `platform.cpp.o` and coexist fine. local link_dir link_dir=$(mktemp -d) cat > "$link_dir/link_probe.c" <<'PROBE' diff --git a/scripts/build-hiredis.sh b/scripts/build-hiredis.sh index 6b099a6b05..b0393e21ff 100755 --- a/scripts/build-hiredis.sh +++ b/scripts/build-hiredis.sh @@ -10,9 +10,6 @@ set -eo pipefail # OpenSSL is built from source to match the app's deployment target, # preventing "Symbol not found" crashes from Homebrew-built libraries. # -# All libraries are built with MACOSX_DEPLOYMENT_TARGET=14.0 to match -# the app's minimum deployment target. -# # Usage: # ./scripts/build-hiredis.sh [arm64|x86_64|both] # @@ -28,9 +25,6 @@ HIREDIS_VERSION="1.2.0" HIREDIS_SHA256="82ad632d31ee05da13b537c124f819eb88e18851d9cb0c30ae0552084811588c" ARCH="${1:-both}" -# The headers the Redis plugin compiles against. The old path under TablePro/Core/Database was -# deleted when the driver moved into a plugin bundle, so this script was installing them where -# nothing read them and leaving the real ones untouched. HEADER_DIR="$REPO_ROOT/Plugins/RedisDriverPlugin/CRedis/include/hiredis" make_build_dir diff --git a/scripts/build-libmongoc.sh b/scripts/build-libmongoc.sh index dcf62fdb9a..bb3183a1b4 100755 --- a/scripts/build-libmongoc.sh +++ b/scripts/build-libmongoc.sh @@ -7,17 +7,12 @@ set -eo pipefail # libbson_arm64.a, libbson_x86_64.a, libbson_universal.a # libmongoc_arm64.a, libmongoc_x86_64.a, libmongoc_universal.a # -# TLS backend: OpenSSL (ENABLE_SSL=OPENSSL). The previous Secure Transport -# build broke TLS handshakes against MongoDB Atlas on macOS 26 with -# errSSLPeerInternalError (-9838). OpenSSL handshakes succeed and TablePro -# already bundles OpenSSL 3 dylibs for Redis/MSSQL/MySQL. +# TLS backend: OpenSSL (ENABLE_SSL=OPENSSL). Secure Transport fails the handshake against +# MongoDB Atlas on macOS 26 with errSSLPeerInternalError (-9838). # # OpenSSL is rebuilt from source for each arch with the correct deployment # target instead of relying on Homebrew or system OpenSSL. # -# All libraries are built with MACOSX_DEPLOYMENT_TARGET=14.0 to match -# the app's minimum deployment target. -# # Usage: # ./scripts/build-libmongoc.sh [arm64|x86_64|both] # diff --git a/scripts/build-libpq.sh b/scripts/build-libpq.sh index bf99a1f275..8ce6e9f39c 100755 --- a/scripts/build-libpq.sh +++ b/scripts/build-libpq.sh @@ -11,10 +11,8 @@ set -eo pipefail # libpgcommon_arm64.a, libpgcommon_x86_64.a, libpgcommon_universal.a # libpgport_arm64.a, libpgport_x86_64.a, libpgport_universal.a # -# All libraries are built with MACOSX_DEPLOYMENT_TARGET=14.0 to match -# the app's minimum deployment target. This prevents the "Symbol not found" -# crash (e.g. _strchrnul) that occurs when Homebrew libraries built for -# the host OS are bundled into the app. +# Built for the app's deployment target, not the host's: a Homebrew libpq crashes an older +# macOS with "Symbol not found" (e.g. _strchrnul). # # Usage: # ./scripts/build-libpq.sh [arm64|x86_64|both] @@ -29,9 +27,6 @@ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/macos.sh" PG_SHA256="c4605b73fea11963406699f949b966e5d173a7ee0ccaef8938dec0ca8a995fe7" ARCH="${1:-both}" -# The PostgreSQL driver became a plugin, and its headers moved with it. This pointed at -# TablePro/Core/Database/CLibPQ/include, which no longer exists, so every rebuild recreated a dead -# directory and never updated the headers the plugin actually compiles against. HEADER_DIR="$REPO_ROOT/Plugins/PostgreSQLDriverPlugin/CLibPQ/include" make_build_dir @@ -159,8 +154,7 @@ build_for_arch() { build_openssl "$arch" build_libpq "$arch" install_libs "$arch" - # Unconditional. Skipping when a header already exists meant a version bump shipped new - # binaries against the previous release's headers. + # Unconditional, so a version bump never ships new binaries with the old headers. install_headers "$arch" } diff --git a/scripts/build-libssh2.sh b/scripts/build-libssh2.sh index ee4b2ff873..b5ad496f64 100755 --- a/scripts/build-libssh2.sh +++ b/scripts/build-libssh2.sh @@ -10,9 +10,6 @@ set -eo pipefail # OpenSSL is built from source to match the app's deployment target, # preventing "Symbol not found" crashes from Homebrew-built libraries. # -# All libraries are built with MACOSX_DEPLOYMENT_TARGET=14.0 to match -# the app's minimum deployment target. -# # Usage: # ./scripts/build-libssh2.sh [arm64|x86_64|both] # diff --git a/scripts/ci/check-deployment-target.sh b/scripts/ci/check-deployment-target.sh index 4ae9579abe..8042708013 100755 --- a/scripts/ci/check-deployment-target.sh +++ b/scripts/ci/check-deployment-target.sh @@ -1,11 +1,7 @@ #!/usr/bin/env bash # -# Fails when a build script writes the macOS deployment target down itself. -# -# The number belongs to project.yml and reaches the scripts through -# scripts/lib/deployment-target.sh. It used to live in five places, and when #2874 moved the app to -# macOS 13 none of them followed: every archive in Libs/ was built for macOS 14 and linked into a -# 13.0 app, which the linker reported 121 times into a build that silenced linker warnings. +# Fails when a build script writes the macOS deployment target down itself. The number belongs +# to project.yml and reaches the scripts through scripts/lib/deployment-target.sh. # # Usage: check-deployment-target.sh diff --git a/scripts/ci/check-lib-sourcing.py b/scripts/ci/check-lib-sourcing.py index 242958ab0a..b1bfd6745a 100755 --- a/scripts/ci/check-lib-sourcing.py +++ b/scripts/ci/check-lib-sourcing.py @@ -1,13 +1,6 @@ #!/usr/bin/env python3 """Fails when a script calls a scripts/lib function without sourcing the library that defines it. -A missing `source` line is invisible to every tool the repo already runs. bash -n only parses, -shellcheck cannot know whether a bare word is a function or a command on PATH, and the call site -reads exactly like a working one. It surfaces at run time as exit 127, and for the one script that -only runs during a release, that means it surfaces during a release: v0.67.1's DMG job died with -"exit code 127" right after "DMG signed", because create-dmg.sh called notarize_and_staple and -never sourced scripts/lib/notarize.sh. - Usage: check-lib-sourcing.py [scripts-dir] """ @@ -16,8 +9,7 @@ import sys FUNCTION = re.compile(r"^([A-Za-z_][A-Za-z0-9_]*)\s*\(\)\s*\{", re.M) -# Any .sh named on a source line. Matched by basename so it works whether the script -# writes lib/common.sh or, as macos.sh does from inside lib/, just common.sh. +# Matched by basename: macos.sh, from inside lib/, sources plain common.sh. SOURCED = re.compile(r"^\s*(?:source|\.)\s+.*?([A-Za-z0-9_.-]+\.sh)", re.M) @@ -33,8 +25,7 @@ def main(): for name in FUNCTION.findall(lib.read_text(encoding="utf-8")): owner.setdefault(name, lib.name) - # Sourcing is transitive: macos.sh sources common.sh, so a script that sources macos.sh gets - # both. Resolving that is the difference between a useful check and five false reports. + # Sourcing is transitive: a script that sources macos.sh also gets common.sh. def sourced_libs(text): return {name for name in SOURCED.findall(text) if (lib_dir / name).is_file()} diff --git a/scripts/ci/verify-plugin-loads.sh b/scripts/ci/verify-plugin-loads.sh index 96e6b9c0ea..49a66ce249 100755 --- a/scripts/ci/verify-plugin-loads.sh +++ b/scripts/ci/verify-plugin-loads.sh @@ -5,13 +5,9 @@ set -euo pipefail # # Usage: verify-plugin-loads.sh [more-directories...] # -# "Bundle failed to load executable" is the failure this repo has shipped twice, both times because -# a plugin's witness table hard-referenced a PluginKit symbol that had been removed. CI built and -# signed the bundles and never once tried to load one, so the first thing to find out was a user's -# install. dlopen is exactly the dyld path that fails in that case, and it takes milliseconds. -# -# This proves the binary and its dependencies resolve. It does not instantiate the principal class -# or call into PluginKit; the app's own version gate does that at runtime. +# dlopen resolves the binary and every library and framework it links, the dyld path behind +# "Bundle failed to load executable". It does not instantiate the principal class. PluginKit ABI: +# .claude/rules/plugin-system.md, ABI, checked with `verify.sh abi`. [ $# -gt 0 ] || { echo "Usage: $0 ..." >&2; exit 2; } @@ -77,7 +73,7 @@ if [ "${#failed[@]}" -gt 0 ]; then echo "" >&2 echo "${#failed[@]} of $checked plugins will not load: ${failed[*]}" >&2 echo "This is the 'Bundle failed to load executable' a user would hit. A removed PluginKit" >&2 - echo "requirement is the usual cause; see the ABI rules in CLAUDE.md." >&2 + echo "symbol is the usual cause; see .claude/rules/plugin-system.md, ABI." >&2 exit 1 fi diff --git a/scripts/export-cloudkit-schema.sh b/scripts/export-cloudkit-schema.sh index 01f64b51d4..3e3927b058 100755 --- a/scripts/export-cloudkit-schema.sh +++ b/scripts/export-cloudkit-schema.sh @@ -1,20 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -# Refresh the checked-in snapshot of the Production CloudKit schema. -# -# CloudKit only creates record fields automatically in the Development -# environment. TablePro pins both apps to Production, so a field added to a -# record type in code never reaches the server on its own: saving a record -# that carries an undeclared field makes CloudKit reject that record. -# -# ConnectionSyncField refuses to write any field that is not verified against -# this snapshot, and ProductionSchemaParityTests fails if the two disagree. -# After deploying a schema change in CloudKit Console, run this script and -# commit the result, then mark the field verified in ConnectionSyncSchema.swift. -# -# The snapshot is only ever this script's output: a hand edit passes -# ProductionSchemaParityTests while Production still rejects the field. +# Refresh the checked-in snapshot of the Production CloudKit schema. When to run it: +# .claude/rules/data-sync-storage.md. # # Requires a CloudKit management token: # xcrun cktool save-token --type management diff --git a/scripts/ios/build-libpq-ios.sh b/scripts/ios/build-libpq-ios.sh index a1246b2ae8..9ad4b22c5a 100755 --- a/scripts/ios/build-libpq-ios.sh +++ b/scripts/ios/build-libpq-ios.sh @@ -294,9 +294,8 @@ build_slice() { for src in "${LIBPQ_SRCS[@]}" "${COMMON_SRCS[@]}" "${PORT_SRCS[@]}"; do local obj_name obj_name=$(basename "${src%.c}.o") - # A source that is not there used to be skipped in silence, so a PostgreSQL bump that - # renamed or moved a file produced a libpq.a quietly missing that object. Only a - # compile failure was ever reported. + # A missing source fails the build: a PostgreSQL bump that moves a file must not drop + # its object from libpq.a. if [ ! -f "$src" ]; then MISSING_SRCS+=("$src") continue diff --git a/scripts/ios/build-mariadb-ios.sh b/scripts/ios/build-mariadb-ios.sh index d2d4ef29b4..920ecf7a85 100755 --- a/scripts/ios/build-mariadb-ios.sh +++ b/scripts/ios/build-mariadb-ios.sh @@ -14,11 +14,9 @@ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../lib/common.sh" # ./scripts/ios/build-mariadb-ios.sh MARIADB_VERSION="3.4.4" -# MariaDB publishes a digest for this tarball independently of the tarball itself, at -# https://archive.mariadb.org/connector-c-$MARIADB_VERSION/sha256sums.txt, which is why the source -# moved here from the GitHub tag archive: GitHub publishes no digest, so pinning one would only -# record whatever was served the first time anybody looked. Note the upstream tarball unpacks to a -# "-src" directory, unlike the GitHub one. +# From archive.mariadb.org, which publishes a digest at +# https://archive.mariadb.org/connector-c-$MARIADB_VERSION/sha256sums.txt; the GitHub tag archive +# has none. The tarball unpacks to a "-src" directory. MARIADB_SHA256="58876fad1c2d33979d78bbfa61d7a3476e8faa2cd0af0f7f8bfeb06deaa1034e" IOS_DEPLOY_TARGET="17.0" diff --git a/scripts/lib/deployment-target.sh b/scripts/lib/deployment-target.sh index 3d22cdc7ae..2b879bc6fd 100644 --- a/scripts/lib/deployment-target.sh +++ b/scripts/lib/deployment-target.sh @@ -6,12 +6,6 @@ # # source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/deployment-target.sh" # -# The number used to be written down in five places: lib/macos.sh plus a private copy in -# build-cassandra.sh, build-dameng.sh, build-duckdb.sh and build-freetds.sh. #2874 moved the app to -# macOS 13 and none of the copies followed, so every archive in Libs/ was built for macOS 14 and -# linked into a 13.0 app. The linker said so 121 times and `-Wl,-w` in the app's OTHER_LDFLAGS -# swallowed all of it. -# # shellcheck shell=bash # shellcheck disable=SC2034 # DEPLOY_TARGET is read by the scripts that source this diff --git a/scripts/lib/macos.sh b/scripts/lib/macos.sh index dae90648e7..c8254a1027 100644 --- a/scripts/lib/macos.sh +++ b/scripts/lib/macos.sh @@ -46,12 +46,7 @@ macho_min_version() { printf '%s' "$version" } -# Fails if any given library was built for a NEWER macOS than the app supports. -# -# The direction matters and three copies had it backwards. A library built for an older macOS is -# fine, it simply supports more systems; one built for a newer macOS cannot run on the app's floor. -# `max(target, minos) == target` is the question. The inverted form passed exactly the libraries -# that break. +# Fails on a library built for a newer macOS than DEPLOY_TARGET; an older one runs fine. verify_deployment_target() { local lib name version failed=0 echo "" @@ -74,10 +69,6 @@ verify_deployment_target() { fi } -# OPENSSL_VERSION and OPENSSL_SHA256 come from common.sh, sourced above. They were duplicated -# here by the split, which is the thing this library exists to stop. - -# Downloads the OpenSSL tarball into BUILD_DIR once, verified against the pin above. fetch_openssl() { local tarball="$BUILD_DIR/openssl-$OPENSSL_VERSION.tar.gz" if [ ! -f "$tarball" ]; then @@ -89,11 +80,7 @@ fetch_openssl() { verify_sha256 "$tarball" "$OPENSSL_SHA256" } -# Builds static OpenSSL for one architecture into $BUILD_DIR/install-openssl-. -# -# Expects BUILD_DIR, NCPU and the tarball fetched by fetch_openssl. Configure runs through -# run_quiet rather than being redirected to /dev/null: three copies discarded its output entirely, -# so a configure failure produced a bare non-zero exit with nothing to read. +# Expects BUILD_DIR, NCPU and the tarball fetched by fetch_openssl. build_openssl() { local arch="$1" local prefix="$BUILD_DIR/install-openssl-$arch" @@ -126,29 +113,19 @@ build_openssl() { echo "✅ OpenSSL $arch: $(du -h "$prefix/lib/libssl.a" | cut -f1) (libssl) $(du -h "$prefix/lib/libcrypto.a" | cut -f1) (libcrypto)" } -# Puts the named libraries in Libs/.a at the requested architecture, which is what -# project.yml links. -# -# Three sources, in order: a slice that is already correct, a per-architecture file, or a thinned -# universal. This existed in five places that disagreed. build-release.sh carried four -# near-identical functions, 159 lines between them, one of which cd'd into Libs and one of which -# only ever thinned the universal; scripts/ci/prepare-libs.sh did a bare `cp` of the per-arch file -# with no fallback at all, so the two took different sources for the same library. -# The architectures in a Mach-O archive, space separated, or empty if it is not there. current_arch() { [ -f "$1" ] || return 0 lipo -info "$1" 2> /dev/null | sed 's/.*: //' | tr -s ' ' | sed 's/ $//' } +# Leaves Libs/.a at the requested architecture, which is what project.yml links. prepare_arch_libs() { local target_arch="$1" shift local lib unresolved=0 for lib in "$@"; do - # An exact match, not "contains". `lipo -info | grep -q arm64` also matches a universal, - # so the substring form left fat libraries in place and the release linked those instead - # of the slice it asked for. + # An exact match: a universal also contains the slice, and must not be linked as one. if [ "$(current_arch "$LIBS_DIR/${lib}.a")" = "$target_arch" ]; then continue fi @@ -176,10 +153,6 @@ prepare_arch_libs() { fi } -# Every library build wants one private scratch directory that goes away on exit. Five scripts -# each declared their own BUILD_DIR, an identical three-line cleanup() and the same trap; one of -# them had leaked its directory on every run until #2352. -# # The trap body is single-quoted so it reads BUILD_DIR when it fires, not when it is installed. # It replaces any EXIT trap already in place, so a script that needs to remove more than this # directory installs its own instead (build-freetds.sh does, for its tarball cache).