From 4cbbe37b4090305d7f204bf215d3fb7c4eb5b386 Mon Sep 17 00:00:00 2001 From: Zeyu Yang <40936154+zeyuyang42@users.noreply.github.com> Date: Sat, 17 Oct 2026 10:33:03 +0200 Subject: [PATCH] Package zips: no __MACOSX tree, no .DS_Store (board ID 182) ditto --sequesterRsrc wrote resource forks and extended attributes as a __MACOSX/._* tree (89 entries in the 0.3.0 Max zip), and Finder's .DS_Store files were copied along with media/ and the bundles. The zip helper in build.sh and the CI step now use --norsrc and delete .DS_Store before zipping; the CMake install rules exclude .DS_Store where they copy whole folders; CI fails the Max job if the zip still carries either. Permissions and the ad-hoc signatures are untouched (checked: codesign --verify --deep --strict on the unzipped bundles). The -p step also drops every stale zip in dist/, not only the ones with the current naming. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/ci.yml | 6 +++++- build.sh | 14 +++++++++----- docs/design/release-process.md | 1 + maxmsp/CMakeLists.txt | 5 +++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a5b4b2..8af7beb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -304,9 +304,13 @@ jobs: echo "$name: $(lipo -archs "$bundle/Contents/MacOS/$name")" done version=$(sed -n 's/.*"version" *: *"\([^"]*\)".*/\1/p' maxmsp/package-info.json | head -n 1) - ( cd maxmsp/dist && ditto -c -k --sequesterRsrc --keepParent Zerr "zerr-max-${version}-macos-arm64.zip" ) + ( cd maxmsp/dist && ditto -c -k --norsrc --keepParent Zerr "zerr-max-${version}-macos-arm64.zip" ) find maxmsp/dist/Zerr -type f | sort ls -l maxmsp/dist/*.zip + # Same flags as build.sh zip_dir(): no __MACOSX/._* tree, no Finder files. + if unzip -l maxmsp/dist/zerr-max-*.zip | grep -e '__MACOSX' -e '\.DS_Store'; then + echo "::error::the Max zip carries macOS metadata files"; exit 1 + fi - name: Upload Max package uses: actions/upload-artifact@v4 diff --git a/build.sh b/build.sh index 0394d1b..5443ff5 100755 --- a/build.sh +++ b/build.sh @@ -328,7 +328,7 @@ package_puredata() { local zip zip="zerr-pd-$(pd_version)-$(host_os)-$(host_arch).zip" - rm -f "$dist"/zerr-pd-*.zip + rm -f "$dist"/*.zip # also zips from a previous version, architecture or naming zip_dir "$dist" zerr "$zip" echo "Pure Data package assembled: $dist/zerr" echo "Pure Data package zipped: $dist/$zip" @@ -412,7 +412,7 @@ package_maxmsp() { # stays Zerr/, the Max package name. local zip="zerr-max-$(max_version)-macos-${archs}.zip" - rm -f "$dist"/zerr-max-*.zip # also zips from a previous version or architecture + rm -f "$dist"/*.zip # also zips from a previous version, architecture or naming zip_dir "$dist" Zerr "$zip" echo "Max package assembled: $dist/Zerr" echo "Max package zipped: $dist/$zip" @@ -448,12 +448,16 @@ host_arch() { } # zip_dir : zips / as / with the -# folder as the top-level entry. ditto keeps the bundle metadata and permissions a -# plain zip of a .mxo can lose; elsewhere CMake's tar does the job. +# folder as the top-level entry. ditto keeps the bundle permissions a plain zip of a +# .mxo can lose; --norsrc leaves out resource forks and extended attributes, which +# --sequesterRsrc would write as a __MACOSX/._* tree that Windows and Linux users see +# as junk (a code signature lives in _CodeSignature/, not in an attribute). Finder's +# .DS_Store files are dropped first. Elsewhere CMake's tar does the job. zip_dir() { local parent="$1" folder="$2" zip="$3" + find "$parent/$folder" -name .DS_Store -delete if command -v ditto &> /dev/null; then - ( cd "$parent" && ditto -c -k --sequesterRsrc --keepParent "$folder" "$zip" ) + ( cd "$parent" && ditto -c -k --norsrc --keepParent "$folder" "$zip" ) else ( cd "$parent" && cmake -E tar cf "$zip" --format=zip "$folder" ) fi diff --git a/docs/design/release-process.md b/docs/design/release-process.md index 7493154..9fbb62e 100644 --- a/docs/design/release-process.md +++ b/docs/design/release-process.md @@ -127,6 +127,7 @@ Checks: codesign --verify --deep --strict maxmsp/dist/Zerr/externals/*.mxo lipo -archs 'maxmsp/dist/Zerr/externals/zerr.features~.mxo/Contents/MacOS/zerr.features~' # arm64 unzip -l maxmsp/dist/zerr-max-*.zip | head +unzip -l maxmsp/dist/zerr-max-*.zip | grep -c -e __MACOSX -e .DS_Store # 0: ditto --norsrc, no Finder files ``` CI (`maxmsp (macos)` job) performs the same assembly and uploads the zip as `zerr-max-macos-arm64`; diff --git a/maxmsp/CMakeLists.txt b/maxmsp/CMakeLists.txt index 05a115d..0e18534 100644 --- a/maxmsp/CMakeLists.txt +++ b/maxmsp/CMakeLists.txt @@ -110,7 +110,7 @@ endif() # the ad-hoc signature max-posttarget.cmake applied; CI verifies it after install. foreach (extern_name ${ZERR_MAX_EXTERNALS}) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/externals/${extern_name}.mxo" - DESTINATION externals USE_SOURCE_PERMISSIONS) + DESTINATION externals USE_SOURCE_PERMISSIONS PATTERN ".DS_Store" EXCLUDE) endforeach () install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/help/" DESTINATION help FILES_MATCHING PATTERN "*.maxhelp" PATTERN "*.mxo" EXCLUDE) @@ -121,7 +121,8 @@ install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/docs/" DESTINATION docs FILES_MATCHING PATTERN "*.maxref.xml") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/examples/" DESTINATION examples FILES_MATCHING PATTERN "*.maxpat" PATTERN "*.yaml" PATTERN "README.md") -install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/media/" DESTINATION media) +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/media/" DESTINATION media + PATTERN ".DS_Store" EXCLUDE) # Speaker layouts shipped with the package. Max adds a package's misc/ folder to # the search path, so `zerr.envelopes~ trigger ring_8` resolves without a path. install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../configs/" DESTINATION misc