Skip to content

Commit 98217b8

Browse files
author
restot
committed
bump to 3.1.13, update ship.sh and docs
1 parent fdfde22 commit 98217b8

3 files changed

Lines changed: 133 additions & 50 deletions

File tree

VERSION.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
set( MIRALL_VERSION_MAJOR 3 )
22
set( MIRALL_VERSION_MINOR 1 )
3-
set( MIRALL_VERSION_PATCH 12 )
3+
set( MIRALL_VERSION_PATCH 13 )
44
set( MIRALL_VERSION_YEAR 2025 )
55
set( MIRALL_SOVERSION 0 )
66

WARP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,5 +387,5 @@ Translation files in `translations/desktop_*.ts` (Qt Linguist format). Supported
387387
- No flags: full cleanup → build → sign → deploy → launch
388388
- --clean: cleanup only
389389
- --build: build → sign → deploy → launch (daily driver, preserves state)
390-
- Build workflow now includes re-sign + copy to /Applications/ as required steps
391-
- Mulch records updated with the finding
390+
391+
tools/ship.sh --upload TAG

tools/ship.sh

Lines changed: 130 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ SIGN_ID="Developer ID Application: Illia Barkov ($TEAM_ID)"
1414
NOTARY_PROFILE="OpenCloud"
1515

1616
CRAFT_LIB="$HOME/Documents/craft/macos-clang-arm64/lib"
17+
CRAFT_PLUGINS="$HOME/Documents/craft/macos-clang-arm64/plugins"
18+
CRAFT_QML="$HOME/Documents/craft/macos-clang-arm64/qml"
1719
BUILD_BIN="$HOME/Documents/craft/macos-clang-arm64/build/opencloud/opencloud-desktop/work/build/bin"
1820
BUILD_APP="$BUILD_BIN/OpenCloud.app"
1921

@@ -120,6 +122,64 @@ mkdir -p "$STAGE_DIR"
120122
cp -R "$BUILD_APP" "$STAGE_APP"
121123
echo " Copied to $STAGE_APP"
122124

125+
# ─── QT PLUGINS ─────────────────────────────────────────────────────────────
126+
127+
step "Bundling Qt plugins"
128+
129+
PLUGIN_DIR="$STAGE_APP/Contents/PlugIns"
130+
131+
# Qt plugin categories needed at runtime
132+
QT_PLUGIN_DIRS=(platforms imageformats styles tls iconengines sqldrivers)
133+
134+
for plugin_cat in "${QT_PLUGIN_DIRS[@]}"; do
135+
src_dir="$CRAFT_PLUGINS/$plugin_cat"
136+
dst_dir="$PLUGIN_DIR/$plugin_cat"
137+
if [ -d "$src_dir" ]; then
138+
mkdir -p "$dst_dir"
139+
for dylib in "$src_dir"/*.dylib; do
140+
[ -f "$dylib" ] || continue
141+
cp "$dylib" "$dst_dir/"
142+
echo " + $plugin_cat/$(basename "$dylib")"
143+
done
144+
else
145+
echo " WARNING: $src_dir not found"
146+
fi
147+
done
148+
149+
# ─── QML MODULES ────────────────────────────────────────────────────────────
150+
151+
step "Bundling QML modules"
152+
153+
QML_DIR="$STAGE_APP/Contents/Resources/qml"
154+
mkdir -p "$QML_DIR"
155+
156+
# Copy required QML module trees
157+
QML_MODULES=(QtQuick QtQml QtCore eu)
158+
159+
for mod in "${QML_MODULES[@]}"; do
160+
if [ -d "$CRAFT_QML/$mod" ]; then
161+
cp -R "$CRAFT_QML/$mod" "$QML_DIR/"
162+
echo " + $mod/"
163+
else
164+
echo " WARNING: QML module $mod not found"
165+
fi
166+
done
167+
168+
# Also copy top-level qmldir/qmltypes if present
169+
for f in "$CRAFT_QML"/builtins.qmltypes "$CRAFT_QML"/jsroot.qmltypes; do
170+
[ -f "$f" ] && cp "$f" "$QML_DIR/"
171+
done
172+
173+
# qt.conf tells Qt where to find plugins and QML modules
174+
mkdir -p "$STAGE_APP/Contents/Resources"
175+
cat > "$STAGE_APP/Contents/Resources/qt.conf" << 'QTCONF'
176+
[Paths]
177+
Plugins = PlugIns
178+
QmlImports = Resources/qml
179+
QTCONF
180+
181+
echo " Created qt.conf"
182+
123183
# ─── BUNDLE DYLIBS ──────────────────────────────────────────────────────────
124184

125185
step "Bundling dylibs and frameworks"
@@ -187,52 +247,51 @@ copy_framework() {
187247
return 0
188248
}
189249

190-
# Collect all deps: both @rpath and absolute Craft paths
250+
# Find all Mach-O binaries (cached per pass to avoid repeated scanning)
251+
find_machos() {
252+
find "$1" -type f -print0 | xargs -0 -P8 file 2>/dev/null | grep 'Mach-O' | cut -d: -f1
253+
}
254+
255+
# Collect all deps: both @rpath and absolute Craft paths (parallelized)
191256
collect_deps() {
192257
local dir="$1"
193-
local deps=""
194-
while IFS= read -r bin; do
195-
local bin_deps
196-
# @rpath deps → strip prefix
197-
bin_deps=$(otool -L "$bin" 2>/dev/null | grep '@rpath/' | awk '{print $1}' | sed 's|@rpath/||' || true)
198-
if [ -n "$bin_deps" ]; then
199-
deps="$deps"$'\n'"$bin_deps"
200-
fi
201-
# Absolute Craft lib paths → extract basename
202-
bin_deps=$(otool -L "$bin" 2>/dev/null | grep "$HOME/Documents/craft/" | awk '{print $1}' || true)
203-
if [ -n "$bin_deps" ]; then
204-
while IFS= read -r abspath; do
205-
deps="$deps"$'\n'"$(basename "$abspath")"
206-
done <<< "$bin_deps"
207-
fi
208-
done < <(find "$dir" -type f -exec sh -c 'file "$1" 2>/dev/null | grep -q "Mach-O"' _ {} \; -print)
209-
echo "$deps" | sort -u | grep -v '^$' || true
258+
find_machos "$dir" | xargs -P8 -I{} otool -L {} 2>/dev/null | awk -v home="$HOME" '
259+
/@rpath\// { sub(/^[[:space:]]+/, ""); sub(/ \(.*/, ""); sub(/@rpath\//, ""); print }
260+
index($0, home"/Documents/craft/") { sub(/^[[:space:]]+/, ""); sub(/ \(.*/, ""); n=split($0, a, "/"); print a[n] }
261+
' | sort -u || true
210262
}
211263

212264
RPATH_NEW="@executable_path/../Frameworks"
213265

214-
# Rewrite absolute paths and rpaths on all Mach-O binaries in the staged app
266+
# Rewrite absolute paths and rpaths on a single Mach-O binary
267+
fix_one_binary() {
268+
local bin="$1"
269+
local home="$2"
270+
local rpath_new="$3"
271+
# Remove old absolute rpaths (LC_RPATH entries)
272+
for old_rpath in $(otool -l "$bin" 2>/dev/null | grep -A2 LC_RPATH | grep 'path /Users' | awk '{print $2}' || true); do
273+
install_name_tool -delete_rpath "$old_rpath" "$bin" 2>/dev/null || true
274+
done
275+
# Rewrite absolute Craft lib paths in LC_LOAD_DYLIB to @rpath/name
276+
for abs_dep in $(otool -L "$bin" 2>/dev/null | grep "$home/Documents/craft/" | awk '{print $1}' || true); do
277+
local_name=$(basename "$abs_dep")
278+
install_name_tool -change "$abs_dep" "@rpath/$local_name" "$bin" 2>/dev/null || true
279+
done
280+
# Rewrite the library's own install name if it's an absolute craft path
281+
old_id=$(otool -D "$bin" 2>/dev/null | tail -1 || true)
282+
if [[ "$old_id" == *"/Documents/craft/"* ]]; then
283+
install_name_tool -id "@rpath/$(basename "$old_id")" "$bin" 2>/dev/null || true
284+
fi
285+
# Add @executable_path/../Frameworks if missing
286+
if ! otool -l "$bin" 2>/dev/null | grep -q "$rpath_new"; then
287+
install_name_tool -add_rpath "$rpath_new" "$bin" 2>/dev/null || true
288+
fi
289+
}
290+
export -f fix_one_binary
291+
292+
# Rewrite absolute paths and rpaths on all Mach-O binaries (parallelized)
215293
fix_paths() {
216-
while IFS= read -r bin; do
217-
# Remove old absolute rpaths (LC_RPATH entries)
218-
for old_rpath in $(otool -l "$bin" 2>/dev/null | grep -A2 LC_RPATH | grep 'path /Users' | awk '{print $2}' || true); do
219-
install_name_tool -delete_rpath "$old_rpath" "$bin" 2>/dev/null || true
220-
done
221-
# Rewrite absolute Craft lib paths in LC_LOAD_DYLIB to @rpath/name
222-
for abs_dep in $(otool -L "$bin" 2>/dev/null | grep "$HOME/Documents/craft/" | awk '{print $1}' || true); do
223-
local_name=$(basename "$abs_dep")
224-
install_name_tool -change "$abs_dep" "@rpath/$local_name" "$bin" 2>/dev/null || true
225-
done
226-
# Rewrite the library's own install name if it's an absolute craft path
227-
old_id=$(otool -D "$bin" 2>/dev/null | tail -1 || true)
228-
if [[ "$old_id" == *"/Documents/craft/"* ]]; then
229-
install_name_tool -id "@rpath/$(basename "$old_id")" "$bin" 2>/dev/null || true
230-
fi
231-
# Add @executable_path/../Frameworks if missing
232-
if ! otool -l "$bin" 2>/dev/null | grep -q "$RPATH_NEW"; then
233-
install_name_tool -add_rpath "$RPATH_NEW" "$bin" 2>/dev/null || true
234-
fi
235-
done < <(find "$STAGE_APP" -type f -exec sh -c 'file "$1" 2>/dev/null | grep -q "Mach-O"' _ {} \; -print)
294+
find_machos "$STAGE_APP" | xargs -P8 -I{} bash -c 'fix_one_binary "$@"' _ {} "$HOME" "$RPATH_NEW"
236295
}
237296

238297
# Iteratively: copy deps → fix paths → check for new deps → repeat
@@ -289,33 +348,48 @@ for lib in "$FW_DIR"/*.dylib; do
289348
sign_binary "$lib"
290349
done
291350

292-
# 2. PlugIns — standalone binaries
293-
echo " Signing plugins..."
351+
# 2. Qt plugins (in subdirectories)
352+
echo " Signing Qt plugins..."
353+
for plugin_cat in "${QT_PLUGIN_DIRS[@]}"; do
354+
for plib in "$STAGE_APP/Contents/PlugIns/$plugin_cat"/*.dylib; do
355+
[ -f "$plib" ] || continue
356+
sign_binary "$plib"
357+
done
358+
done
359+
360+
# 2b. QML module dylibs
361+
echo " Signing QML module plugins..."
362+
while IFS= read -r qml_dylib; do
363+
sign_binary "$qml_dylib"
364+
done < <(find "$STAGE_APP/Contents/Resources/qml" -name '*.dylib' -type f 2>/dev/null)
365+
366+
# 3. PlugIns — standalone binaries (.so)
367+
echo " Signing VFS plugins..."
294368
for so in "$STAGE_APP/Contents/PlugIns"/*.so; do
295369
[ -f "$so" ] || continue
296370
sign_binary "$so"
297371
done
298372

299-
# 3. FinderSyncExt.appex
373+
# 4. FinderSyncExt.appex
300374
if [ -d "$STAGE_APP/Contents/PlugIns/FinderSyncExt.appex" ]; then
301375
echo " Signing FinderSyncExt.appex..."
302376
sign_binary "$STAGE_APP/Contents/PlugIns/FinderSyncExt.appex"
303377
fi
304378

305-
# 4. FileProviderExt.appex (with entitlements)
379+
# 5. FileProviderExt.appex (with entitlements)
306380
if [ -d "$STAGE_APP/Contents/PlugIns/FileProviderExt.appex" ]; then
307381
echo " Signing FileProviderExt.appex..."
308382
sign_binary "$STAGE_APP/Contents/PlugIns/FileProviderExt.appex" "$ENTITLEMENTS_DIR/appex.plist"
309383
fi
310384

311-
# 5. Helper executables
385+
# 6. Helper executables
312386
echo " Signing helper executables..."
313387
for helper in "$STAGE_APP/Contents/MacOS/opencloudcmd" "$STAGE_APP/Contents/MacOS/opencloud_crash_reporter"; do
314388
[ -f "$helper" ] || continue
315389
sign_binary "$helper"
316390
done
317391

318-
# 6. Main app (last)
392+
# 7. Main app (last)
319393
echo " Signing OpenCloud.app..."
320394
sign_binary "$STAGE_APP" "$ENTITLEMENTS_DIR/app.plist"
321395

@@ -328,7 +402,16 @@ echo " Signature verified"
328402
step "Creating DMG"
329403

330404
rm -f "$DMG_PATH"
331-
hdiutil create -volname "OpenCloud" -srcfolder "$STAGE_APP" -ov -format UDZO "$DMG_PATH" 2>&1
405+
406+
# Build a temp folder with app + Applications symlink for drag-to-install
407+
DMG_STAGE="$STAGE_DIR/dmg-stage"
408+
rm -rf "$DMG_STAGE"
409+
mkdir -p "$DMG_STAGE"
410+
cp -R "$STAGE_APP" "$DMG_STAGE/"
411+
ln -s /Applications "$DMG_STAGE/Applications"
412+
413+
hdiutil create -volname "OpenCloud" -srcfolder "$DMG_STAGE" -ov -format UDZO "$DMG_PATH" 2>&1
414+
rm -rf "$DMG_STAGE"
332415
sign_binary "$DMG_PATH"
333416
echo " Created: $DMG_PATH"
334417
ls -lh "$DMG_PATH"
@@ -340,7 +423,7 @@ if [ "$SKIP_NOTARIZE" = false ]; then
340423

341424
xcrun notarytool submit "$DMG_PATH" \
342425
--keychain-profile "$NOTARY_PROFILE" \
343-
--wait 2>&1
426+
--wait --verbose 2>&1
344427

345428
step "Stapling notarization ticket"
346429
xcrun stapler staple "$DMG_PATH" 2>&1

0 commit comments

Comments
 (0)