mirror of
https://gitlab.com/openlp/packaging.git
synced 2024-12-22 13:02:50 +00:00
Update the macOS build system to use dmgbuild instead of manually running hdiutil and AppleScript.
bzr-revno: 31
This commit is contained in:
commit
ea2cf8459f
@ -34,3 +34,4 @@ __pycache__
|
||||
*.dll
|
||||
*.DS_Store
|
||||
config.ini
|
||||
*.dmg
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
@ -1,32 +0,0 @@
|
||||
on run
|
||||
-- wait for virus scanner
|
||||
delay 2
|
||||
|
||||
tell application "Finder"
|
||||
tell disk "%(dmg_name)s"
|
||||
open
|
||||
set current view of container window to icon view
|
||||
set toolbar visible of container window to false
|
||||
set statusbar visible of container window to false
|
||||
set the bounds of container window to {400, 100, 1100, 500}
|
||||
set theViewOptions to the icon view options of container window
|
||||
set arrangement of theViewOptions to not arranged
|
||||
set icon size of theViewOptions to 128
|
||||
set background picture of theViewOptions to file ".background:installer-background.png"
|
||||
set position of item "%(app_name)s" of container window to {160, 200}
|
||||
set position of item "Applications" of container window to {550, 200}
|
||||
set position of item ".background" of container window to {100, 500}
|
||||
set position of item ".DS_Store" of container window to {200, 500}
|
||||
set position of item ".fseventsd" of container window to {300, 500}
|
||||
set position of item ".Trashes" of container window to {400, 500}
|
||||
set position of item ".VolumeIcon.icns" of container window to {500, 500}
|
||||
delay 5
|
||||
close
|
||||
open
|
||||
update without registering applications
|
||||
-- wait until the virus scan completes
|
||||
delay 2
|
||||
-- eject
|
||||
end tell
|
||||
end tell
|
||||
end run
|
@ -2,9 +2,7 @@
|
||||
sphinx = sphinx-build-3.4
|
||||
pyinstaller = %(projects)s/../pyinstaller/pyinstaller.py
|
||||
lrelease = /opt/local/libexec/qt5/bin/lrelease
|
||||
diskutil = diskutil
|
||||
hdiutil = hdiutil
|
||||
osascript = osascript
|
||||
dmgbuild = dmgbuild
|
||||
mudrawbin = mudraw
|
||||
mutoolbin = mutool
|
||||
|
||||
@ -12,10 +10,9 @@ mutoolbin = mutool
|
||||
branch = %(projects)s/trunk
|
||||
documentation = %(projects)s/documentation
|
||||
app_icon = %(here)s/OpenLP.icns
|
||||
dmg_icon = %(here)s/openlp-dmg.icns
|
||||
bundle_info = %(here)s/Info.plist
|
||||
hooks = %(here)s/../pyinstaller-hooks
|
||||
dmg_background = %(here)s/DmgImageInstallBackground.png
|
||||
dmg_settings = %(here)s/dmg-settings.py
|
||||
|
||||
[transifex]
|
||||
username =
|
||||
|
BIN
osx/dmg-background-new-with-icons.png
Normal file
BIN
osx/dmg-background-new-with-icons.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
BIN
osx/dmg-background-new.png
Normal file
BIN
osx/dmg-background-new.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
BIN
osx/dmg-background.png
Normal file
BIN
osx/dmg-background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
27
osx/dmg-settings-new.py
Normal file
27
osx/dmg-settings-new.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
|
||||
# This is the settings file for building the DMG. Run dmgbuild like so:
|
||||
# $ dmgbuild -s dmg-settings.py -D size=<size>,app=<path/to/OpenLP.app> "OpenLP" OpenLP-{version}.dmg
|
||||
|
||||
HERE = os.getcwd()
|
||||
|
||||
format = 'UDBZ'
|
||||
size = '600M'
|
||||
files = [defines.get('app', '/Applications/OpenLP.app')]
|
||||
symlinks = { 'Applications': '/Applications' }
|
||||
badge_icon = os.path.join(HERE, 'openlp-logo-new.icns')
|
||||
icon_locations = {
|
||||
'OpenLP.app': (160, 200),
|
||||
'Applications': (550, 200)
|
||||
}
|
||||
background = os.path.join(HERE, 'dmg-background-new.png')
|
||||
window_rect = ((100, 100), (700, 457))
|
||||
default_view = 'icon-view'
|
||||
show_icon_preview = False
|
||||
arrange_by = None
|
||||
scroll_position = (0, 0)
|
||||
grid_offset = (0, 0)
|
||||
grid_spacing = 100
|
||||
label_pos = 'bottom' # or 'right'
|
||||
text_size = 16
|
||||
icon_size = 128
|
27
osx/dmg-settings.py
Normal file
27
osx/dmg-settings.py
Normal file
@ -0,0 +1,27 @@
|
||||
import os
|
||||
|
||||
# This is the settings file for building the DMG. Run dmgbuild like so:
|
||||
# $ dmgbuild -s dmg-settings.py -D size=<size>,app=<path/to/OpenLP.app> "OpenLP" OpenLP-{version}.dmg
|
||||
|
||||
HERE = os.getcwd()
|
||||
|
||||
format = 'UDZO'
|
||||
size = defines.get('size', '600M')
|
||||
files = [defines.get('app', '/Applications/OpenLP.app')]
|
||||
symlinks = { 'Applications': '/Applications' }
|
||||
badge_icon = defines.get('icon', 'OpenLP.icns')
|
||||
icon_locations = {
|
||||
'OpenLP.app': (160, 200),
|
||||
'Applications': (550, 200)
|
||||
}
|
||||
background = os.path.join(HERE, 'dmg-background.png')
|
||||
window_rect = ((100, 100), (700, 460))
|
||||
default_view = 'icon-view'
|
||||
show_icon_preview = False
|
||||
arrange_by = None
|
||||
scroll_position = (0, 0)
|
||||
grid_offset = (0, 0)
|
||||
grid_spacing = 100
|
||||
label_pos = 'bottom' # or 'right'
|
||||
text_size = 16
|
||||
icon_size = 128
|
@ -27,9 +27,9 @@ Mac OS X Build Script
|
||||
This script is used to build the Mac OS X app bundle and pack it into dmg file.
|
||||
For this script to work out of the box, it depends on a number of things:
|
||||
|
||||
Python 3.3/3.4
|
||||
Python 3.4
|
||||
|
||||
PyQt4
|
||||
PyQt5
|
||||
You should already have this installed, OpenLP doesn't work without it. The
|
||||
version the script expects is the packaged one available from River Bank
|
||||
Computing.
|
||||
@ -111,6 +111,8 @@ def _which(command):
|
||||
"""
|
||||
Return absolute path to a command found on system PATH.
|
||||
"""
|
||||
if command.startswith('/'):
|
||||
return command
|
||||
for path in os.environ["PATH"].split(os.pathsep):
|
||||
if os.access(os.path.join(path, command), os.X_OK):
|
||||
return "%s/%s" % (path, command)
|
||||
@ -237,11 +239,12 @@ class MacosxBuilder(object):
|
||||
self.sphinx = _which(self.config.get('executables', 'sphinx'))
|
||||
self.pyinstaller = os.path.abspath(self.config.get('executables', 'pyinstaller'))
|
||||
self.lrelease = self.config.get('executables', 'lrelease')
|
||||
self.diskutil = _which(self.config.get('executables', 'diskutil'))
|
||||
self.hdiutil = self.config.get('executables', 'hdiutil')
|
||||
self.osascript = _which(self.config.get('executables', 'osascript'))
|
||||
self.dmgbuild = _which(self.config.get('executables', 'dmgbuild'))
|
||||
self.mudraw_bin = _which(self.config.get('executables', 'mudrawbin'))
|
||||
self.mutool_bin = _which(self.config.get('executables', 'mutoolbin'))
|
||||
if self.mutool_bin:
|
||||
self.mutool_lib = os.path.abspath(
|
||||
os.path.join(os.path.dirname(self.mutool_bin), '..', 'lib', 'libjbig2dec.0.dylib'))
|
||||
|
||||
def setup_paths(self):
|
||||
"""
|
||||
@ -264,9 +267,7 @@ class MacosxBuilder(object):
|
||||
self.openlp_script = os.path.abspath(os.path.join(self.work_path, 'openlp.py'))
|
||||
self.hooks_path = os.path.abspath(os.path.join(self.work_path, self.config.get('paths', 'hooks')))
|
||||
self.app_icon = os.path.abspath(self.config.get('paths', 'app_icon'))
|
||||
self.dmg_icon = os.path.abspath(self.config.get('paths', 'dmg_icon'))
|
||||
self.bundle_info = os.path.abspath(self.config.get('paths', 'bundle_info'))
|
||||
self.dmg_background_img = os.path.abspath(self.config.get('paths', 'dmg_background'))
|
||||
self.i18n_utils = os.path.join(self.work_path, 'scripts', 'translation_utils.py')
|
||||
self.source_path = os.path.join(self.work_path, 'openlp')
|
||||
self.manual_path = os.path.join(self.docs_path, 'manual')
|
||||
@ -275,12 +276,13 @@ class MacosxBuilder(object):
|
||||
self.build_path = os.path.join(self.work_path, 'build')
|
||||
self.dist_app_path = os.path.join(self.work_path, 'dist', 'OpenLP.app')
|
||||
self.dist_path = os.path.join(self.work_path, 'dist', 'OpenLP.app', 'Contents', 'MacOS')
|
||||
self.dmg_settings = os.path.abspath(self.config.get('paths', 'dmg_settings'))
|
||||
|
||||
# Path to Qt translation files.
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
qt_plug_dir = str(list(QCoreApplication.libraryPaths())[0])
|
||||
self.qt_translat_path = os.path.join(os.path.dirname(qt_plug_dir), 'translations')
|
||||
self.qt_translations_path = os.path.join(os.path.dirname(qt_plug_dir), 'translations')
|
||||
|
||||
def update_code(self):
|
||||
"""
|
||||
@ -453,11 +455,12 @@ class MacosxBuilder(object):
|
||||
copy(os.path.join(self.script_path, 'LICENSE.txt'), os.path.join(self.dist_path, 'LICENSE.txt'))
|
||||
self._print_verbose('... mudraw')
|
||||
if self.mudraw_bin and os.path.isfile(self.mudraw_bin):
|
||||
copy(os.path.join(self.mudraw_bin), os.path.join(self.dist_path, 'mudraw'))
|
||||
copy(self.mudraw_bin, os.path.join(self.dist_path, 'mudraw'))
|
||||
self.relink_mudraw()
|
||||
elif self.mutool_bin and os.path.isfile(self.mutool_bin):
|
||||
copy(os.path.join(self.mutool_bin), os.path.join(self.dist_path, 'mutool'))
|
||||
copy(self.mutool_bin, os.path.join(self.dist_path, 'mutool'))
|
||||
self.relink_mutool()
|
||||
copy(self.mutool_lib, os.path.join(self.dist_path, 'libjbig2dec.0.dylib'))
|
||||
else:
|
||||
self._print('... WARNING: mudraw and mutool not found')
|
||||
|
||||
@ -564,10 +567,10 @@ class MacosxBuilder(object):
|
||||
if code != 0:
|
||||
raise Exception('Error running lconvert on %s' % source_path)
|
||||
self._print('Copying qm files...')
|
||||
source = self.qt_translat_path
|
||||
source = self.qt_translations_path
|
||||
files = os.listdir(source)
|
||||
for filename in files:
|
||||
if filename.startswith('qt_') and filename.endswith('.qm') and len(filename) == 8:
|
||||
if filename.startswith('qt_') and filename.endswith('.qm'):
|
||||
self._print_verbose('... %s', filename)
|
||||
copy(os.path.join(source, filename), os.path.join(self.dist_path, 'i18n', filename))
|
||||
|
||||
@ -625,86 +628,26 @@ class MacosxBuilder(object):
|
||||
# Release version does not contain revision in .dmg name.
|
||||
if self.args.devel:
|
||||
dmg_name = 'OpenLP-' + str(self.version_string) + '.dmg'
|
||||
dmg_title = 'OpenLP {version}'.format(version=self.version_string)
|
||||
else:
|
||||
dmg_name = 'OpenLP-' + str(self.version_tag) + '.dmg'
|
||||
dmg_title = 'OpenLP {version}'.format(version=self.version_tag)
|
||||
|
||||
dmg_file = os.path.join(self.work_path, 'build', dmg_name)
|
||||
self.dmg_file = os.path.join(self.work_path, 'dist', dmg_name)
|
||||
# Remove dmg if it exists.
|
||||
if os.path.exists(dmg_file):
|
||||
os.remove(dmg_file)
|
||||
if os.path.exists(self.dmg_file):
|
||||
os.remove(self.dmg_file)
|
||||
# Create empty dmg file.
|
||||
size = self._get_directory_size(self.dist_app_path) # in bytes.
|
||||
size = size / (1000 * 1000) # Convert to megabytes.
|
||||
size += 10 # Additional space in .dmg for other files.
|
||||
self._print('... dmg disk size: %s' % size)
|
||||
self._run_command([self.hdiutil, 'create', dmg_file, '-ov', '-megabytes', str(size), '-fs', 'HFS+', '-volname',
|
||||
'OpenLP'], 'Could not create dmg file.')
|
||||
|
||||
# Mount empty dmg file.
|
||||
old_mounts = self._get_mountpoints()
|
||||
self._print('... mounting the dmg file: %s' % dmg_file)
|
||||
self._run_command([self.hdiutil, 'attach', dmg_file], 'Could not mount dmg file, cannot continue.')
|
||||
new_mounts = self._get_mountpoints()
|
||||
# Get the mount point from difference between paths
|
||||
# after mounting and before mounting the dmg file.
|
||||
dmg_volume_path = list(set(new_mounts) - set(old_mounts))[0]
|
||||
|
||||
# Copy OpenLP.app and other files to .dmg
|
||||
# TODO more reliable way to determine dmg_volume_path
|
||||
self._print('... Copying the app to the dmg: ' + dmg_volume_path)
|
||||
self._run_command(['cp', '-R', self.dist_app_path, dmg_volume_path],
|
||||
'Could not copy app bundle, dmg creation failed.')
|
||||
|
||||
# Set icon for dmg file.
|
||||
# http://endrift.com/blog/2010/06/14/dmg-files-volume-icons-cli/
|
||||
self._print('... Setting the dmg icon.')
|
||||
dmg_icon = os.path.join(dmg_volume_path, '.VolumeIcon.icns')
|
||||
self._run_command(['cp', self.dmg_icon, dmg_icon], 'Could not copy the dmg icon file, dmg creation failed.')
|
||||
# Set proper dmg icon attributes.
|
||||
self._run_command(['SetFile', '-c', 'icnC', dmg_icon], 'Could not set dmg icon attributes.')
|
||||
# Ensures dmg icon will be used while mounted.
|
||||
self._run_command(['SetFile', '-a', 'C', dmg_volume_path], 'Could not set dmg icon attributes.')
|
||||
|
||||
# Create symlink in dmg pointing to the /Applications directory on OS X.
|
||||
self._print('... Creating symlink to /Applications.')
|
||||
os.symlink('/Applications', os.path.join(dmg_volume_path, 'Applications'))
|
||||
|
||||
# Set dmg background. Requires running Mac OS X gui.
|
||||
# TODO: better formatting and code refactoring
|
||||
if not self.args.devel:
|
||||
self._print('... Setting the background image.')
|
||||
|
||||
os.mkdir(os.path.join(dmg_volume_path, '.background'))
|
||||
self._run_command(['cp', self.dmg_background_img, os.path.join(dmg_volume_path,
|
||||
'.background/installer-background.png')],
|
||||
'Could not copy the background image, dmg creation failed.')
|
||||
|
||||
self.adjust_dmg_view(os.path.basename(dmg_volume_path))
|
||||
|
||||
# Unmount dmg file.
|
||||
self._print('... unmounting the dmg.')
|
||||
# Sometimes it could happen that OSX Finder is blocking umount.
|
||||
# We need to find this process and kill it.
|
||||
try:
|
||||
output = subprocess.check_output(['fuser', dmg_volume_path]).strip()
|
||||
if output:
|
||||
blocking_proc_pid = int(output.split()[0])
|
||||
os.kill(int(blocking_proc_pid), signal.SIGKILL)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
self._print('... failed to kill process using %s' % dmg_volume_path)
|
||||
# Unmount dmg file.
|
||||
self._run_command([self.hdiutil, 'detach', dmg_volume_path],
|
||||
'Could not unmount the dmg file, dmg creation failed.')
|
||||
|
||||
# Compress dmg file.
|
||||
self._print('... compressing the dmg file')
|
||||
compressed_dmg = os.path.join(self.work_path, 'dist', os.path.basename(dmg_file)) # Put dmg to 'dist' dir.
|
||||
# Remove dmg if it exists.
|
||||
if os.path.exists(compressed_dmg):
|
||||
os.remove(compressed_dmg)
|
||||
self._run_command([self.hdiutil, 'convert', dmg_file, '-format', 'UDZO', '-imagekey', 'zlib-level=9', '-o',
|
||||
compressed_dmg], 'Could not compress the dmg file, dmg creation failed.')
|
||||
self._print('... %s' % self.script_path)
|
||||
os.chdir(self.script_path)
|
||||
self._run_command([self.dmgbuild, '-s', self.dmg_settings, '-D', 'size={size}M'.format(size=size),
|
||||
'-D', 'icon={icon_path}'.format(icon_path=self.app_icon),
|
||||
'-D', 'app={dist_app_path}'.format(dist_app_path=self.dist_app_path), dmg_title, self.dmg_file],
|
||||
'Unable to run dmgbuild')
|
||||
|
||||
# Jenkins integration.
|
||||
# Continuous integration server needs to know the filename of dmg.
|
||||
@ -713,40 +656,25 @@ class MacosxBuilder(object):
|
||||
fpath = os.path.join(self.branch_path, 'openlp.properties')
|
||||
self._print('... writing property file for jenkins: %s' % fpath)
|
||||
f = open(fpath, 'w')
|
||||
f.write('OPENLP_DMGNAME=' + os.path.basename(dmg_file) + '\n')
|
||||
f.write('OPENLP_DMGNAME=' + os.path.basename(self.dmg_file) + '\n')
|
||||
f.close()
|
||||
|
||||
# Dmg done.
|
||||
self._print('Finished creating dmg file, resulting file: %s' % compressed_dmg)
|
||||
|
||||
self.dmg_file = compressed_dmg
|
||||
|
||||
def adjust_dmg_view(self, dmg_volume_name):
|
||||
try:
|
||||
master_script = os.path.join(self.script_path, 'applescript-adjust-dmg-view.master')
|
||||
apple_script = os.path.join(self.script_path, 'adjust-dmg-view.applescript')
|
||||
with open(master_script) as r, open(apple_script, 'w') as w:
|
||||
apple_script = r.read() % {'dmg_name': dmg_volume_name, 'app_name': 'OpenLP.app'}
|
||||
w.write(apple_script)
|
||||
p = Popen([self.osascript, apple_script])
|
||||
result = p.returncode
|
||||
if (result != 0):
|
||||
self._print('Adjusting dmg view failed (non-zero exit code).')
|
||||
except (IOError, OSError):
|
||||
self._print('Adjusting dmg view failed.')
|
||||
self._print('Finished creating dmg file, resulting file: %s' % self.dmg_file)
|
||||
|
||||
def main(self):
|
||||
"""
|
||||
The main function to run the Mac OS X builder.
|
||||
"""
|
||||
self._print_verbose('OpenLP main script: ......%s', self.openlp_script)
|
||||
self._print_verbose('Script path: .............%s', os.path.split(os.path.abspath(__file__))[0])
|
||||
self._print_verbose('Script path: .............%s', self.script_path)
|
||||
self._print_verbose('Branch path: .............%s', self.branch_path)
|
||||
self._print_verbose('Source path: .............%s', self.source_path)
|
||||
self._print_verbose('"dist.app" path: .........%s', self.dist_app_path)
|
||||
self._print_verbose('"dist" path: .............%s', self.dist_path)
|
||||
self._print_verbose('"hooks" path: ............%s', self.hooks_path)
|
||||
self._print_verbose('PyInstaller: .............%s', self.pyinstaller)
|
||||
self._print_verbose('dmgbuild: ................%s', self.dmgbuild)
|
||||
self._print_verbose('Documentation branch path:%s', self.docs_path)
|
||||
if self.mudraw_bin:
|
||||
self._print_verbose('mudraw binary ............%s', self.mudraw_bin)
|
||||
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 101 KiB |
Binary file not shown.
Before Width: | Height: | Size: 87 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user