← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~matthiashub/openlp/osx-build-scripts into lp:openlp

 

Matthias Hub has proposed merging lp:~matthiashub/openlp/osx-build-scripts into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~matthiashub/openlp/osx-build-scripts/+merge/51433

Added OS X build scripts
Please note: there is also one change in openlp.pyw to support the qt plugins folder on OS X
-- 
https://code.launchpad.net/~matthiashub/openlp/osx-build-scripts/+merge/51433
Your team OpenLP Core is requested to review the proposed merge of lp:~matthiashub/openlp/osx-build-scripts into lp:openlp.
=== modified file 'openlp.pyw'
--- openlp.pyw	2011-02-24 05:47:38 +0000
+++ openlp.pyw	2011-02-26 20:37:07 +0000
@@ -273,6 +273,8 @@
     qInitResources()
     # Now create and actually run the application.
     app = OpenLP(qt_args)
+    if sys.platform == 'darwin':
+         QtGui.QApplication.addLibraryPath(QtGui.QApplication.applicationDirPath() + "/qt4_plugins")
     #i18n Set Language
     language = LanguageManager.get_language()
     appTranslator = LanguageManager.get_translator(language)

=== added directory 'resources/osx'
=== added file 'resources/osx/Info.plist.master'
--- resources/osx/Info.plist.master	1970-01-01 00:00:00 +0000
+++ resources/osx/Info.plist.master	2011-02-26 20:37:07 +0000
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd";>
+<plist version="1.0">
+<dict>
+<key>CFBundleIdentifier</key>
+<string>org.openlp</string>
+<key>CFBundleShortVersionString</key>
+<string>%(openlp_version)s</string>
+<key>CFBundleVersion</key>
+<string>%(openlp_version)s</string>
+<key>CFBundleInfoDictionaryVersion</key>
+<string>6.0</string>
+<key>CFBundleDisplayName</key>
+<string>%(openlp_appname)s</string>
+<key>CFBundleIconFile</key>
+<string>openlp-logo-with-text.icns</string>
+<key>CFBundleExecutable</key>
+<string>MacOS/openlp</string>
+<key>CFBundleName</key>
+<string>%(openlp_appname)s</string>
+<key>CFBundleGetInfoString</string>
+<string>%(openlp_appname)s %(openlp_version)s</string>
+<key>LSHasLocalizedDisplayName</string>
+<false/>
+<key>NSAppleScriptEnabled</key>
+<false/>
+<key>CFBundlePackageType</key>
+<string>APPL</string>
+<key>LSBackgroundOnly</key>
+<false/>
+</dict>
+</plist>

=== added file 'resources/osx/Makefile'
--- resources/osx/Makefile	1970-01-01 00:00:00 +0000
+++ resources/osx/Makefile	2011-02-26 20:37:07 +0000
@@ -0,0 +1,28 @@
+all:
+	python build.py -c openlp.cfg
+
+view:
+	python build.py -c openlp.cfg --package-view --compress-view
+
+package:
+
+	python build.py -c openlp.cfg --package --package-view
+
+bundle:
+
+	python build.py -c openlp.cfg --compress --compress-view
+
+clean:
+	# remove old configuration files
+	rm -f openlp.spec
+	rm -f Info.plist
+	rm -f .version
+
+	# remove old build artifacts
+	rm -rf build
+	rm -rf dist
+	rm -rf Macopenlp.app
+	rm -rf OpenLP.app
+	rm -f warnopenlp.txt
+	rm -f *dmg
+

=== added file 'resources/osx/applescript-adjustview-10-5.master'
--- resources/osx/applescript-adjustview-10-5.master	1970-01-01 00:00:00 +0000
+++ resources/osx/applescript-adjustview-10-5.master	2011-02-26 20:37:07 +0000
@@ -0,0 +1,74 @@
+on saveImageWithItselfAsIcon(icon_image_file)
+	-- save icon_image_file with itself as icon
+	set icon_image_file_string to icon_image_file as string
+	tell application "Image Events"
+		launch
+		set icon_image to open file icon_image_file_string
+		save icon_image with icon
+		close icon_image
+	end tell
+end saveImageWithItselfAsIcon
+
+on copyIconOfTo(aFileOrFolderWithIcon, aFileOrFolder)
+	tell application "Finder" to set f to aFileOrFolderWithIcon as alias
+	-- grab the file's icon
+	my CopyOrPaste(f, "c")
+	-- now the icon is in the clipboard
+	tell application "Finder" to set c to aFileOrFolder as alias
+	my CopyOrPaste(result, "v")
+end copyIconOfTo
+
+on CopyOrPaste(i, cv)
+	tell application "Finder"
+		activate
+    open information window of i
+	end tell
+	tell application "System Events" to tell process "Finder" to tell window 1
+		keystroke tab -- select icon button
+		keystroke (cv & "w") using command down (* (copy or paste) + close window *)
+	end tell -- window 1 then process Finder then System Events
+end CopyOrPaste
+
+on run
+	set icon_image_file to POSIX file "%s" as alias
+	set dmg_file to POSIX file "/Volumes/%s" as alias
+
+	my saveImageWithItselfAsIcon(icon_image_file)
+	-- wait for virus scanner
+	delay 2
+	my copyIconOfTo(icon_image_file, dmg_file)
+
+	tell application "Finder"
+		tell disk "%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 ".installer-background.png"
+                        if not exists file "Applications" then
+			    make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
+                        end if
+			delay 5
+			set position of item "%s" of container window to {160, 200}
+			set position of item ".Trashes" of container window to {100, 500}
+			set position of item ".installer-background.png" of container window to {200, 500}
+			set position of item ".DS_Store" of container window to {400, 500}
+			set position of item "Applications" of container window to {550, 200}
+			set position of item ".VolumeIcon.icns" of container window to {500, 500}
+			set position of item ".fseventsd" of container window to {300, 500}
+			if exists POSIX file ".SymAVx86QSFile" then
+				set position of item ".SymAVx86QSFile" of container window to {600, 500}
+			end if
+			open
+			close
+			update without registering applications
+			-- wait until the virus scan completes
+			delay 5
+			-- eject
+		end tell
+	end tell
+end run

=== added file 'resources/osx/applescript-adjustview-10-6.master'
--- resources/osx/applescript-adjustview-10-6.master	1970-01-01 00:00:00 +0000
+++ resources/osx/applescript-adjustview-10-6.master	2011-02-26 20:37:07 +0000
@@ -0,0 +1,73 @@
+on saveImageWithItselfAsIcon(icon_image_file)
+	-- save icon_image_file with itself as icon
+	set icon_image_file_string to icon_image_file as string
+	tell application "Image Events"
+		launch
+		set icon_image to open file icon_image_file_string
+		save icon_image with icon
+		close icon_image
+	end tell
+end saveImageWithItselfAsIcon
+
+on copyIconOfTo(aFileOrFolderWithIcon, aFileOrFolder)
+	tell application "Finder" to set f to aFileOrFolderWithIcon as alias
+	-- grab the file's icon
+	my CopyOrPaste(f, "c")
+	-- now the icon is in the clipboard
+	tell application "Finder" to set c to aFileOrFolder as alias
+	my CopyOrPaste(result, "v")
+end copyIconOfTo
+
+on CopyOrPaste(i, cv)
+	tell application "Finder"
+		activate
+    set infoWindow to open information window of i
+    set infoWindowName to name of infoWindow
+	end tell
+	tell application "System Events" to tell process "Finder" to tell window infoWindowName
+		keystroke tab -- select icon button
+		keystroke (cv & "w") using command down (* (copy or paste) + close window *)
+	end tell -- window 1 then process Finder then System Events
+end CopyOrPaste
+
+on run
+	set icon_image_file to POSIX file "%s" as alias
+	set dmg_file to POSIX file "/Volumes/%s" as alias
+
+	my saveImageWithItselfAsIcon(icon_image_file)
+	-- wait for virus scanner
+	delay 2
+	my copyIconOfTo(icon_image_file, dmg_file)
+
+	tell application "Finder"
+		tell disk "%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 ".installer-background.png"
+			make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
+			delay 5
+			set position of item "%s" of container window to {160, 200}
+			set position of item ".Trashes" of container window to {100, 500}
+			set position of item ".installer-background.png" of container window to {200, 500}
+			set position of item ".DS_Store" of container window to {400, 500}
+			set position of item "Applications" of container window to {550, 200}
+			set position of item ".VolumeIcon.icns" of container window to {500, 500}
+			set position of item ".fseventsd" of container window to {300, 500}
+			if exists POSIX file ".SymAVx86QSFile" then
+				set position of item ".SymAVx86QSFile" of container window to {600, 500}
+			end if
+			open
+			close
+			update without registering applications
+			-- wait until the virus scan completes
+			delay 5
+			-- eject
+		end tell
+	end tell
+end run

=== added file 'resources/osx/applescript-seticon-10-5.master'
--- resources/osx/applescript-seticon-10-5.master	1970-01-01 00:00:00 +0000
+++ resources/osx/applescript-seticon-10-5.master	2011-02-26 20:37:07 +0000
@@ -0,0 +1,40 @@
+on saveImageWithItselfAsIcon(icon_image_file)
+        -- save icon_image_file with itself as icon
+        set icon_image_file_string to icon_image_file as string
+        tell application "Image Events"
+                launch
+                set icon_image to open file icon_image_file_string
+                save icon_image with icon
+                close icon_image
+        end tell
+end saveImageWithItselfAsIcon
+
+on copyIconOfTo(aFileOrFolderWithIcon, aFileOrFolder)
+        tell application "Finder" to set f to aFileOrFolderWithIcon as alias
+        -- grab the file's icon
+        my CopyOrPaste(f, "c")
+        -- now the icon is in the clipboard
+        tell application "Finder" to set c to aFileOrFolder as alias
+        my CopyOrPaste(result, "v")
+end copyIconOfTo
+
+on CopyOrPaste(i, cv)
+        tell application "Finder"
+                activate
+                open information window of i
+        end tell
+        tell application "System Events" to tell process "Finder" to tell window 1
+                keystroke tab -- select icon button
+                keystroke (cv & "w") using command down (* (copy or paste) + close window *)
+        end tell -- window 1 then process Finder then System Events
+end CopyOrPaste
+
+on run
+        set icon_image_file to POSIX file "%s" as alias
+        set dmg_file to POSIX file "%s" as alias
+
+        my saveImageWithItselfAsIcon(icon_image_file)
+        -- wait for virus scanner
+        delay 2
+        my copyIconOfTo(icon_image_file, dmg_file)
+end run

=== added file 'resources/osx/applescript-seticon-10-6.master'
--- resources/osx/applescript-seticon-10-6.master	1970-01-01 00:00:00 +0000
+++ resources/osx/applescript-seticon-10-6.master	2011-02-26 20:37:07 +0000
@@ -0,0 +1,41 @@
+on saveImageWithItselfAsIcon(icon_image_file)
+        -- save icon_image_file with itself as icon
+        set icon_image_file_string to icon_image_file as string
+        tell application "Image Events"
+                launch
+                set icon_image to open file icon_image_file_string
+                save icon_image with icon
+                close icon_image
+        end tell
+end saveImageWithItselfAsIcon
+
+on copyIconOfTo(aFileOrFolderWithIcon, aFileOrFolder)
+        tell application "Finder" to set f to aFileOrFolderWithIcon as alias
+        -- grab the file's icon
+        my CopyOrPaste(f, "c")
+        -- now the icon is in the clipboard
+        tell application "Finder" to set c to aFileOrFolder as alias
+        my CopyOrPaste(result, "v")
+end copyIconOfTo
+
+on CopyOrPaste(i, cv)
+        tell application "Finder"
+                activate
+                set infoWindow to open information window of i
+                set infoWindowName to name of infoWindow
+        end tell
+        tell application "System Events" to tell process "Finder" to tell window infoWindowName
+                keystroke tab -- select icon button
+                keystroke (cv & "w") using command down (* (copy or paste) + close window *)
+        end tell -- window 1 then process Finder then System Events
+end CopyOrPaste
+
+on run
+        set icon_image_file to POSIX file "%s" as alias
+        set dmg_file to POSIX file "%s" as alias
+
+        my saveImageWithItselfAsIcon(icon_image_file)
+        -- wait for virus scanner
+        delay 2
+        my copyIconOfTo(icon_image_file, dmg_file)
+end run

=== added file 'resources/osx/build.py'
--- resources/osx/build.py	1970-01-01 00:00:00 +0000
+++ resources/osx/build.py	2011-02-26 20:37:07 +0000
@@ -0,0 +1,261 @@
+#!/usr/bin/python
+# -*- encoding: utf-8 -*-
+import time
+import os
+import ConfigParser
+import logging
+import optparse
+import sys
+import platform
+import re
+import subprocess as subp
+
+if __name__ == '__main__':
+
+    # set default actions
+    doBuild = True
+    doCompressView = True
+    doPackageView = True
+    doCreateDmg = True
+    doCompressDmg = True
+    doDeployQt = True
+   
+    # set the script name
+    script_name = "build"
+ 
+    parser = optparse.OptionParser()
+    parser.add_option('-c', '--config', dest = 'config', help = 'config file', metavar = 'CONFIG')
+    parser.add_option('-v', '--package-view', dest = 'package_view', help = 'triggers view adjustment scripts for package', metavar = 'PACKAGEVIEWONLY', action='store_true', default=False)
+    parser.add_option('-y', '--compress-view', dest = 'compress_view', help = 'triggers view adjustment scripts for dmg', metavar = 'COMPRESSVIEWONLY', action='store_true', default=False)
+    parser.add_option('-p', '--package', dest = 'package', help = 'package application folder to dmg', metavar = 'PACKAGE', action='store_true', default=False)
+    parser.add_option('-z', '--compress', dest = 'compress', help = 'compresses the existing dmg', metavar = 'COMPRESS', action='store_true', default=False)
+    parser.add_option('-b', '--basedir', dest = 'basedir', help = 'volume basedir like /Volumes/OpenLP', metavar = 'BASEDIR', default='/Volumes/OpenLP')
+    
+    (options, args) = parser.parse_args()
+    
+    # if an option is set, false all
+    if (options.package_view is True or options.compress_view is True or options.package is True or options.compress is True):
+        doBuild = False
+        doDeployQt = False
+        doPackageView = options.package_view
+        doCompressView = options.compress_view
+        doCreateDmg = options.package
+        doCompressDmg = options.compress
+
+    if not options.config:
+        parser.error('option --config|-c is required')
+
+    logHandler = logging.StreamHandler()
+    logHandler.setFormatter(logging.Formatter('%(asctime)s %(levelname)-8s %(message)s',
+                                              '%a, %d %b %Y %H:%M:%S'))
+    logging.getLogger().addHandler(logHandler)
+    logging.getLogger().setLevel(logging.DEBUG)
+ 
+    config = ConfigParser.RawConfigParser()
+    config.readfp(open(options.config, 'r'))
+ 
+    if not config.has_section('openlp'):
+        logging.error('[%s] config file "%s" lacks an [openlp] section',
+                      script_name, options.config)
+        sys.exit(1)
+
+    if not sys.platform == "darwin":
+        logging.error('[%s] this script only works on Macintosh OS X systems, not on %s',
+                      script_name, sys.platform)
+        sys.exit(1)
+
+    version = platform.mac_ver()[0]
+    # we only need the differenciation between leopard and snow leopard
+    if version.startswith("10.6"):
+        SNOWLEOPARD = True
+        logging.info('[%s] using snow leopard scripts (version = %s)', script_name, version)
+        adjustview_scriptname = "applescript-adjustview-10-6.master"
+        seticon_scriptname = "applescript-seticon-10-6.master"
+    else:
+        SNOWLEOPARD = False
+        logging.info('[%s] using leopard scripts (version = %s)', script_name, version)
+        adjustview_scriptname = "applescript-adjustview-10-5.master"
+        seticon_scriptname = "applescript-seticon-10-5.master"
+
+    if not os.path.isfile(adjustview_scriptname) or not os.path.isfile(seticon_scriptname):
+        logging.error('[%s] could not find apple scripts for given mac version %s', script_name, version)
+        sys.exit(1)
+
+    settings = dict()
+    for k in config.options('openlp'):
+        settings[k] = config.get('openlp', k)
+
+    # prepare the configuration files
+    os.system('python expander.py --config %(config_file)s --template openlp.spec.master --expandto %(target_directory)s/openlp.spec' \
+              % { 'config_file' : options.config, 'target_directory' : os.getcwd() })
+    os.system('python expander.py --config %(config_file)s --template Info.plist.master --expandto %(target_directory)s/Info.plist' \
+              % { 'config_file' : options.config, 'target_directory' : os.getcwd() })
+    os.system('python expander.py --config %(config_file)s --template version.master --expandto %(target_directory)s/.version' \
+              % { 'config_file' : options.config, 'target_directory' : os.getcwd() })
+
+    # prepare variables
+    app_name = settings['openlp_appname'].lower()
+    app_dir = os.getcwd() + '/' + settings['openlp_appname'] + '.app'
+
+    # if the view option is set, skip the building steps
+    if (doBuild is True):
+        logging.info('[%s] now building the app with pyinstaller at "%s"...', script_name, settings['pyinstaller_basedir'])
+        result = os.system('python %s/pyinstaller.py openlp.spec' \
+                  % settings['pyinstaller_basedir'])
+        if (result != 0):
+            logging.error('[%s] The pyinstaller build reported an error, cannot continue!', script_name)
+            sys.exit(1)
+        
+        logging.info('[%s] copying the qt_menu files...', script_name)
+        # see http://www.pyinstaller.org/ticket/157
+        result = os.system('cp -R %(qt_menu_directory)s %(application_directory)s/Contents/Resources' \
+                  % { 'qt_menu_directory' : settings['qt_menu_basedir'], 
+                      'application_directory' : app_dir })
+        if (result != 0):
+            logging.error('[%s] could not copy the qt_menu files, cannot continue!', script_name)
+            sys.exit(1)
+
+        dist_folder = os.getcwd() + '/dist/' + app_name
+        # logging.info('[%s] copying the additional app files (from %s)...', script_name, dist_folder)
+        # result = os.system('cp -R %(dist_directory)s/* %(application_directory)s/Contents/MacOS' \
+        #           % { 'dist_directory' : dist_folder,
+        #               'application_directory' : app_dir })
+        # if (result != 0):
+        #     logging.error('[%s] could not copy additional files, cannot continue!', script_name)
+        #     sys.exit(1)
+
+        logging.info('[%s] copying the new plugins...', script_name)
+        result = os.system('cp -R %(openlp_directory)s/openlp/plugins %(application_directory)s/Contents/MacOS' \
+                  % { 'openlp_directory' : settings['openlp_basedir'], 
+                      'application_directory' : app_dir })
+        if (result != 0):
+            logging.error('[%s] could not copy plugins, dmg creation failed!', script_name)
+            sys.exit(1)
+
+        logging.info('[%s] copying the icons to the resource directory...', script_name)
+        result = os.system('cp %(icon_file)s %(application_directory)s/Contents/Resources' \
+                  % { 'icon_file' : settings['openlp_icon_file'], 
+                      'application_directory' : app_dir })
+        if (result != 0):
+            logging.error('[%s] could not copy the icon, dmg creation failed!', script_name)
+            sys.exit(1)
+
+        logging.info('[%s] copying the version file...', script_name)
+        result = os.system('CpMac %s/.version %s/Contents/MacOS' % (os.getcwd(), app_dir)) 
+        if (result != 0):
+            logging.error('[%s] could not copy the version file, dmg creation failed!', script_name)
+            sys.exit(1)
+        
+        logging.info('[%s] copying the new Info.plist...', script_name)
+        result = os.system('cp %(target_directory)s/Info.plist %(application_directory)s/Contents' \
+                  % { 'target_directory' : os.getcwd(), 
+                      'application_directory' : app_dir })
+        if (result != 0):
+            logging.error('[%s] could not copy the info file, dmg creation failed!', script_name)
+            sys.exit(1)
+
+    if (doDeployQt is True):
+        logging.info('[%s] running mac deploy qt on %s.app...', script_name, settings['openlp_appname']);
+
+        result = os.system('macdeployqt %s.app' % settings['openlp_appname']);
+        if (result != 0):
+            logging.error('[%s] could not create dmg file!', script_name)
+            sys.exit(1)
+        
+    if (doCreateDmg is True):
+        logging.info('[%s] creating the dmg...', script_name)
+        dmg_file = os.getcwd() + '/' + settings['openlp_dmgname'] + '.dmg' 
+        result = os.system('hdiutil create %(dmg_file)s~ -ov -megabytes %(vol_size)s -fs HFS+ -volname %(vol_name)s' \
+                  % { 'dmg_file' : dmg_file,
+                      'vol_size' : '250',
+                      'vol_name' : settings['openlp_appname'] })
+        if (result != 0):
+            logging.error('[%s] could not create dmg file!', script_name)
+            sys.exit(1)
+
+        logging.info('[%s] mounting the dmg file...', script_name)
+        output = subp.Popen(["hdiutil", "attach", dmg_file + "~.dmg"], stdout=subp.PIPE).communicate()[0]
+        logging.debug(output)
+
+        p = re.compile('Apple_HFS\s+(.+?)\s*$')
+        result = p.search(output, re.M)
+        volume_basedir = ''
+        if result:
+            volume_basedir = result.group(1)
+        else:
+            logging.error('could not mount dmg file, cannot continue!')
+            sys.exit(1)
+
+        logging.info('[%s] copying the app (from %s) to the dmg (at %s)...', script_name, app_dir, volume_basedir)
+        result = os.system('CpMac -r %s %s' \
+                 % ( app_dir, volume_basedir ))
+        if (result != 0):
+            logging.error('[%s] could not copy application, dmg creation failed!', script_name)
+            sys.exit(1)
+
+        logging.info('[%s] copying the background image...', script_name)
+        # os.mkdir(volume_basedir + '/.background')
+        result = os.system('CpMac %s %s' % (settings['installer_backgroundimage_file'], volume_basedir + '/.installer-background.png'))
+        if (result != 0):
+            logging.error('[%s] could not copy the background image, dmg creation failed!', script_name)
+            sys.exit(1)
+
+    else:
+        # setting base dir
+        volume_basedir = options.basedir
+        dmg_file = os.getcwd() + '/' + settings['openlp_dmgname'] + '.dmg'
+
+    if (doPackageView is True):
+        logging.info('[%s] making adjustments to the view...', script_name)
+        try:
+            f = open(adjustview_scriptname)
+            p = subp.Popen(["osascript"], stdin=subp.PIPE)
+            p.communicate(f.read() % ((os.getcwd() + '/' + settings['openlp_dmg_icon_file']), settings['openlp_appname'], settings['openlp_appname'], settings['openlp_appname']))
+            f.close()
+            result = p.returncode
+            if (result != 0):
+                logging.error('[%s] could not adjust the view, dmg creation failed!', script_name)
+                sys.exit(1)
+        except IOError, e:
+            logging.error('[%s] could not adjust the view (%s), dmg creation failed!', script_name, e)
+            sys.exit(1)
+        except OSError, e:
+            logging.error('[%s] could not adjust the view (%s), dmg creation failed!', script_name, e)
+            sys.exit(1)
+
+    if (doCreateDmg is True):
+        logging.info('[%s] unmounting the dmg...', script_name)
+        result = os.system('hdiutil detach %s' % volume_basedir)
+        if (result != 0):
+            logging.error('[%s] could not unmount the dmg file, dmg creation failed!', script_name)
+            sys.exit(1)
+
+    if (doCompressDmg is True):
+        logging.info('[%s] compress the dmg file...', script_name)
+        result = os.system('hdiutil convert %s~.dmg -format UDZO -imagekey zlib-level=9 -o %s' \
+                  % (dmg_file, dmg_file))
+        if (result != 0):
+            logging.error('[%s] could not compress the dmg file, dmg creation failed!', script_name)
+            sys.exit(1)
+
+    if (doCompressView is True):
+        logging.info('[%s] setting icon of the dmg file...', script_name)
+        try:
+            f = open(seticon_scriptname)
+            p = subp.Popen(["osascript"], stdin=subp.PIPE)
+            p.communicate(f.read() % ((os.getcwd() + '/' + settings['openlp_dmg_icon_file']), dmg_file))
+            f.close()
+            result = p.returncode
+            if (result != 0):
+                logging.error('[%s] could not set the icon to the dmg file, dmg creation failed!', script_name)
+                sys.exit(1)
+        except IOError, e:
+            logging.error('[%s] could not adjust the view (%s), dmg creation failed!', script_name, e)
+            sys.exit(1)
+        except OSError, e:
+            logging.error('[%s] could not set the icon to the dmg file(%s), dmg creation failed!', script_name, e)
+            sys.exit(1)
+
+    if (doCompressDmg is True):
+        logging.info('[%s] finished creating dmg file, resulting file is "%s"', script_name, dmg_file)
+

=== added file 'resources/osx/expander.py'
--- resources/osx/expander.py	1970-01-01 00:00:00 +0000
+++ resources/osx/expander.py	2011-02-26 20:37:07 +0000
@@ -0,0 +1,195 @@
+#!/usr/bin/python
+# -*- encoding: utf-8 -*-
+
+# TODOs:
+# - defaults for non-supplied expansions:
+#   template contains 
+
+import ConfigParser
+import logging
+import optparse
+import os
+import re
+import sys
+
+# variable expansion:
+# - %(dog)s --- normal python expansion
+# - %(dog%)s --- no python expansion, leave as is (stripping the trailing %)
+# - %(dog:cat) --- if there is an expansion for dog, dog will be used; otherwise if cat exists cat will be used
+# - %(dog=cat) --- if there is an expansion for dog, dog will be used; otherwise "cat" will be used
+# reConf = re.compile(r'(?<!%)%\((?P<key>[^\(]+?)\)s')
+reConf = re.compile(r'(?P<verbatim>%?)%\((?P<key>[^+=:&\)]+?)(?:(?P<kind>[+=:&])(?P<default>[^\)]+))?\)(?P<type>s|d)')
+
+def expandVariable(match, expansions, errors):
+    key = match.group('key')
+    kind = match.group('kind')
+    default = match.group('default')
+    typ = match.group('type')
+    verbatim = match.group('verbatim')
+
+    if verbatim:
+        return match.group(0)[1:]
+
+    # literal default
+    if kind == '=':
+        if key in expansions:
+            return expansions[key]
+        return default
+
+    # variable default
+    if kind == ':' and default in expansions:
+        return expansions[default]
+
+    if kind == '+' and default in expansions:
+        if key in expansions:
+            key = expansions[key]
+        if typ == 's':
+            return '%s%s' % (key, expansions[default])
+        if typ == 'd':
+            try:
+                return str(int(key) + int(expansions[default]))
+            except:
+                pass
+
+    if kind == '&' and default in expansions:
+        if typ == 's':
+            return '%s%s' % (key, expansions[default])
+        if typ == 'd':
+            try:
+                return str(int(key) + int(expansions[default]))
+            except:
+                pass
+
+    if key in expansions:
+        return expansions[key]
+        
+    if not match.group(0) in errors:
+        errors.append(match.group(0))
+
+    return None
+
+options = None
+
+if __name__ == '__main__':
+
+    # get config file
+    parser = optparse.OptionParser()
+    parser.add_option('-c', '--config', dest = 'config', help = 'config file', metavar = 'CONFIG')
+    parser.add_option('-t', '--template', dest = 'template', help = 'template file', metavar = 'TEMPLATE')
+    parser.add_option('-x', '--expandto', dest = 'expanded', help = 'expanded file', metavar = 'EXPANDED')
+    parser.add_option('-e', '--echo', dest = 'echo', help = 'echo variable', metavar = 'ECHOVAR')
+
+    (options, args) = parser.parse_args()
+
+    if not options.config:
+        parser.error('option --config|-c is required')
+    if not os.path.exists(options.config):
+        parser.error('config file "%s" does not exist' % options.config)
+    if not options.echo:
+        if not options.template:
+            parser.error('option --template|-t is required')
+        if not os.path.exists(options.template):
+            parser.error('template file "%s" does not exist' % options.template)
+        if not options.expanded:
+            parser.error('option --expandto|-e is required')
+
+    logHandler = logging.StreamHandler()
+    logHandler.setFormatter(logging.Formatter('%(asctime)s %(levelname)-8s %(message)s',
+                                              '%a, %d %b %Y %H:%M:%S'))
+    logging.getLogger().addHandler(logHandler)
+    logging.getLogger().setLevel(logging.DEBUG)
+
+    config = ConfigParser.RawConfigParser()
+    config.readfp(open(options.config, 'r'))
+
+    if not config.has_section('openlp'):
+        logging.error('[expander] %s: config file "%s" lacks an [openlp] section',
+                      options.template, options.config)
+
+    expansions = dict()
+    for k in config.options('openlp'):
+        expansions[k] = config.get('openlp', k)
+
+    # commandline overrides?
+    for override in args:
+        if not '=' in override:
+            continue
+        
+        (k, v) = override.split('=', 2)
+        expansions[k] = v
+
+    if options.echo:
+        if options.echo in expansions:
+            print expansions[options.echo]
+            sys.exit(0)
+        else:
+            sys.exit(1)
+
+
+    # closure to capture expansions and errors variable
+    errors = []
+    expanded = []
+    
+
+    try:
+        # try to expand the template
+        line = 0
+        faulty = False
+
+        template = open(options.template, 'r')
+        raw = template.readlines()
+        template.close()
+
+        def _expand(m):
+            return expandVariable(m, expansions = expansions, errors = errors)
+    
+        for l in raw:
+            line += 1
+            exp = reConf.sub(_expand, l)
+            if errors:
+                for key in errors:
+                    logging.error('[expander] %s: line %d: could not expand key "%s"', options.template, line, key)
+                faulty = True
+                errors = []
+            else:
+                expanded.append(exp)
+
+        if faulty:
+            sys.exit(1)
+
+        # successfully expanded template, now backup potentially existing target file
+        targetFile = options.expanded % expansions
+        if os.path.exists(targetFile):
+            if os.path.exists('%s~' % targetFile):
+                os.unlink('%s~' % targetFile)
+            os.rename(options.expanded, '%s~' % targetFile)
+            logging.info('[expander] %s: backed up existing target file "%s" to "%s"',
+                         options.template, targetFile, '%s~' % options.expanded)
+        
+
+        # TODO: make sure that target directory exists
+        targetDir = os.path.dirname(targetFile)
+        if not os.path.exists(targetDir):
+            os.makedirs(targetDir)
+
+        # write target file
+        try:
+            target = open(targetFile, 'w')
+            for exp in expanded:
+                target.write(exp)
+            target.close()
+        except Exception, e:
+            logging.error('[expander] %s: could not expand to "%s"', options.template, options.expaned, e)
+
+
+        # copy over file access mode from template
+        mode = os.stat(options.template)
+        os.chmod(options.expanded, mode.st_mode)
+
+        logging.info('[expander] expanded "%s" to "%s"',
+                     options.template, options.expanded)
+    
+
+    except:
+        pass
+

=== added file 'resources/osx/installation-background.png'
Binary files resources/osx/installation-background.png	1970-01-01 00:00:00 +0000 and resources/osx/installation-background.png	2011-02-26 20:37:07 +0000 differ
=== added file 'resources/osx/openlp-logo-420x420-background.png'
Binary files resources/osx/openlp-logo-420x420-background.png	1970-01-01 00:00:00 +0000 and resources/osx/openlp-logo-420x420-background.png	2011-02-26 20:37:07 +0000 differ
=== added file 'resources/osx/openlp-logo-420x420.png'
Binary files resources/osx/openlp-logo-420x420.png	1970-01-01 00:00:00 +0000 and resources/osx/openlp-logo-420x420.png	2011-02-26 20:37:07 +0000 differ
=== added file 'resources/osx/openlp-logo-with-text.icns'
Binary files resources/osx/openlp-logo-with-text.icns	1970-01-01 00:00:00 +0000 and resources/osx/openlp-logo-with-text.icns	2011-02-26 20:37:07 +0000 differ
=== added file 'resources/osx/openlp-splash-screen.png'
Binary files resources/osx/openlp-splash-screen.png	1970-01-01 00:00:00 +0000 and resources/osx/openlp-splash-screen.png	2011-02-26 20:37:07 +0000 differ
=== added file 'resources/osx/openlp.cfg'
--- resources/osx/openlp.cfg	1970-01-01 00:00:00 +0000
+++ resources/osx/openlp.cfg	2011-02-26 20:37:07 +0000
@@ -0,0 +1,11 @@
+[openlp]
+openlp_appname = OpenLP
+openlp_dmgname = OpenLP-1.9.4-bzrXXXX
+openlp_version = XXXX
+openlp_full_version = 1.9.4-latest
+openlp_basedir = /Users/openlp/trunk
+openlp_icon_file = openlp-logo-with-text.icns
+openlp_dmg_icon_file = openlp-logo-420x420.png
+installer_backgroundimage_file = installation-background.png
+pyinstaller_basedir = /Users/openlp/pyinstaller/trunk
+qt_menu_basedir = /Library/Frameworks/QtGui.framework/Versions/4/Resources/qt_menu.nib

=== added file 'resources/osx/openlp.spec.master'
--- resources/osx/openlp.spec.master	1970-01-01 00:00:00 +0000
+++ resources/osx/openlp.spec.master	2011-02-26 20:37:07 +0000
@@ -0,0 +1,24 @@
+# -*- mode: python -*-
+a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), '%(openlp_basedir)s/openlp.pyw'],
+             pathex=['%(pyinstaller_basedir)s'], hookspath=['%(openlp_basedir)s/resources/pyinstaller'])
+pyz = PYZ(a.pure)
+exe = EXE(pyz,
+          a.scripts,
+          exclude_binaries=1,
+          name=os.path.join('build/pyi.darwin/openlp', 'openlp'),
+          debug=False,
+          strip=False,
+          upx=True,
+          console=1 )
+coll = COLLECT( exe,
+               a.binaries,
+               a.zipfiles,
+               a.datas,
+               strip=False,
+               upx=True,
+               name=os.path.join('dist', 'openlp'))
+import sys
+if sys.platform.startswith("darwin"):
+    app = BUNDLE(coll,
+                 name='%(openlp_appname)s.app',
+                 version='%(openlp_version)s')

=== added file 'resources/osx/version.master'
--- resources/osx/version.master	1970-01-01 00:00:00 +0000
+++ resources/osx/version.master	2011-02-26 20:37:07 +0000
@@ -0,0 +1,1 @@
+%(openlp_full_version)s


Follow ups