diff --git a/macbuild/LICENSE b/macbuild/LICENSE new file mode 100644 index 000000000..a47d294dd --- /dev/null +++ b/macbuild/LICENSE @@ -0,0 +1,30 @@ +The following two files are derivative works of: + https://github.com/andreyvit/create-dmg.git + + (1) makeDMG4mac.py + (2) Resources/template-KLayoutDMG.applescript + +The original "LICENSE" file is quoted below. +=============================================================================== +The MIT License (MIT) + +Copyright (c) 2008-2014 Andrey Tarantsov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +=============================================================================== diff --git a/macbuild/ReadMe.md b/macbuild/ReadMe.md index 0e39fdb87..7412de414 100644 --- a/macbuild/ReadMe.md +++ b/macbuild/ReadMe.md @@ -1,4 +1,4 @@ -<< Draft Version 0.003>> Relevant KLayout version: 0.25.1 +Relevant KLayout version: 0.25.1 # 1. Introduction This directory "macbuild" contains different files required for building KLayout (http://www.klayout.de/) version 0.25 or later for different Mac OSXs including: @@ -15,7 +15,7 @@ By default, Qt framework is "Qt5" from Mac Ports (https://www.macports.org/) whi ### IMPORTANT ``` * Please DO NOT USE "Qt 5.10.0" which is problematic in showing your design in the main canvas. -* Please USE "Qt 5.9.x" instead. +* Please USE "Qt 5.9.x" instead (5.9.3 is recommended). * Building with Qt4 will lead to some compile errors. ``` Also by default, supported script languages, i.e, Ruby and Python, are those standard ones bundled with the OS. @@ -41,7 +41,7 @@ $ cd /where/'build.sh'/exists $ ./build4mac.py -d ``` 3. Confirm successful build. -4. Run 'build4mac.py' again with the same options used in 2. PLUS "-y" to deploy executables and libraries (including Qt's frameworks) under "klayout.app" bundle. +4. Run 'build4mac.py' again with the same options used in 2. PLUS "-y" to deploy executables and libraries (including Qt's frameworks) under "klayout.app" bundle. The buddy command line tools (strm*) will also be deployed. ``` $ ./build4mac.py -d -y ``` @@ -58,7 +58,7 @@ $ cd /where/'build.sh'/exists $ ./build4mac.py -r mp24 -p mp36 ``` 3. Confirm successful build. -4. Run 'build4mac.py' again with the same options used in 2. PLUS "-Y" to deploy executables and libraries under "klayout.app" bundle. +4. Run 'build4mac.py' again with the same options used in 2. PLUS "-Y" to deploy executables and libraries under "klayout.app" bundle. The buddy command line tools (strm*) will also be deployed. ``` $ ./build4mac.py -r mp24 -p mp36 -Y ``` @@ -67,6 +67,21 @@ That is, paths to other modules (Ruby, Python, and Qt5 Frameworks) remain unchan 5. Copy/move generated bundles ("klayout.app" and "klayout.scripts/") to your "/Applications" directory for installation. -By: Kazzz (January 08, 2018) +---- +# 4. Making a DMG installer +You can make a DMG installer using another Python script 'makeDMG4mac.py'. +This script requires a directory generated by 'build4mac.py' with [-y|-Y] option (refer to 3A.4 & 3B.4) + +1. Make a symbolic link from the parent directory (where 'build.sh' exists) to 'makeDMG4mac.py', that is, +``` +makeDMG4mac.py -> macbuild/makeDMG4mac.py +``` +2. Invoke 'makeDMG4mac.py' with -p and -m options, for example, +``` +$ cd /where/'build.sh'/exists +$ ./makeDMG4mac.py -p qt5.pkg.macos-HighSierra-release -m +``` + +By: Kazzz (January 16, 2018) [End of File] diff --git a/macbuild/ReadMe.txt b/macbuild/ReadMe.txt index ffa630d17..c8519bab3 100644 --- a/macbuild/ReadMe.txt +++ b/macbuild/ReadMe.txt @@ -1,4 +1,4 @@ -<< Draft Version 0.003>> +<< Draft Version 0.004>> Relevant KLayout version: 0.25.1 1. Introduction: @@ -15,7 +15,7 @@ Relevant KLayout version: 0.25.1 : * Please DO NOT USE "5.10.0" which is problematic in showing your design in the main canvas. - * Please USE "5.9.x" instead. + * Please USE "5.9.x" instead (5.9.3 is recommended). * Building with Qt4 will lead to some compile errors. Also by default, supported script languages, i.e, Ruby and Python, are those @@ -42,6 +42,7 @@ Relevant KLayout version: 0.25.1 (3) Confirm successful build. (4) Run 'build4mac.py' again with the same options used in (2) PLUS "-y" to deploy executables and libraries (including Qt's frameworks) under "klayout.app" bundle. + The buddy command line tools (strm*) will also be deployed. $ ./build4mac.py -d -y (5) Copy/move generated bundles ("klayout.app" and "klayout.scripts/") to your "/Applications" directory for installation. @@ -57,6 +58,7 @@ Relevant KLayout version: 0.25.1 (3) Confirm successful build. (4) Run 'build4mac.py' again with the same options used in (2) PLUS "-Y" to deploy executables and libraries under "klayout.app" bundle. + The buddy command line tools (strm*) will also be deployed. $ ./build4mac.py -r mp24 -p mp36 -Y * [-Y|--DEPOLY] option deploys KLayout's dylibs and executables only. That is, paths to other modules (Ruby, Python, and Qt5 Frameworks) @@ -64,6 +66,15 @@ Relevant KLayout version: 0.25.1 (5) Copy/move generated bundles ("klayout.app" and "klayout.scripts/") to your "/Applications" directory for installation. -By: Kazzz (January 08, 2018) +4. Making a DMG installer + You can make a DMG installer using another Python script 'makeDMG4mac.py'. + This script requires a directory generated by 'build4mac.py' with [-y|-Y] option (refer to 3A.4 & 3B.4) + (1) Make a symbolic link from the parent directory (where 'build.sh' exists) to 'makeDMG4mac.py', that is, + makeDMG4mac.py -> macbuild/makeDMG4mac.py + (2) Invoke 'makeDMG4mac.py' with -p and -m options, for example, + $ cd /where/'build.sh'/exists + $ ./makeDMG4mac.py -p qt5.pkg.macos-HighSierra-release -m + +By: Kazzz (January 16, 2018) [End of File] diff --git a/macbuild/Resources/KLayoutDMG-Back.logoist b/macbuild/Resources/KLayoutDMG-Back.logoist new file mode 100644 index 000000000..850b30229 Binary files /dev/null and b/macbuild/Resources/KLayoutDMG-Back.logoist differ diff --git a/macbuild/Resources/KLayoutDMG-Back.png b/macbuild/Resources/KLayoutDMG-Back.png new file mode 100644 index 000000000..a4090afad Binary files /dev/null and b/macbuild/Resources/KLayoutDMG-Back.png differ diff --git a/macbuild/Resources/template-KLayoutDMG.applescript b/macbuild/Resources/template-KLayoutDMG.applescript new file mode 100644 index 000000000..cb369eacb --- /dev/null +++ b/macbuild/Resources/template-KLayoutDMG.applescript @@ -0,0 +1,116 @@ +------------------------------------------------------------------------------------------------- +(* + * Template File: + * macbuild/Resources/template-KLayoutDMG.applescript + * + * Actual AppleScrip File to be generated: + * macbuild/Resources/KLayoutDMG.applescript + * + * Description: + * A template AppleScript to make a fancy DMG installer of KLayout + * (http://www.klayout.de/index.php) bundles. + * "makeDMG4mac.py" will read this template and generate the actual AppleScript to execute. + * Values to be found and replaced by "makeDMG4mac.py" are marked by ${KEYWORD}. + * + * The background image was designed using Logoist2 (http://www.syniumsoftware.com/en/logoist) + * and exported to a PNG file of 1000 x 700 pix size. + *----------------------------------------------------------------------------------------------- + * This is a derivative work of Ref. 2) below. Refer to "macbuild/LICENSE" file. + * Ref. + * 1) https://el-tramo.be/guides/fancy-dmg/ + * 2) https://github.com/andreyvit/create-dmg.git + *) +------------------------------------------------------------------------------------------------- +on run (volumeName) -- most likely, the volume name is "KLayout" + tell application "Finder" + tell disk (volumeName as string) + -- [1] Open the volume + open + + -- [2] Set the key coordinates and windows size + -- The size of given background PNG image is 1000 x 700 pix + -- ORGX = [50] pix + -- ORGY = [100] pix + -- WIN_WIDTH = [1000] pix + -- WIN_HEIGHT = [700] pix + set posMargin to 50 + set negMargin to 10 + set theTopLeftX to ${ORGX} + set theTopLeftY to ${ORGY} + set theWidth to ${WIN_WIDTH} + set theHeight to ${WIN_HEIGHT} + set theBottomRightX to (theTopLeftX + theWidth + posMargin) + set theBottomRightY to (theTopLeftY + theHeight + posMargin) + + -- [3] Set the full path to .DS_Store file + set dotDSStore to "${FULL_PATH_DS_STORE}" + + -- [4] Set global view options + tell container window + set current view to icon view + set toolbar visible to false + set statusbar visible to false + set statusbar visible to false + set bounds to {theTopLeftX, theTopLeftY, theBottomRightX, theBottomRightY} + set position of every item to {theTopLeftX + 150, theTopLeftY + 350} + end tell + + -- [5] Set icon view options + set opts to the icon view options of container window + tell opts + set icon size to 80 + set text size to 16 + set arrangement to not arranged + end tell + + -- [6] Set the background PNG image (1000 x 700 pix) file name stored + set background picture of opts to file ".background:${BACKGROUND_PNG_FILE}" + + -- [7] Set positions of each icon + -- ITEM_1 = klayout.app {960, 140} + -- ITEM_2 = klayout.scripts {610, 140} + -- ITEM_3 = Applications {790, 140} + set position of item "${ITEM_1}" to {${X1}, ${Y1}} + set position of item "${ITEM_2}" to {${X2}, ${Y2}} + set position of item "${ITEM_3}" to {${X3}, ${Y3}} + + -- [8] Update the contents of container + close + open + update without registering applications + + -- [9] Force save the negatively resized window size + delay 2 + tell container window + set statusbar visible to false + set bounds to {theTopLeftX, theTopLeftY, theBottomRightX - negMargin, theBottomRightY - negMargin} + end tell + update without registering applications + end tell + + -- [10] Restore back the original window size + delay 2 + tell disk (volumeName as string) + tell container window + set statusbar visible to false + set bounds to {theTopLeftX, theTopLeftY, theBottomRightX, theBottomRightY} + end tell + update without registering applications + end tell + + -- [11] Wait for some time so that "Finder" can complete writing to .DS_Store file + delay 3 + set elapsedTime to 0 + set ejected to false + repeat while ejected is false + delay 1 + set elapsedTime to elapsedTime + 1 + if (do shell script "${CHECK_BASH}") = "0" then set ejected to true + end repeat + log "### Elapsed <" & elapsedTime & "> [sec] for writing .DS_Store file." + end tell +end run + +-- +-- End of file +-- diff --git a/macbuild/makeDMG4mac.py b/macbuild/makeDMG4mac.py new file mode 100755 index 000000000..f7044037a --- /dev/null +++ b/macbuild/makeDMG4mac.py @@ -0,0 +1,540 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +#============================================================================================= +# File: "macbuild/makeDMG4mac.py" +# +# Python script for making a DMG file of KLayout (http://www.klayout.de/index.php) bundles. +# +# This is a derivative work of Ref. 2) below. Refer to "macbuild/LICENSE" file. +# Ref. +# 1) https://el-tramo.be/guides/fancy-dmg/ +# 2) https://github.com/andreyvit/create-dmg.git +#============================================================================================= +from __future__ import print_function # to use print() of Python 3 in Python >= 2.7 +from time import sleep +import sys +import os +import shutil +import glob +import platform +import optparse +import subprocess +import hashlib + +#------------------------------------------------------------------------------- +## To import global dictionaries of different modules and utility functions +#------------------------------------------------------------------------------- +mydir = os.path.dirname(os.path.abspath(__file__)) +sys.path.append( mydir + "/macbuild" ) +from build4mac_util import * + +#------------------------------------------------------------------------------- +## To set global variables including present directory and platform info. +#------------------------------------------------------------------------------- +def SetGlobals(): + global ProjectDir # project directory where "build.sh" exists + global Usage # string on usage + global GenOSName # generic OS name + global Platform # platform + global PkgDir # the package directory where "klayout.app" and "klayout.scripts" exist + global OpClean # 'clean' operation + global OpMake # 'make' operation + global DMGSerialNum # the DMG serial number + global QtIdentification # Qt identification + global Version # KLayout's version + global OccupiedDS # approx. occupied disc space + global BackgroundPNG # the background PNG image file + global VolumeIcons # the volume icon file + global AppleScriptDMG # the AppleScript for KLayout DMG + global WorkDMG # work DMG file created under ProjectDir/ + global VolumeDMG # the volume name of DMG + global TargetDMG # the name of target DMG file + global RootApplications # reserved directory name for applications + # auxiliary variables on platform + global System # 6-tuple from platform.uname() + global Node # - do - + global Release # - do - + global Version # - do - + global Machine # - do - + global Processor # - do - + global Bit # machine bit-size + + Usage = "\n" + Usage += "--------------------------------------------------------------------------------------------------------\n" + Usage += "<< Usage of 'makeDMG4mac.py' >>\n" + Usage += " for making a DMG file of KLayout 0.25 or later on different Apple Mac OSX platforms.\n" + Usage += "\n" + Usage += "$ [python] ./makeDMG4mac.py \n" + Usage += " option & argument : descriptions | default value\n" + Usage += " ----------------------------------------------------------------------------------+---------------\n" + Usage += " <-p|--pkg > : package directory created by `build4mac.py` with [-y|-Y] | `` \n" + Usage += " : like 'qt5.pkg.macos-HighSierra-release' | \n" + Usage += " <-c|--clean> : clean the work directory | disabled \n" + Usage += " <-m|--make> : make a compressed DMG file | disabled \n" + Usage += " : <-c|--clean> and <-m|--make> are mutually exclusive | \n" + Usage += " [-q|--qt ] : ID name of deployed Qt | Qt593mp \n" + Usage += " [-s|--serial ] : DMG serial number | 1 \n" + Usage += " [-?|--?] : print this usage and exit | disabled \n" + Usage += "--------------------------------------------------------------------------------------------------------\n" + + ProjectDir = os.getcwd() + (System, Node, Release, Version, Machine, Processor) = platform.uname() + + if not System == "Darwin": + print("") + print( "!!! Sorry. Your system <%s> looks like non-Mac" % System, file=sys.stderr ) + print(Usage) + quit() + + release = int( Release.split(".")[0] ) # take the first of ['14', '5', '0'] + if release == 14: + GenOSName = "MacOSX" + Platform = "Yosemite" + elif release == 15: + GenOSName = "MacOSX" + Platform = "ElCapitan" + elif release == 16: + GenOSName = "macOS" + Platform = "Sierra" + elif release == 17: + GenOSName = "macOS" + Platform = "HighSierra" + else: + Platform = "" + print("") + print( "!!! Sorry. Unsupported major OS release <%d>" % release, file=sys.stderr ) + print(Usage) + quit() + + if not Machine == "x86_64": + print("") + print( "!!! Sorry. Only x86_64 architecture machine is supported but found <%s>" % Machine, file=sys.stderr ) + print(Usage) + quit() + + PkgDir = "" + OpClean = False + OpMake = False + DMGSerialNum = 1 + QtIdentification = "Qt593mp" + Version = GetKLayoutVersionFrom( "./version.sh" ) + OccupiedDS = -1 + BackgroundPNG = "KLayoutDMG-Back.png" + VolumeIcons = "KLayoutHDD.icns" + AppleScriptDMG = "macbuild/Resources/KLayoutDMG.applescript" + WorkDMG = "work-KLayout.dmg" + VolumeDMG = "KLayout" + TargetDMG = "" + RootApplications = "/Applications" + +#------------------------------------------------------------------------------ +## To check the contents of the package directory +# +# @return on success, positive integer in [MB] that tells approx. occupied disc space; +# on failure, -1 +#------------------------------------------------------------------------------ +def CheckPkgDirectory(): + + if PkgDir == "": + print( "! Package directory is not specified", file=sys.stderr ) + print(Usage) + return -1 + + if not os.path.isdir(PkgDir): + print( "! Specified package directory <%s> does not exist" % PkgDir, file=sys.stderr ) + print( "" ) + return -1 + + os.chdir(PkgDir) + items = glob.glob( "*" ) # must be ['klayout.app', 'klayout.scripts'] + if not len(items) == 2: + print( "! The package directory <%s> must have just <2> directories ['klayout.app', 'klayout.scripts']" % PkgDir, file=sys.stderr ) + print( "" ) + os.chdir(ProjectDir) + return -1 + + if not os.path.isdir( "klayout.app" ): + print( "! The package directory <%s> does not hold bundle" % PkgDir, file=sys.stderr ) + print( "" ) + os.chdir(ProjectDir) + return -1 + + if not os.path.isdir( "klayout.scripts" ): + print( "! The package directory <%s> does not hold subdirectory" % PkgDir, file=sys.stderr ) + print( "" ) + os.chdir(ProjectDir) + return -1 + + os.chdir( "klayout.scripts" ) + if not os.path.isdir( "KLayoutEditor.app" ): + print( "! The package directory <%s> does not hold bundle under 'klayout.scripts/'" % PkgDir, file=sys.stderr ) + print( "" ) + os.chdir(ProjectDir) + return -1 + + if not os.path.isdir( "KLayoutViewer.app" ): + print( "! The package directory <%s> does not hold bundle under 'klayout.scripts/'" % PkgDir, file=sys.stderr ) + print( "" ) + os.chdir(ProjectDir) + return -1 + + os.chdir(ProjectDir) + os.chdir(PkgDir) + size1 = int( os.popen( "\du -sm klayout.app" ) .read().strip("\n").split("\t")[0] ) + size2 = int( os.popen( "\du -sm klayout.scripts" ).read().strip("\n").split("\t")[0] ) + os.chdir(ProjectDir) + return size1+size2 + +#------------------------------------------------------------------------------ +## To get command line parameters +#------------------------------------------------------------------------------ +def ParseCommandLineArguments(): + global ProjectDir + global Usage + global GenOSName + global Platform + global PkgDir + global OpClean + global OpMake + global DMGSerialNum + global QtIdentification + global Version + global OccupiedDS + global TargetDMG + + p = optparse.OptionParser( usage=Usage ) + p.add_option( '-p', '--pkg', + dest='pkg_dir', + help="the pkg directory" ) + + p.add_option( '-c', '--clean', + action='store_true', + dest='operation_clean', + default=False, + help="clean operation" ) + + p.add_option( '-m', '--make', + action='store_true', + dest='operation_make', + default=False, + help="make operation" ) + + p.add_option( '-q', '--qt', + dest='qt_identification', + help="Qt's ID" ) + + p.add_option( '-s', '--serial', + dest='dmg_serial', + help="DMG serial number" ) + + p.add_option( '-?', '--??', + action='store_true', + dest='checkusage', + default=False, + help='check usage' ) + + p.set_defaults( pkg_dir = "", + operation_clean = False, + operation_make = False, + qt_identification = "Qt593mp", + dmg_serial = "1", + checkusage = False ) + + opt, args = p.parse_args() + if (opt.checkusage): + print(Usage) + quit() + + PkgDir = opt.pkg_dir + OpClean = opt.operation_clean + OpMake = opt.operation_make + QtIdentification = opt.qt_identification + DMGSerialNum = int(opt.dmg_serial) + TargetDMG = "klayout-%s-%s-%s-%d-%s.dmg" % (Version, GenOSName, Platform, DMGSerialNum, QtIdentification) + + OccupiedDS = CheckPkgDirectory() + if not OccupiedDS > 0: + quit() + + if (OpClean and OpMake) or (not OpClean and not OpMake): + print( "! Specify <-c|--clean> OR <-m|--make>", file=sys.stderr ) + print(Usage) + quit() + +#------------------------------------------------------------------------------ +## Make the target DMG file +# +# @param[in] msg message to print +# +# @return True on success; False on failure +#------------------------------------------------------------------------------ +def MakeTargetDMGFile(msg=""): + #----------------------------------------------------------------------- + # The work DMG is mounted like: + # /dev/disk6s1 248Mi 228Mi 20Mi 93% 58449 5027 92% /Volumes/KLayout + #----------------------------------------------------------------------- + global MountDir # the mount directory: eg. /Volumes/KLayout + global FileSys # the file system : eg. /dev/disk6s1 + + #------------------------------------------------------------- + # [1] Print message + #------------------------------------------------------------- + if not msg == "": + print(msg) + + #------------------------------------------------------------- + # [2] Do the following jobs (0) through (14) sequentially + #------------------------------------------------------------- + + #-------------------------------------------------------- + # (0) Cleanup ProjectDir/ + #-------------------------------------------------------- + CleanUp() + + #-------------------------------------------------------- + # (1) Read the AppleScript template file and generate + # the actual one to execute later + #-------------------------------------------------------- + os.chdir(ProjectDir) + print( ">>> (1) Preparing AppleScript to execute later..." ) + tempScr = "macbuild/Resources/template-KLayoutDMG.applescript" + try: + fd = open( tempScr, "r" ) + tmpl = fd.read() + fd.close() + except Exception as e: + print( " ! Failed to read <%s>" % tempScr, file=sys.stderr ) + return False + else: + t = string.Template(tmpl) + # Figures below were determined by experiments for best fit + applescript = t.safe_substitute( + ORGX='50', ORGY='100', + WIN_WIDTH='1000', WIN_HEIGHT='700', + FULL_PATH_DS_STORE='/Volumes/%s/.DS_Store' % VolumeDMG, + BACKGROUND_PNG_FILE=BackgroundPNG, + ITEM_1='klayout.app', X1='960', Y1='140', + ITEM_2='klayout.scripts', X2='610', Y2='140', + ITEM_3='Applications', X3='790', Y3='140', + CHECK_BASH='[ -f " & dotDSStore & " ]; echo $?' + ) + try: + # print(applescript) + fd = open( AppleScriptDMG, "w" ) + fd.write(applescript) + fd.close() + except Exception as e: + print( "! Failed to write <%s>" % AppleScriptDMG, file=sys.stderr ) + return False + else: + print( " saved <%s>" % AppleScriptDMG ) + + #---------------------------------------------------- + # (2) Create a work disk image under ProjectDir/ + #---------------------------------------------------- + if os.path.exists(WorkDMG): + os.remove(WorkDMG) + dmgsize = OccupiedDS + 20 # approx. occupied size plus 20[MB] + cmdline = 'hdiutil create -srcfolder %s -volname %s -fs HFS+ -fsargs "-c c=64,a=16,e=16" ' + cmdline += '-format UDRW -size %dm %s' + command = cmdline % (PkgDir, VolumeDMG, dmgsize, WorkDMG) + print( ">>> (2) Creating a work DMG file <%s> of <%d> [MB] with the volume name of <%s>..." % (WorkDMG, dmgsize, VolumeDMG) ) + os.system(command) + MountDir = "/Volumes/%s" % VolumeDMG + + #-------------------------------------------------------- + # (3) Check if the mount point 'MountDir' already exists. + # If so, unmount it first. + #-------------------------------------------------------- + command1 = "hdiutil info | grep %s | grep \"/dev/\" | awk '{print $1}'" % VolumeDMG + print ( ">>> (3) Checking if the mount point <%s> already exists..." % MountDir) + FileSys = os.popen(command1).read().strip('\n') + if os.path.isdir(MountDir) and not FileSys == "": + command2 = "hdiutil detach %s" % FileSys + os.system(command2) + print( " Mount directory <%s> was detached" % MountDir ) + else: + print( " Mount directory <%s> does not exist; nothing to do" % MountDir ) + + #-------------------------------------------------------- + # (4) Mount the DMG + #-------------------------------------------------------- + print( ">>> (4) Mounting <%s> to <%s>" % (WorkDMG, MountDir ) ) + command1 = "hdiutil attach %s -readwrite -noverify -noautoopen -quiet" % WorkDMG + os.system(command1) + + command2 = "hdiutil info | grep %s | grep \"/dev/\" | awk '{print $1}'" % VolumeDMG + FileSys = os.popen(command2).read().strip('\n') + if FileSys == "": + print( "! Failed to identify the file system on which <%s> is mounted" % VolumeDMG ) + return False + else: + print( " File System = %s" % FileSys ) + + #-------------------------------------------------------- + # (5) Copy the background image + #-------------------------------------------------------- + print( ">>> (5) Copying the background image..." ) + imageSrc = "macbuild/Resources/%s" % BackgroundPNG + imageDest = "%s/.background" % MountDir + if not os.path.isdir(imageDest): + os.mkdir(imageDest) + command = "\cp -p %s %s/%s" % (imageSrc, imageDest, BackgroundPNG) + os.system(command) + + #-------------------------------------------------------- + # (6) Create a symbolic link to /Applications + #-------------------------------------------------------- + print( ">>> (6) Creating a symbolic link to /Applications..." ) + command = "\ln -s %s %s/%s" % (RootApplications, MountDir, RootApplications) + os.system(command) + + #-------------------------------------------------------- + # (7) Run the AppleScript + #-------------------------------------------------------- + print( ">>> (7) Running the AppleScript..." ) + command = "/usr/bin/osascript %s %s" % (AppleScriptDMG, VolumeDMG) + process = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True ) + output, error = process.communicate() + if not output == "": + print( " STDOUT: %s" % output ) + if not error == "": + print( " STDERR: %s" % error ) + + #-------------------------------------------------------- + # (8) Copy the custom volume icon + #-------------------------------------------------------- + sleep(4) + print( ">>> (8) Copying the volume icon..." ) + iconsSrc = "macbuild/Resources/%s" % VolumeIcons + iconsDest = "%s/.VolumeIcon.icns" % MountDir + command1 = "\cp -p %s %s" % (iconsSrc, iconsDest) + command2 = "SetFile -c icnC %s" % iconsDest + os.system(command1) + sleep(2) + os.system(command2) + sleep(2) + + #-------------------------------------------------------- + # (9) Change the permission + #-------------------------------------------------------- + print( ">>> (9) Changing permission to 755..." ) + command = "\chmod -Rf 755 %s &> /dev/null" % MountDir + os.system(command) + + #-------------------------------------------------------- + # (10) Set volume bootability and startup disk options. + # The folder will open on mount. + #-------------------------------------------------------- + print( ">>> (10) Setting volume bootability and startup disk options..." ) + command = "bless --folder %s --openfolder %s" % (MountDir, MountDir) + os.system(command) + sleep(2) + + #-------------------------------------------------------- + # (11) Set attributes of files and directories + #-------------------------------------------------------- + print( ">>> (11) Setting attributes of files and directories..." ) + command = "SetFile -a C %s" % MountDir # Custom icon (allowed on folders) + os.system(command) + sleep(2) + + #-------------------------------------------------------- + # (12) Unmount the disk image + #-------------------------------------------------------- + print( ">>> (12) Unmounting the disk image..." ) + command = "hdiutil detach %s" % FileSys + os.system(command) + + #-------------------------------------------------------- + # (13) Compress the disk image + #-------------------------------------------------------- + print( "" ) + print( ">>> (13) Compressing the disk image..." ) + command = "hdiutil convert %s -format UDZO -imagekey zlib-level=9 -o %s" % (WorkDMG, TargetDMG) + os.system(command) + os.remove(WorkDMG) + print( "" ) + print( " generated compressed target DMG <%s>" % TargetDMG ) + + #-------------------------------------------------------- + # (14) Compute MD5 checksum + #-------------------------------------------------------- + print( "" ) + print( ">>> (14) Computing MD5 checksum..." ) + with open( TargetDMG, "rb" ) as f: + data = f.read() + md5 = hashlib.md5(data).hexdigest() + md5 += " *%s\n" % TargetDMG + f.close() + path, ext = os.path.splitext( os.path.basename(TargetDMG) ) + md5TargetDMG = path + ".dmg.md5" + with open( md5TargetDMG, "w" ) as f: + f.write(md5) + f.close() + print( " generated MD5 checksum file <%s>" % md5TargetDMG ) + print( "" ) + + return True + +#------------------------------------------------------------------------------ +## Clean up +# +# @param[in] msg message to print +# +#------------------------------------------------------------------------------ +def CleanUp(msg=""): + + #---------------------------------------------------- + # [1] Print message + #---------------------------------------------------- + if not msg == "": + print(msg) + + #---------------------------------------------------- + # [2] Clean up *.dmg* + #---------------------------------------------------- + os.chdir(ProjectDir) + dmgs = glob.glob( "*.dmg*" ) + for item in dmgs: + os.system( "rm -Rf %s" % item ) + + #---------------------------------------------------- + # [3] Clean up AppleScript if any + #---------------------------------------------------- + if os.path.exists(AppleScriptDMG) and os.path.isfile(AppleScriptDMG): + os.remove(AppleScriptDMG) + +#------------------------------------------------------------------------------ +## The main function +#------------------------------------------------------------------------------ +def Main(): + SetGlobals() + ParseCommandLineArguments() + if OpMake: + print( "" ) + print( " ### You are going to make <%s> from <%s>" % (TargetDMG, PkgDir) ) + print( " KLayout bundles occupy about <%d> [MB] of disc space." % OccupiedDS ) + print( "" ) + ok = MakeTargetDMGFile() + if not ok: + print( " !!! Failed to make the target DMG <%s> ..." % TargetDMG, file=sys.stderr ) + print( "", file=sys.stderr ) + else: + print( " ### Done making the target DMG" ) + print( "" ) + else: + print( "" ) + print( " ### You are going to clean up <%s> directory" % ProjectDir ) + CleanUp() + print( " ### Done cleaning up" ) + print( "" ) + +#=================================================================================== +if __name__ == "__main__": + Main() + +#--------------- +# End of file +#---------------