Clean up the AppVeyor Mac build and package OpenSSL (#4825)

So it's easier to install new packages without system Python
[publish binaries]
This commit is contained in:
Magnus Gille
2026-02-11 17:51:31 -08:00
committed by GitHub
parent f502c1ab80
commit 3d54fb799c
2 changed files with 286 additions and 60 deletions

View File

@@ -1,11 +1,10 @@
#!/bin/bash #!/bin/bash
set -ev set -ev
cd src cd src
export PIP_BREAK_SYSTEM_PACKAGES=1
# Ensure we use the correct Python binary
PYTHON_VER=${PYTHON_VERSION}
# Homebrew install location # Homebrew install location
BREW_PYTHON_ROOT=`brew --prefix python@${PYTHON_VER}` BREW_PYTHON_ROOT=`brew --prefix python@${PYTHON_VERSION}`
export PATH="${BREW_PYTHON_ROOT}/bin:$PATH" export PATH="${BREW_PYTHON_ROOT}/bin:$PATH"
BREW_PYTHON_FRAMEWORK="${BREW_PYTHON_ROOT}/Frameworks/Python.framework" BREW_PYTHON_FRAMEWORK="${BREW_PYTHON_ROOT}/Frameworks/Python.framework"
@@ -16,71 +15,66 @@ mkdir -p GoldenCheetah.app/Contents/Frameworks
cp `brew --prefix icu4c`/lib/libicudata.*.dylib GoldenCheetah.app/Contents/Frameworks cp `brew --prefix icu4c`/lib/libicudata.*.dylib GoldenCheetah.app/Contents/Frameworks
# Copy python framework and change permissions to fix paths # Copy python framework and change permissions to fix paths
# Note: The framework already contains site-packages with numpy, sip, etc.
# because install.sh runs "pip install -r requirements.txt" which installs
# packages into the brew Python's framework site-packages.
echo "Copying Python Framework from ${BREW_PYTHON_FRAMEWORK}" echo "Copying Python Framework from ${BREW_PYTHON_FRAMEWORK}"
# Remove any old attempts to avoid link confusion # Remove any old attempts to avoid link confusion
rm -rf GoldenCheetah.app/Contents/Frameworks/Python.framework rm -rf GoldenCheetah.app/Contents/Frameworks/Python.framework
rsync -axL "${BREW_PYTHON_FRAMEWORK}/" "GoldenCheetah.app/Contents/Frameworks/Python.framework/" rsync -axL "${BREW_PYTHON_FRAMEWORK}/" "GoldenCheetah.app/Contents/Frameworks/Python.framework/"
# This ensures every level of the path is a real directory
mkdir -p "GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VER}/lib/python${PYTHON_VER}"
chmod -R +w GoldenCheetah.app/Contents/Frameworks
# Locate the actual site-packages where pip installed dependencies (e.g. numpy)
# We rely on numpy being installed to find the true site-packages location
SITE_PACKAGES_SRC=$( ${BREW_PYTHON_ROOT}/bin/python3 -c "import numpy; import os; print(os.path.dirname(os.path.dirname(numpy.__file__)))" )
echo "Found source site-packages at: $SITE_PACKAGES_SRC"
if [ -z "$SITE_PACKAGES_SRC" ]; then
echo "ERROR: Failed to locate site-packages using numpy."
echo "Python command returned an empty string."
echo "Aborting build to prevent rsync from copying the root filesystem."
exit 1
fi
# Verify Python framework was copied correctly
PYTHON_LIB_DIR="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VER}/lib/python${PYTHON_VER}"
if [ ! -d "$PYTHON_LIB_DIR" ]; then
echo "ERROR: Python framework lib directory not found at $PYTHON_LIB_DIR"
echo "Contents of Frameworks directory:"
ls -laR GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/ || true
exit 1
fi
# Copy pip-installed packages from the actual install location
# Homebrew Python installs packages to /usr/local/lib, not into the framework
# Define the internal lib path clearly
INTERNAL_PYTHON_DIR="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VER}/lib/python${PYTHON_VER}"
# Fix the Python Framework structure broken by rsync -L # Fix the Python Framework structure broken by rsync -L
# rsync -L turns symlinks into directories, confusing codesign. We restore the standard structure. # rsync -L turns symlinks into directories/files, confusing codesign. We restore the standard structure.
echo "Restoring standard Python Framework structure..." echo "Restoring standard Python Framework structure..."
pushd GoldenCheetah.app/Contents/Frameworks/Python.framework > /dev/null pushd GoldenCheetah.app/Contents/Frameworks/Python.framework > /dev/null
rm -rf Headers Resources Python Versions/Current rm -rf Headers Resources Python Versions/Current
ln -s "${PYTHON_VER}" Versions/Current ln -s "${PYTHON_VERSION}" Versions/Current
ln -s Versions/Current/Headers Headers ln -s Versions/Current/Headers Headers
ln -s Versions/Current/Resources Resources ln -s Versions/Current/Resources Resources
ln -s Versions/Current/Python Python ln -s Versions/Current/Python Python
popd > /dev/null popd > /dev/null
echo "Merging pip-installed packages into bundle..." # This ensures every level of the path is a real directory
# Create the parent path explicitly, avoiding symlink traversal issues mkdir -p "GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/python${PYTHON_VERSION}"
mkdir -p "$INTERNAL_PYTHON_DIR"
# Now create site-packages specifically chmod -R +w GoldenCheetah.app/Contents/Frameworks
SITE_PACKAGES="${INTERNAL_PYTHON_DIR}/site-packages"
mkdir -p "$SITE_PACKAGES"
# Copy from the source found via the specific python version PYTHON_BIN="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}"
rsync -ax --ignore-existing "$SITE_PACKAGES_SRC/" "$SITE_PACKAGES/"
echo "Installing requirements into bundle..."
if [ -f "$PYTHON_BIN" ]; then
# Fix RPATH early
install_name_tool -add_rpath "@executable_path/../.." "$PYTHON_BIN" || true
# Re-sign the binary immediately because install_name_tool invalidated it
codesign --force --sign - "$PYTHON_BIN"
echo "Running pip install using bundled python: $PYTHON_BIN"
# Ensure modern build tools
"$PYTHON_BIN" -m pip install --upgrade pip setuptools wheel
# Install all requirements at once
# Calculate target site-packages
# Note: AppVeyor script might define variables differently, but structure is standard.
# 'GoldenCheetah.app' is in the current directory (src)
SITE_PACKAGES="$(pwd)/GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/Current/lib/python3.11/site-packages"
if [ ! -d "$SITE_PACKAGES" ]; then
SITE_PACKAGES=$(find "$(pwd)/GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/Current/lib" -name "python3.*" -type d | head -n 1)/site-packages
fi
echo "Installing Python packages to bundle target: $SITE_PACKAGES"
"$PYTHON_BIN" -m pip install --target "$SITE_PACKAGES" --ignore-installed --break-system-packages --no-cache-dir --only-binary :all: -r ../src/Python/requirements.txt
else
echo "ERROR: Bundled python binary not found at $PYTHON_BIN"
exit 1
fi
SITE_PACKAGES_SRC=$( "$PYTHON_BIN" -c "import numpy; import os; print(os.path.dirname(os.path.dirname(numpy.__file__)))" )
echo "Verified Site Packages at: $SITE_PACKAGES_SRC"
# Remove direct_url.json metadata which may contain absolute paths to the build machine
find "$SITE_PACKAGES_SRC" -name "direct_url.json" -delete
# Update deployed Python framework path # Update deployed Python framework path
# Change the ID of the library itself so it knows it lives in the app now # Change the ID of the library itself so it knows it lives in the app now
install_name_tool -id @executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VER}/Python ./GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VER}/Python install_name_tool -id @executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python ./GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python
# Update GoldenCheetah binary to reference deployed lib # Update GoldenCheetah binary to reference deployed lib
# We replace the absolute path to the brew framework with the relative path inside the bundle # We replace the absolute path to the brew framework with the relative path inside the bundle
@@ -90,13 +84,13 @@ GC_BIN="./GoldenCheetah.app/Contents/MacOS/GoldenCheetah"
OLD_GC_PATH=$(otool -L "$GC_BIN" | grep "Python.framework" | grep -v executable_path | awk '{print $1}' | head -n 1) OLD_GC_PATH=$(otool -L "$GC_BIN" | grep "Python.framework" | grep -v executable_path | awk '{print $1}' | head -n 1)
if [ -n "$OLD_GC_PATH" ]; then if [ -n "$OLD_GC_PATH" ]; then
echo "Updating GoldenCheetah binary dependency from $OLD_GC_PATH" echo "Updating GoldenCheetah binary dependency from $OLD_GC_PATH"
install_name_tool -change "$OLD_GC_PATH" "@executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VER}/Python" "$GC_BIN" install_name_tool -change "$OLD_GC_PATH" "@executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python" "$GC_BIN"
else else
echo "GoldenCheetah binary already uses relative path or Python framework not found." echo "GoldenCheetah binary already uses relative path or Python framework not found."
fi fi
# Update Python binary to reference deployed lib instead of the Cellar one # Update Python binary to reference deployed lib instead of the Cellar one
PYTHON_BIN="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VER}/bin/python${PYTHON_VER}" PYTHON_BIN="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}"
if [ -f "$PYTHON_BIN" ]; then if [ -f "$PYTHON_BIN" ]; then
echo "Debugging dependencies for $PYTHON_BIN" echo "Debugging dependencies for $PYTHON_BIN"
otool -L "$PYTHON_BIN" otool -L "$PYTHON_BIN"
@@ -110,7 +104,7 @@ else
fi fi
# Same for the Python app stub if it exists # Same for the Python app stub if it exists
PYTHON_APP_BIN="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VER}/Resources/Python.app/Contents/MacOS/Python" PYTHON_APP_BIN="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Resources/Python.app/Contents/MacOS/Python"
if [ -f "$PYTHON_APP_BIN" ]; then if [ -f "$PYTHON_APP_BIN" ]; then
# Fix the app stub dependency too! # Fix the app stub dependency too!
otool -L "$PYTHON_APP_BIN" | grep "Python" | grep "/" | grep -v "@executable_path" | awk '{print $1}' | while read OLD_PATH_APP; do otool -L "$PYTHON_APP_BIN" | grep "Python" | grep "/" | grep -v "@executable_path" | awk '{print $1}' | while read OLD_PATH_APP; do
@@ -118,19 +112,126 @@ if [ -f "$PYTHON_APP_BIN" ]; then
done done
fi fi
# Fix pip binaries to be relocatable (replace shebangs)
echo "Fixing pip binaries to be relocatable..."
PYTHON_BIN_DIR="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin"
if [ -d "$PYTHON_BIN_DIR" ]; then
for PIP_BIN in pip pip3 pip${PYTHON_VERSION}; do
if [ -f "$PYTHON_BIN_DIR/$PIP_BIN" ]; then
echo "Rewriting shebang for $PIP_BIN"
rm "$PYTHON_BIN_DIR/$PIP_BIN"
cat > "$PYTHON_BIN_DIR/$PIP_BIN" <<EOF
#!/bin/sh
exec "\$(dirname "\$0")/python${PYTHON_VERSION}" -m pip "\$@"
EOF
chmod +x "$PYTHON_BIN_DIR/$PIP_BIN"
fi
done
fi
# Patch _sysconfigdata to remove absolute paths from build machine
echo "Patching _sysconfigdata..."
SYSCONFIG_FILE=$(find "GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/python${PYTHON_VERSION}" -name "_sysconfigdata_*.py" | head -n 1)
if [ -f "$SYSCONFIG_FILE" ]; then
echo "Patching $SYSCONFIG_FILE to be relocatable..."
# Use python to safely replace the string literal, avoiding sed quoting issues
# BREW_PYTHON_ROOT is set at top of script
python3 <<EOF
import sys
import os
filepath = "$SYSCONFIG_FILE"
prefix = "$BREW_PYTHON_ROOT"
if os.path.exists(filepath):
with open(filepath, 'r') as f:
content = f.read()
# Ensure sys is imported
if "import sys" not in content:
content = "import sys\n" + content
# Replace absolute prefix with f-string using sys.prefix
# This preserves implicit string concatenation (e.g. f'...' '...')
content = content.replace("'" + prefix, "f'{sys.prefix}")
content = content.replace('"' + prefix, 'f"{sys.prefix}')
with open(filepath, 'w') as f:
f.write(content)
EOF
fi
# Fix libpython dependencies inside the framework to point to the internal framework binary # Fix libpython dependencies inside the framework to point to the internal framework binary
# This prevents macdeployqt from chasing external links and failing with path errors # This prevents macdeployqt from chasing external links and failing with path errors
find GoldenCheetah.app/Contents/Frameworks/Python.framework -name "libpython*.dylib" -type f | while read LIB; do find GoldenCheetah.app/Contents/Frameworks/Python.framework -name "libpython*.dylib" -type f | while read LIB; do
echo "Fixing library dependency for: $LIB" echo "Fixing library dependency for: $LIB"
OLD_LIB_PATH=$(otool -L "$LIB" | grep "Python.framework" | grep -v executable_path | awk '{print $1}' | head -n 1) OLD_LIB_PATH=$(otool -L "$LIB" | grep "Python.framework" | grep -v executable_path | awk '{print $1}' | head -n 1)
if [ -n "$OLD_LIB_PATH" ]; then if [ -n "$OLD_LIB_PATH" ]; then
echo " Changing $OLD_LIB_PATH to @executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VER}/Python" echo " Changing $OLD_LIB_PATH to @executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python"
install_name_tool -change "$OLD_LIB_PATH" "@executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VER}/Python" "$LIB" install_name_tool -change "$OLD_LIB_PATH" "@executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python" "$LIB"
fi fi
# Also fix the ID of the dylib itself if needed (macdeployqt likes valid IDs) # Also fix the ID of the dylib itself if needed (macdeployqt likes valid IDs)
install_name_tool -id "@executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VER}/lib/$(basename $LIB)" "$LIB" install_name_tool -id "@executable_path/../Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/$(basename $LIB)" "$LIB"
done done
# OpenSSL bundling for Python _ssl module
echo "Bundling OpenSSL libraries for Python..."
OPENSSL_PREFIX=$(brew --prefix openssl@3)
if [ -d "$OPENSSL_PREFIX" ]; then
echo "Found OpenSSL at $OPENSSL_PREFIX"
# Destination for OpenSSL libs (same level as Python framework usually, or inside it)
# Putting them in Frameworks/ is standard
DEST_FRAMEWORKS="GoldenCheetah.app/Contents/Frameworks"
# Copy the dylibs
cp "$OPENSSL_PREFIX/lib/libssl.3.dylib" "$DEST_FRAMEWORKS/"
cp "$OPENSSL_PREFIX/lib/libcrypto.3.dylib" "$DEST_FRAMEWORKS/"
# Make them writable for install_name_tool
chmod +w "$DEST_FRAMEWORKS/libssl.3.dylib"
chmod +w "$DEST_FRAMEWORKS/libcrypto.3.dylib"
# Fix IDs of the copied libs
# Fix IDs of the copied libs
install_name_tool -id "@loader_path/libssl.3.dylib" "$DEST_FRAMEWORKS/libssl.3.dylib"
install_name_tool -id "@loader_path/libcrypto.3.dylib" "$DEST_FRAMEWORKS/libcrypto.3.dylib"
# Fix dependency of libssl on libcrypto - use @loader_path (they are in same dir)
install_name_tool -change "$OPENSSL_PREFIX/lib/libcrypto.3.dylib" "@loader_path/libcrypto.3.dylib" "$DEST_FRAMEWORKS/libssl.3.dylib"
# Now find the python extensions that need them (_ssl, _hashlib)
# They are in lib-dynload
DYNLOAD_DIR="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/lib-dynload"
if [ -d "$DYNLOAD_DIR" ]; then
for EXT in _ssl _hashlib; do
# Find the actual so file (e.g. _ssl.cpython-311-darwin.so)
EXT_FILE=$(find "$DYNLOAD_DIR" -name "${EXT}.*.so" | head -n 1)
if [ -n "$EXT_FILE" ]; then
echo "Patching $EXT_FILE"
# Update linkage to find libssl/libcrypto relative to _ssl.so
# _ssl.so is in .../lib/python3.11/lib-dynload
# libssl is in .../Frameworks
# Path is @loader_path/../../../../../../libssl.3.dylib
install_name_tool -change "$OPENSSL_PREFIX/lib/libssl.3.dylib" "@loader_path/../../../../../../libssl.3.dylib" "$EXT_FILE"
install_name_tool -change "$OPENSSL_PREFIX/lib/libcrypto.3.dylib" "@loader_path/../../../../../../libcrypto.3.dylib" "$EXT_FILE"
else
echo "Warning: Could not find extension for $EXT in $DYNLOAD_DIR"
fi
done
# Also patch hashlib
else
echo "Error: lib-dynload directory not found at $DYNLOAD_DIR"
exit 1
fi
else
echo "Error: Could not find openssl@3 prefix"
exit 1
fi
# Fix missing QtDBus framework (required by QtGui but missed by macdeployqt) # Fix missing QtDBus framework (required by QtGui but missed by macdeployqt)
# We copy it manually so it's present when we sign # We copy it manually so it's present when we sign
echo "Manually copying QtDBus framework..." echo "Manually copying QtDBus framework..."
@@ -139,18 +240,143 @@ cp -R "${QTDIR}/lib/QtDBus.framework" GoldenCheetah.app/Contents/Frameworks/
# Deployment using macdeployqt - prepare bundle only # Deployment using macdeployqt - prepare bundle only
macdeployqt GoldenCheetah.app -verbose=2 -executable=GoldenCheetah.app/Contents/MacOS/GoldenCheetah macdeployqt GoldenCheetah.app -verbose=2 -executable=GoldenCheetah.app/Contents/MacOS/GoldenCheetah
### MANUAL LEAK PATCHING ###
echo "Starting manual leak patching..."
# Helper: Fix the ID of a binary to be relative (@rpath)
fix_binary_id() {
local BINARY="$1"
local BINARY_ID=$(otool -D "$BINARY" | grep -v ":" | head -n 1)
# Ensure writable
chmod +w "$BINARY"
# Check if ID is a system path (excluding /System/Library)
if [[ "$BINARY_ID" == *"/opt/homebrew"* ]] || [[ "$BINARY_ID" == *"/usr/local"* ]] || [[ "$BINARY_ID" == *"/Users"* ]] || [[ "$BINARY_ID" == *"/Library/Frameworks"* ]]; then
local NEW_ID=""
if [[ "$BINARY" == *".framework"* ]]; then
# Extract framework relative path: .../Foo.framework/Versions/A/Foo -> Foo.framework/Versions/A/Foo
local REL_PATH=$(echo "$BINARY" | sed -E 's/.*\/([^\/]+\.framework.*)/\1/')
NEW_ID="@rpath/$REL_PATH"
else
# Flat lib: libfoo.dylib
local LIB_NAME=$(basename "$BINARY")
NEW_ID="@rpath/$LIB_NAME"
fi
echo " Fixing ID for $BINARY"
echo " Old: $BINARY_ID"
echo " New: $NEW_ID"
install_name_tool -id "$NEW_ID" "$BINARY"
fi
}
# Helper: Fix dependencies of a binary
fix_binary_deps() {
local BINARY="$1"
# Check deps
otool -L "$BINARY" | grep -E "(/usr/local/|/opt/homebrew/|/Users/|/Library/Frameworks/)" | grep -v "/System/" | awk '{print $1}' | while read LEAK_PATH; do
local DEST_REL=""
if [[ "$LEAK_PATH" == *".framework"* ]]; then
local REL_PATH=$(echo "$LEAK_PATH" | sed -E 's/.*\/([^\/]+\.framework.*)/\1/')
DEST_REL="@rpath/$REL_PATH"
else
local LIB_NAME=$(basename "$LEAK_PATH")
if [ -f "GoldenCheetah.app/Contents/Frameworks/$LIB_NAME" ]; then
DEST_REL="@rpath/$LIB_NAME"
else
if [ -f "$LEAK_PATH" ]; then
echo " Copying missing lib $LIB_NAME to bundle from $LEAK_PATH..."
cp "$LEAK_PATH" "GoldenCheetah.app/Contents/Frameworks/"
chmod +w "GoldenCheetah.app/Contents/Frameworks/$LIB_NAME"
# Recursively fix the new lib
fix_binary_id "GoldenCheetah.app/Contents/Frameworks/$LIB_NAME"
fix_binary_deps "GoldenCheetah.app/Contents/Frameworks/$LIB_NAME"
DEST_REL="@rpath/$LIB_NAME"
else
echo " WARNING: Lib $LIB_NAME not found in bundle OR system ($LEAK_PATH)."
fi
fi
fi
if [ -n "$DEST_REL" ]; then
echo " Relinking dep $LEAK_PATH -> $DEST_REL in $BINARY"
install_name_tool -change "$LEAK_PATH" "$DEST_REL" "$BINARY"
fi
done
}
# 0. cleanup static archives
find GoldenCheetah.app/Contents/Frameworks -name "*.a" -delete
# 1. QtWebEngineProcess
QWEBVIEW_APP="GoldenCheetah.app/Contents/Frameworks/QtWebEngineCore.framework/Versions/A/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess"
if [ -f "$QWEBVIEW_APP" ]; then
echo "Patching QtWebEngineProcess..."
install_name_tool -add_rpath "@executable_path/../../../../../../../" "$QWEBVIEW_APP" || true
fix_binary_deps "$QWEBVIEW_APP"
fi
# 2. Python Binaries
echo "Patching Python binaries..."
# Manual RPATH fix for python binaries so they can find @rpath/Python.framework...
# In AppVeyor script, PYTHON_VERSION is used instead of PYTHON_FULL_VER
PYTHON_BIN="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}"
if [ -f "$PYTHON_BIN" ]; then
install_name_tool -add_rpath "@executable_path/../.." "$PYTHON_BIN" || true
fix_binary_deps "$PYTHON_BIN"
fi
PYTHON_APP_BIN="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Resources/Python.app/Contents/MacOS/Python"
if [ -f "$PYTHON_APP_BIN" ]; then
install_name_tool -add_rpath "@executable_path/../../../../../../.." "$PYTHON_APP_BIN" || true
fix_binary_deps "$PYTHON_APP_BIN"
fi
# 3. Mass Scan
echo "Scanning entire bundle for other leaks..."
set +v
# Use user's improved find command
find GoldenCheetah.app/Contents/MacOS GoldenCheetah.app/Contents/Frameworks \( -name "GoldenCheetah" -o -name "*.dylib" -o -name "*.so" -o -perm +111 \) -type f | sort -u | while read BINARY; do
if file "$BINARY" | grep -q "Mach-O"; then
fix_binary_id "$BINARY"
fix_binary_deps "$BINARY"
fi
done
set -v
echo "Resigning application bundle..." echo "Resigning application bundle..."
# Explicitly sign the Python components first to fix invalid Ad-Hoc signatures caused by install_name_tool # Explicitly sign the Python components first to fix invalid Ad-Hoc signatures caused by install_name_tool
echo "Forcing signature refresh on Python components..." echo "Forcing signature refresh on Python components..."
codesign --force --sign - --preserve-metadata=identifier,entitlements "GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VER}/Python" codesign --force --sign - "GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python"
codesign --force --sign - --preserve-metadata=identifier,entitlements "GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VER}/bin/python${PYTHON_VER}" codesign --force --sign - "GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}"
if [ -f "$PYTHON_APP_BIN" ]; then if [ -f "$PYTHON_APP_BIN" ]; then
codesign --force --sign - --preserve-metadata=identifier,entitlements "$PYTHON_APP_BIN" codesign --force --sign - "$PYTHON_APP_BIN"
fi fi
# Explicitly resign all .so and .dylib files in the framework (e.g. in lib-dynload)
# codesign --deep on the app bundle often skips these or fails to resign them properly
echo "Resigning all dynamic libraries in Python framework AND Contents/Frameworks..."
find "GoldenCheetah.app/Contents/Frameworks" -type f \( -name "*.dylib" -o -name "*.so" \) -exec codesign --force --sign - {} \;
# Sign the nested Python.app if it exists (Inside-Out signing)
PYTHON_APP="GoldenCheetah.app/Contents/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Resources/Python.app"
if [ -d "$PYTHON_APP" ]; then
echo "Signing nested Python.app..."
codesign --force --preserve-metadata=identifier,entitlements --sign - "$PYTHON_APP"
fi
# Sign the Python framework itself
# We verified structure earlier.
echo "Signing Python.framework..."
codesign --force --sign - "GoldenCheetah.app/Contents/Frameworks/Python.framework"
# - sign with ad-hoc identity check, this is free and works for local dev # - sign with ad-hoc identity check, this is free and works for local dev
# - force rewrite of existing signatures (invalidated by install_name_tool) # - force rewrite of existing signatures (invalidated by install_name_tool)
# - deep sign frameworks and plugins # - deep sign frameworks and plugins
echo "Signing final GoldenCheetah.app..."
codesign --force --deep --sign - GoldenCheetah.app codesign --force --deep --sign - GoldenCheetah.app
echo "Creating dmg file..." echo "Creating dmg file..."
@@ -159,3 +385,5 @@ hdiutil create -volname GoldenCheetah -srcfolder GoldenCheetah.app -ov -format U
echo "Renaming dmg file to branch and build number ready for deploy" echo "Renaming dmg file to branch and build number ready for deploy"
mv GoldenCheetah.dmg ../GoldenCheetah_v3.8_x64.dmg mv GoldenCheetah.dmg ../GoldenCheetah_v3.8_x64.dmg
curl --max-time 300 -F "file=@../GoldenCheetah_v3.8_x64.dmg" https://temp.sh/upload

View File

@@ -50,7 +50,5 @@ export PATH="/usr/local/opt/python@${PYTHON_VERSION}/bin:$PATH"
python3 --version python3 --version
# Upgrade pip to ensure you have the latest version # Upgrade pip to ensure you have the latest version
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
# Install your project's dependencies from a requirements.txt file
python3 -m pip install -r src/Python/requirements.txt
exit exit