diff --git a/.bzrignore b/.bzrignore index c53fdd8..abc3f4f 100644 --- a/.bzrignore +++ b/.bzrignore @@ -34,3 +34,4 @@ __pycache__ *.dll *.DS_Store config.ini +*.dmg diff --git a/osx/DmgImageInstallBackground.png b/osx/DmgImageInstallBackground.png deleted file mode 100644 index 8a41d3b..0000000 Binary files a/osx/DmgImageInstallBackground.png and /dev/null differ diff --git a/osx/applescript-adjust-dmg-view.master b/osx/applescript-adjust-dmg-view.master deleted file mode 100755 index 330dd65..0000000 --- a/osx/applescript-adjust-dmg-view.master +++ /dev/null @@ -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 diff --git a/osx/config.ini.default b/osx/config.ini.default index 8dccb2c..c045080 100644 --- a/osx/config.ini.default +++ b/osx/config.ini.default @@ -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 = diff --git a/osx/dmg-background-new-with-icons.png b/osx/dmg-background-new-with-icons.png new file mode 100644 index 0000000..3071a00 Binary files /dev/null and b/osx/dmg-background-new-with-icons.png differ diff --git a/osx/dmg-background-new.png b/osx/dmg-background-new.png new file mode 100644 index 0000000..de774e1 Binary files /dev/null and b/osx/dmg-background-new.png differ diff --git a/osx/dmg-background.png b/osx/dmg-background.png new file mode 100644 index 0000000..ab2e63e Binary files /dev/null and b/osx/dmg-background.png differ diff --git a/osx/dmg-settings-new.py b/osx/dmg-settings-new.py new file mode 100644 index 0000000..983cea5 --- /dev/null +++ b/osx/dmg-settings-new.py @@ -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=,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 diff --git a/osx/dmg-settings.py b/osx/dmg-settings.py new file mode 100644 index 0000000..abe7acb --- /dev/null +++ b/osx/dmg-settings.py @@ -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=,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 diff --git a/osx/macosx-builder.py b/osx/macosx-builder.py index 6b0724b..57ef00d 100644 --- a/osx/macosx-builder.py +++ b/osx/macosx-builder.py @@ -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) diff --git a/osx/openlp-dmg.icns b/osx/openlp-dmg.icns deleted file mode 100644 index 4aad87b..0000000 Binary files a/osx/openlp-dmg.icns and /dev/null differ diff --git a/osx/openlp-dmg.png b/osx/openlp-dmg.png deleted file mode 100644 index 1ec98c5..0000000 Binary files a/osx/openlp-dmg.png and /dev/null differ diff --git a/osx/openlp-logo-new.png.icns b/osx/openlp-logo-new.icns similarity index 100% rename from osx/openlp-logo-new.png.icns rename to osx/openlp-logo-new.icns diff --git a/osx/openlp-new-dmg.png b/osx/openlp-new-dmg.png deleted file mode 100644 index c60ccf3..0000000 Binary files a/osx/openlp-new-dmg.png and /dev/null differ diff --git a/osx/openlp-new-dmg.png.icns b/osx/openlp-new-dmg.png.icns deleted file mode 100644 index 83e45f6..0000000 Binary files a/osx/openlp-new-dmg.png.icns and /dev/null differ