diff --git a/.github/workflows/macOS.yml b/.github/workflows/macOS.yml index 2d9db6f..799ddec 100644 --- a/.github/workflows/macOS.yml +++ b/.github/workflows/macOS.yml @@ -55,10 +55,8 @@ jobs: - name: assemble bundle run: | bash build-mac-app.sh - mv macos/snappy/SnapPy.app . - tar cfz Snappy_app.tgz SnapPy.app - uses: actions/upload-artifact@v3 with: - name: SnapPy_app.tgz - path: ./SnapPy_app.tgz + name: SnapPy.dmg + path: ./macOS/dmg-maker/SnapPy.dmg diff --git a/build-mac-app.sh b/build-mac-app.sh index a24516b..bda112b 100644 --- a/build-mac-app.sh +++ b/build-mac-app.sh @@ -3,3 +3,8 @@ cd macOS rm -rf snappy/SnapPy.app . bin/make-bundle.sh . bin/sign-bundle.sh +rm -rf dist +mkdir dist +mv snappy/SnapPy.app dist +. bin/notarize.sh + diff --git a/macOS/bin/notarize.sh b/macOS/bin/notarize.sh new file mode 100644 index 0000000..0cf0660 --- /dev/null +++ b/macOS/bin/notarize.sh @@ -0,0 +1,18 @@ +#!/bin/bash +source Ids.sh +set -e +cd dmg-maker +APP="../dist/SnapPy.app" +DMG="SnapPy.dmg" +OPTIONS="--wait --no-progress --apple-id $USERNAME \ +--team-id $IDENTITY --password $PASSWORD --wait" +python3 dmg-maker.py +echo "Notarizing app ..." +xcrun notarytool submit $DMG $OPTIONS +xcrun stapler staple $APP +python3 dmg-maker.py +echo "Signing disk image ..." +codesign -s $IDENTITY --timestamp --options runtime --force $DMG +echo "Notarizing disk image ..." +xcrun notarytool submit $DMG $OPTIONS +xcrun stapler staple $DMG diff --git a/macOS/bin/sign-bundle.sh b/macOS/bin/sign-bundle.sh index bc81fea..c30aa4d 100644 --- a/macOS/bin/sign-bundle.sh +++ b/macOS/bin/sign-bundle.sh @@ -4,7 +4,7 @@ set -e APP=SnapPy.app WORK_DIR=snappy -echo Signing SnapPy.app +echo "Signing $APP ..." FRAMEWORKS=$APP/Contents/Frameworks MACOS=$APP/Contents/MacOS pushd $WORK_DIR @@ -24,6 +24,8 @@ done $SIGN $APP # Of course spctl will fail, since the app is not notarized. -# But we want to see what it says. +# But we want to see what it says anyway. +echo "Verifying with spctl - should be rejected as unnotarized ..." spctl --verbose --assess SnapPy.app || true popd + diff --git a/macOS/dmg-maker/background.png b/macOS/dmg-maker/background.png new file mode 100644 index 0000000..25b31a8 Binary files /dev/null and b/macOS/dmg-maker/background.png differ diff --git a/macOS/dmg-maker/dmg-maker.py b/macOS/dmg-maker/dmg-maker.py new file mode 100755 index 0000000..e19ec89 --- /dev/null +++ b/macOS/dmg-maker/dmg-maker.py @@ -0,0 +1,68 @@ +#! /usr/bin/env python3 +""" +Creates a nice disk image, with background and /Applications symlink +for the app. + +One issue here is that Snow Leopard uses a different (undocumented, of +course) format for the .DS_Store files than earlier versions, which makes +disk images created on it not work correctly on those systems. Thus this "solution" uses a .DS_Store file created on Leopard as follows: + +(1) Use Disk Utility to create a r/w DMG large enough to store everything and open it. + +(2) Copy over the application and add a symlink to /Applications. + +(3) Create a subdirectory ".background" containing the file "background.png". + +(4) Open the disk image in the Finder and do View->Hide Tool Bar and then View->Show View Options. To add the background picture inside the hidden directory, use cmd-shift-g in the file dialog. Adjust everything to suit, close window and open it. Then copy the .DS_Store file to dotDS_store. + +""" +import os +import re +import shutil +from subprocess import check_call +from math import ceil + +name = "SnapPy" +dist_dir = "../dist" +print('dmg name is %s' % name) + +def main(): + # Make sure the dmg isn't currently mounted, or this won't work. + mount_name = "/Volumes/" + name + while os.path.exists(mount_name): + print("Trying to eject " + mount_name) + subprocess.check_call("hdiutil detach " + mount_name) + # Remove old dmg if there is one + while os.path.exists(name + ".dmg"): + os.remove(name + ".dmg") + while os.path.exists(name + "-tmp.dmg"): + os.remove(name + "-tmp.dmg") + # Add symlink to /Applications if not there: + if not os.path.exists(dist_dir + "/Applications"): + os.symlink("/Applications/", dist_dir + "/Applications") + + # copy over the background and .DS_Store file + background = os.path.join(dist_dir, '.background') + shutil.rmtree(background, ignore_errors=True) + os.mkdir(background) + shutil.copy('background.png', background) + shutil.copy('dotDS_Store', os.path.join(dist_dir, '.DS_Store')) + + # figure out the needed size: + raw_size = os.popen("du -sh " + dist_dir).read() + size, units = re.search("([0-9.]+)([KMG])", raw_size).groups() + new_size = "%d" % ceil(1.2 * float(size)) + units + # Run the main script: + check_call(['hdiutil', 'makehybrid', '-hfs', + '-hfs-volume-name', 'SnapPy', + '-hfs-openfolder', dist_dir, + '-o', 'SnapPy-tmp.dmg', + dist_dir] ) + check_call(['hdiutil', 'convert', '-format', 'UDZO', + 'SnapPy-tmp.dmg', '-o', '%s.dmg'%name]) + os.remove("SnapPy-tmp.dmg") + # Delete symlink to /Applications or egg_info will be glacial on newer setuptools. + os.remove(dist_dir + "/Applications") + +if __name__ == "__main__": + main() diff --git a/macOS/dmg-maker/dotDS_Store b/macOS/dmg-maker/dotDS_Store new file mode 100644 index 0000000..c2018c9 Binary files /dev/null and b/macOS/dmg-maker/dotDS_Store differ