Add missing icons for _playlist to the macOS build.
[dcpomatic.git] / platform / osx / make_dmg.sh
1 #!/bin/bash
2 #
3 # Syntax: make_dmg.sh <environment> <builddir> <type> <apple-id> <apple-password>
4 # where <type> is universal or thin
5 #
6 # e.g. make_dmg.sh /Users/carl/osx-environment /Users/carl/cdist universal foo@bar.net opensesame
7
8 # Don't set -e here as egrep (used a few times) returns 1 if no matches
9 # were found.
10
11 version=`git describe --tags --abbrev=0 | sed -e "s/v//"`
12
13 # DMG size in megabytes
14 DMG_SIZE=256
15 ENV=$1
16 ROOT=$2
17 TYPE=$3
18 APPLE_ID=$4
19 APPLE_PASSWORD=$5
20
21 if [ "$TYPE" != "universal" -a "$TYPE" != "thin" ]; then
22     echo "Syntax: $0 <builddir> <type>"
23     echo "where <type> is universal or thin"
24     exit 1
25 fi
26
27 # This is our work area for making up the .dmgs
28 mkdir -p build/platform/osx
29 cd build/platform/osx
30
31 function copy {
32     case $TYPE in
33         universal)
34             for f in $1/32/$2; do
35                 if [ -h $f ]; then
36                     ln -s $(readlink $f) "$3/`basename $f`"
37                 else
38                     g=`echo $f | sed -e "s/\/32\//\/64\//g"`
39                     mkdir -p "$3"
40                     lipo -create $f $g -output "$3/`basename $f`"
41                 fi
42             done
43             ;;
44         thin)
45             if [ -h $1/$2 ]; then
46                 ln -s $(readlink $1/$2) "$3/`basename $f`"
47             else
48                 cp $1/$2 "$3"
49             fi
50             ;;
51     esac
52 }
53
54 function copy_lib_root {
55     case $TYPE in
56         universal)
57             for f in $ROOT/32/lib/$1*.dylib; do
58                 if [ -h $f ]; then
59                     ln -s $(readlink $f) "$2/`basename $f`"
60                 else
61                     g=`echo $f | sed -e "s/\/32\//\/64\//g"`
62                     mkdir -p "$2"
63                     lipo -create $f $g -output "$2/`basename $f`"
64                 fi
65             done
66             ;;
67         thin)
68             for f in $ROOT/lib/$1*.dylib; do
69                 if [ -h $f ]; then
70                     ln -s $(readlink $f) "$2/`basename $f`"
71                 else
72                     mkdir -p "$2"
73                     cp $f "$2"
74                 fi
75             done
76             ;;
77     esac
78     to_relink="$to_relink|$1"
79 }
80
81 function copy_lib_env {
82     case $TYPE in
83         universal)
84             for f in $ENV/32/lib/$1*.dylib; do
85                 if [ -h $f ]; then
86                     ln -s $(readlink $f) "$2/`basename $f`"
87                 else
88                     g=`echo $f | sed -e "s/\/32\//\/64\//g"`
89                     mkdir -p "$2"
90                     lipo -create $f $g -output "$2/`basename $f`"
91                 fi
92             done
93             ;;
94         thin)
95             for f in $ENV/64/lib/$1*.dylib; do
96                 if [ -h $f ]; then
97                     ln -s $(readlink $f) "$2/`basename $f`"
98                 else
99                     mkdir -p "$2"
100                     cp $f "$2"
101                 fi
102             done
103             ;;
104     esac
105     to_relink="$to_relink|$1"
106 }
107
108 # @param #1 directory to copy to
109 function copy_libs {
110     local dest="$1"
111     copy_lib_root libcxml "$dest"
112     copy_lib_root libdcp-1.0 "$dest"
113     copy_lib_root libasdcp-carl "$dest"
114     copy_lib_root libkumu-carl "$dest"
115     copy_lib_root libsub "$dest"
116     copy_lib_root libopenjp2 "$dest"
117     copy_lib_root libavdevice "$dest"
118     copy_lib_root libavformat "$dest"
119     copy_lib_root libavfilter "$dest"
120     copy_lib_root libavutil "$dest"
121     copy_lib_root libavcodec "$dest"
122     copy_lib_root libswscale "$dest"
123     copy_lib_root libpostproc "$dest"
124     copy_lib_root libswresample "$dest"
125     copy $ROOT src/dcpomatic/build/src/lib/libdcpomatic2.dylib "$dest"
126     copy $ROOT src/dcpomatic/build/src/wx/libdcpomatic2-wx.dylib "$dest"
127     copy_lib_env libboost_system "$dest"
128     copy_lib_env libboost_filesystem "$dest"
129     copy_lib_env libboost_thread "$dest"
130     copy_lib_env libboost_date_time "$dest"
131     copy_lib_env libboost_locale "$dest"
132     copy_lib_env libboost_regex "$dest"
133     copy_lib_env libxml++ "$dest"
134     copy_lib_env libxslt "$dest"
135     copy_lib_env libxml2 "$dest"
136     copy_lib_env libglibmm-2.4 "$dest"
137     copy_lib_env libgobject "$dest"
138     copy_lib_env libgthread "$dest"
139     copy_lib_env libgmodule "$dest"
140     copy_lib_env libsigc "$dest"
141     copy_lib_env libglib-2 "$dest"
142     copy_lib_env libintl "$dest"
143     copy_lib_env libsndfile "$dest"
144     copy_lib_env libssh "$dest"
145     copy_lib_env libwx "$dest"
146     copy_lib_env libfontconfig "$dest"
147     copy_lib_env libfreetype "$dest"
148     copy_lib_env libexpat "$dest"
149     copy_lib_env libltdl "$dest"
150     copy_lib_env libxmlsec1 "$dest"
151     copy_lib_env libcurl "$dest"
152     copy_lib_env libffi "$dest"
153     copy_lib_env libpango "$dest"
154     copy_lib_env libcairo "$dest"
155     copy_lib_env libpixman "$dest"
156     copy_lib_env libharfbuzz "$dest"
157     copy_lib_env libsamplerate "$dest"
158     copy_lib_env libicui18n "$dest"
159     copy_lib_env libicudata "$dest"
160     copy_lib_env libicuio "$dest"
161     copy_lib_env libicule "$dest"
162     copy_lib_env libiculx "$dest"
163     copy_lib_env libicutest "$dest"
164     copy_lib_env libicutu "$dest"
165     copy_lib_env libicuuc "$dest"
166     copy_lib_env libFLAC "$dest"
167     copy_lib_env libvorbis "$dest"
168     copy_lib_env libogg "$dest"
169     copy_lib_env libxerces-c "$dest"
170 }
171
172 # @param #1 directory to copy to
173 function copy_resources {
174     local dest="$1"
175     case $TYPE in
176         universal)
177             local prefix=$ROOT/32
178             ;;
179         thin)
180             local prefix=$ROOT
181             ;;
182     esac
183     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic_small.png "$dest"
184     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2.icns "$dest"
185     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_kdm.icns "$dest"
186     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_server.icns "$dest"
187     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_player.icns "$dest"
188     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_batch.icns "$dest"
189     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_playlist.icns "$dest"
190     cp $prefix/src/dcpomatic/graphics/osx/preferences/colour_conversions.png "$dest"
191     cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults.png "$dest"
192     cp $prefix/src/dcpomatic/graphics/osx/preferences/kdm_email.png "$dest"
193     cp $prefix/src/dcpomatic/graphics/osx/preferences/email.png "$dest"
194     cp $prefix/src/dcpomatic/graphics/osx/preferences/servers.png "$dest"
195     cp $prefix/src/dcpomatic/graphics/osx/preferences/tms.png "$dest"
196     cp $prefix/src/dcpomatic/graphics/osx/preferences/keys.png "$dest"
197     cp $prefix/src/dcpomatic/graphics/osx/preferences/cover_sheet.png "$dest"
198     cp $prefix/src/dcpomatic/graphics/osx/preferences/notifications.png "$dest"
199     cp $prefix/src/dcpomatic/graphics/osx/preferences/locations.png "$dest"
200     cp $prefix/src/dcpomatic/graphics/osx/preferences/sound.png "$dest"
201     cp $prefix/src/dcpomatic/fonts/LiberationSans-Regular.ttf "$dest"
202     cp $prefix/src/dcpomatic/fonts/LiberationSans-Italic.ttf "$dest"
203     cp $prefix/src/dcpomatic/fonts/LiberationSans-Bold.ttf "$dest"
204     cp $prefix/src/dcpomatic/fonts/fonts.conf.osx "$dest"/fonts.conf
205     cp $prefix/src/dcpomatic/graphics/splash.png "$dest"
206     cp $prefix/src/dcpomatic/graphics/zoom.png "$dest"
207     cp $prefix/src/dcpomatic/graphics/zoom_all.png "$dest"
208     cp $prefix/src/dcpomatic/graphics/select.png "$dest"
209     cp $prefix/src/dcpomatic/graphics/snap.png "$dest"
210     cp $prefix/src/dcpomatic/graphics/sequence.png "$dest"
211     cp $prefix/src/dcpomatic/graphics/me.jpg "$dest"
212     cp -r $prefix/share/libdcp/xsd "$dest"
213
214     # i18n: DCP-o-matic .mo files
215     for lang in de_DE es_ES fr_FR it_IT sv_SE nl_NL ru_RU pl_PL da_DK pt_PT pt_BR sk_SK cs_CZ uk_UA zh_CN tr_TR; do
216         mkdir -p "$dest/$lang/LC_MESSAGES"
217         cp $prefix/src/dcpomatic/build/src/lib/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
218         cp $prefix/src/dcpomatic/build/src/wx/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
219         cp $prefix/src/dcpomatic/build/src/tools/mo/$lang/*.mo "$dest/$lang/LC_MESSAGES"
220     done
221
222     # i18n: wxWidgets .mo files
223     for lang in de es fr it sv nl ru pl da cs; do
224         mkdir "$dest/$lang"
225         cp $ENV/64/share/locale/$lang/LC_MESSAGES/wxstd.mo "$dest/$lang"
226     done
227 }
228
229 # param $1 list of things that link to other things
230 function relink {
231     to_relink=`echo $to_relink | sed -e "s/\+//g"`
232     local linkers=("$@")
233
234     for obj in "${linkers[@]}"; do
235         deps=`otool -L "$obj" | awk '{print $1}' | egrep "($to_relink)" | egrep "($ENV|$ROOT|boost|libicu)"`
236         changes=""
237         for dep in $deps; do
238             base=`basename $dep`
239             if [ "$TYPE" == "universal" ]; then
240                 # $dep will be a path within 64/; make a 32/ path too
241                 dep32=`echo $dep | sed -e "s/\/64\//\/32\//g"`
242                 changes="$changes -change $dep @executable_path/../Frameworks/$base -change $dep32 @executable_path/../Frameworks/$base"
243             else
244                 changes="$changes -change $dep @executable_path/../Frameworks/$base"
245             fi
246         done
247         if test "x$changes" != "x"; then
248             install_name_tool $changes -id `basename "$obj"` "$obj"
249         fi
250     done
251 }
252
253 # @param #1 .app directory
254 # @param #2 full name e.g. DCP-o-matic Batch Converter
255 # @param #3 bundle id e.g. com.dcpomatic.batch
256 function make_dmg {
257     local appdir="$1"
258     local full_name="$2"
259     local bundle_id="$3"
260     tmp_dmg=dcpomatic_tmp.dmg
261     dmg="$full_name $version.dmg"
262     vol_name=DCP-o-matic-$version
263
264     codesign --deep --force --verify --verbose --options runtime --sign "Developer ID Application: Carl Hetherington (R82DXSR997)" "$appdir"
265     if [ "$?" != "0" ]; then
266         echo "Failed to sign .app"
267         exit 1
268     fi
269
270     mkdir -p $vol_name
271     cp -a "$appdir" $vol_name
272     ln -s /Applications "$vol_name/Applications"
273     cat<<EOF > "$vol_name/READ ME.txt"
274 Welcome to DCP-o-matic!  The first time you run the program there may be
275 a long (several-minute) delay while OS X checks the code for viruses and
276 other malware.  Please be patient!
277 EOF
278     cat<<EOF > "$vol_name/READ ME.de_DE.txt"
279 Beim erstmaligen Start der DCP-o-matic Anwendungen kann ein längerer
280 Verifikationsvorgang auftreten.  Dies ist von der OS X Sicherheitsumgebung
281 'Gatekeeper' verursacht.  Dieser je nach Rechner teils minutenlange
282 Verifikationsvorgang ist gegenwärtig normal und nicht zu umgehen,
283 es ist kein Programmfehler.  Warten sie die Verifikation für jede der
284 DCP-o-matic Anwendungen ab, bei weiteren Programmstarts wird sie nicht
285 mehr auftreten.
286 EOF
287
288     rm -f $tmp_dmg "$dmg"
289     hdiutil create -srcfolder $vol_name -volname $vol_name -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW -size $DMG_SIZE $tmp_dmg
290     attach=$(hdiutil attach -readwrite -noverify -noautoopen $tmp_dmg)
291     device=`echo $attach | egrep '^/dev/' | sed 1q | awk '{print $5}'`
292     sleep 5
293
294     echo '
295   tell application "Finder"
296     tell disk "'$vol_name'"
297            open
298            set current view of container window to icon view
299            set toolbar visible of container window to false
300            set statusbar visible of container window to false
301            set the bounds of container window to {400, 200, 940, 300}
302            set theViewOptions to the icon view options of container window
303            set arrangement of theViewOptions to not arranged
304            set icon size of theViewOptions to 64
305            set position of item "'$appdir'" of container window to {90, 80}
306            set position of item "Applications" of container window to {265, 80}
307            set position of item "READ ME.txt" of container window to {430, 80}
308            set position of item "READ ME.de_DE.txt" of container window to {595, 80}
309            close
310            open
311            update without registering applications
312            delay 5
313      end tell
314    end tell
315 ' | osascript
316
317     chmod -Rf go-w /Volumes/"$vol_name"/"$appdir"
318     sync
319
320     hdiutil eject $device
321     hdiutil convert -format UDZO $tmp_dmg -imagekey zlib-level=9 -o "$dmg"
322     sips -i "$appdir/Contents/Resources/dcpomatic2.icns"
323     DeRez -only icns "$appdir/Contents/Resources/dcpomatic2.icns" > "$appdir/Contents/Resources/DCP-o-matic.rsrc"
324     Rez -append "$appdir/Contents/Resources/DCP-o-matic.rsrc" -o "$dmg"
325     SetFile -a C "$dmg"
326     xattr -c "$dmg"
327
328     set -e
329     codesign --verify --verbose --options runtime --sign "Developer ID Application: Carl Hetherington (R82DXSR997)" "$dmg"
330
331     # We only notarize thin builds, as if we're building universal binaries we must be on an OS
332     # sufficiently old that it can't notarize anyway
333     if [ "$TYPE" == "thin" ]; then
334
335         id=$(xcrun altool --notarize-app -t osx -f "$dmg" --primary-bundle-id $bundle_id -u $APPLE_ID -p $APPLE_PASSWORD --output-format xml | grep -C1 RequestUUID | tail -n 1 | sed -e "s/<string>//g" | sed -e "s/<\/string>//g")
336         N=0
337         while [ 1 ]; do
338             echo "Checking up on $id"
339             status=$(xcrun altool --notarization-info $id -u $APPLE_ID -p $APPLE_PASSWORD --output-format xml)
340             summary=$(echo "$status" | grep -C1 "<key>Status</key>" | tail -n 1 | sed -e "s/    .//g")
341             echo "Got $summary"
342             if [ "$summary" == "<string>invalid</string>" ]; then
343                 echo "Notarization failed."
344                 echo $status
345                 exit 1
346             fi
347             if [ "$summary" == "<string>success</string>" ]; then
348                 break
349             fi
350             sleep 30
351             N=$((N+1))
352             if [ "$N" == "30" ]; then
353                 echo "Timed out waiting for notarization"
354                 exit 1
355             fi
356         done
357
358         xcrun stapler staple "$dmg"
359     fi
360     set +e
361
362     rm $tmp_dmg
363     rm -rf $vol_name
364 }
365
366 # @param #1 appdir
367 function setup {
368     appdir="$1"
369     approot="$appdir/Contents"
370     rm -rf "$appdir"
371     mkdir -p "$approot/MacOS"
372     mkdir -p "$approot/Frameworks"
373     mkdir -p "$approot/Resources"
374
375     to_relink="dcpomatic"
376     copy_libs "$approot/Frameworks"
377     copy_resources "$approot/Resources"
378 }
379
380 case $TYPE in
381     universal)
382         prefix=$ROOT/32
383         ;;
384     thin)
385         prefix=$ROOT
386         ;;
387 esac
388
389 # DCP-o-matic main
390 setup "DCP-o-matic 2.app"
391 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2 "$approot/MacOS"
392 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_cli "$approot/MacOS"
393 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_create "$approot/MacOS"
394 copy $ROOT bin/ffprobe "$approot/MacOS"
395 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
396 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2.Info.plist "$approot/Info.plist"
397 rl=("$approot/MacOS/dcpomatic2" "$approot/MacOS/dcpomatic2_cli" "$approot/MacOS/dcpomatic2_create" "$approot/MacOS/ffprobe" "$approot/Frameworks/"*.dylib)
398 relink "${rl[@]}"
399 make_dmg "$appdir" "DCP-o-matic" com.dcpomatic
400
401 # DCP-o-matic KDM Creator
402 setup "DCP-o-matic 2 KDM Creator.app"
403 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_kdm "$approot/MacOS"
404 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_kdm_cli "$approot/MacOS"
405 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
406 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_kdm.Info.plist "$approot/Info.plist"
407 rl=("$approot/MacOS/dcpomatic2_kdm" "$approot/MacOS/dcpomatic2_kdm_cli" "$approot/Frameworks/"*.dylib)
408 relink "${rl[@]}"
409 make_dmg "$appdir" "DCP-o-matic KDM Creator" com.dcpomatic.kdm
410
411 # DCP-o-matic Encode Server
412 setup "DCP-o-matic 2 Encode Server.app"
413 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_server "$approot/MacOS"
414 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_server_cli "$approot/MacOS"
415 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
416 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_server.Info.plist "$approot/Info.plist"
417 rl=("$approot/MacOS/dcpomatic2_server" "$approot/MacOS/dcpomatic2_server_cli" "$approot/Frameworks/"*.dylib)
418 relink "${rl[@]}"
419 make_dmg "$appdir" "DCP-o-matic Encode Server" com.dcpomatic.server
420
421 # DCP-o-matic Batch Converter
422 setup "DCP-o-matic 2 Batch converter.app"
423 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_batch "$approot/MacOS"
424 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
425 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_batch.Info.plist "$approot/Info.plist"
426 rl=("$approot/MacOS/dcpomatic2_batch" "$approot/Frameworks/"*.dylib)
427 relink "${rl[@]}"
428 make_dmg "$appdir" "DCP-o-matic Batch Converter" com.dcpomatic.batch
429
430 # DCP-o-matic Player
431 setup "DCP-o-matic 2 Player.app"
432 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_player "$approot/MacOS"
433 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
434 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_player.Info.plist "$approot/Info.plist"
435 rl=("$approot/MacOS/dcpomatic2_player" "$approot/Frameworks/"*.dylib)
436 relink "${rl[@]}"
437 make_dmg "$appdir" "DCP-o-matic Player" com.dcpomatic.player
438
439 # DCP-o-matic Playlist Editor
440 setup "DCP-o-matic 2 Playlist Editor.app"
441 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_playlist "$approot/MacOS"
442 copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
443 cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_playlist.Info.plist "$approot/Info.plist"
444 rl=("$approot/MacOS/dcpomatic2_playlist" "$approot/Frameworks/"*.dylib)
445 relink "${rl[@]}"
446 make_dmg "$appdir" "DCP-o-matic Playlist Editor" com.dcpomatic.playlist