diff --git a/src/Makefile b/src/Makefile index 9f03fbba8b..9830d6ed7f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2901,10 +2901,30 @@ $(APPDIR)/Contents: ############################################################################## ### MacVim GUI -.PHONY: macvim macvimclean +.PHONY: macvim macvim-dmg macvimclean + +RELEASEDIR = MacVim/build/Release +DMGDIR = MacVim/build/dmg + macvim: $(VIMTARGET) xcodebuild -project MacVim/MacVim.xcodeproj $(XCODEFLAGS) +macvim-dmg: macvim + mkdir -p $(DMGDIR) + cp MacVim/mvim $(DMGDIR)/ + cp -r $(RELEASEDIR)/MacVim.app $(DMGDIR)/ + rm -rf $(RELEASEDIR)/MacVim-$(VERSION).dmg + create-dmg/create-dmg \ + --volname "MacVim $(VERSION)" \ + --volicon MacVim/icons/MacVim.icns \ + --background create-dmg/background.png \ + --window-size 650 470 \ + --icon-size 80 \ + --icon MacVim.app 240 320 \ + --icon mvim 570 80 \ + --app-drop-link 410 320 \ + $(RELEASEDIR)/MacVim-$(VERSION).dmg $(DMGDIR) + macvimclean: if test -d MacVim; then \ xcodebuild -project MacVim/MacVim.xcodeproj clean; \ diff --git a/src/create-dmg/LICENSE b/src/create-dmg/LICENSE new file mode 100644 index 0000000000..349b6d82b3 --- /dev/null +++ b/src/create-dmg/LICENSE @@ -0,0 +1,21 @@ +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/src/create-dmg/README b/src/create-dmg/README new file mode 100644 index 0000000000..4557795edb --- /dev/null +++ b/src/create-dmg/README @@ -0,0 +1,2 @@ +Content of this directory (except background.png) is copied from +https://github.com/andreyvit/create-dmg (5acf22f). diff --git a/src/create-dmg/background.png b/src/create-dmg/background.png new file mode 100644 index 0000000000..739494dc9f Binary files /dev/null and b/src/create-dmg/background.png differ diff --git a/src/create-dmg/background.pxd b/src/create-dmg/background.pxd new file mode 100644 index 0000000000..60dddda486 Binary files /dev/null and b/src/create-dmg/background.pxd differ diff --git a/src/create-dmg/builder/create-dmg.builder b/src/create-dmg/builder/create-dmg.builder new file mode 100644 index 0000000000..d4285280f1 --- /dev/null +++ b/src/create-dmg/builder/create-dmg.builder @@ -0,0 +1,26 @@ +SET app_name create-dmg + +VERSION create-dmg.cur create-dmg heads/master + +NEWDIR build.dir temp %-build - + +NEWFILE create-dmg.zip featured %.zip % + + +COPYTO [build.dir] + INTO create-dmg [create-dmg.cur]/create-dmg + INTO sample [create-dmg.cur]/sample + INTO support [create-dmg.cur]/support + +SUBSTVARS [build.dir]/create-dmg [[]] + + +ZIP [create-dmg.zip] + INTO [build-files-prefix] [build.dir] + + +PUT megabox-builds create-dmg.zip +PUT megabox-builds build.log + +PUT s3-builds create-dmg.zip +PUT s3-builds build.log diff --git a/src/create-dmg/create-dmg b/src/create-dmg/create-dmg new file mode 100755 index 0000000000..3e55dd9742 --- /dev/null +++ b/src/create-dmg/create-dmg @@ -0,0 +1,230 @@ +#! /bin/bash + +# Create a read-only disk image of the contents of a folder + +set -e; + +function pure_version() { + echo '1.0.0.2' +} + +function version() { + echo "create-dmg $(pure_version)" +} + +function usage() { + version + echo "Creates a fancy DMG file." + echo "Usage: $(basename $0) options... image.dmg source_folder" + echo "All contents of source_folder will be copied into the disk image." + echo "Options:" + echo " --volname name" + echo " set volume name (displayed in the Finder sidebar and window title)" + echo " --volicon icon.icns" + echo " set volume icon" + echo " --background pic.png" + echo " set folder background image (provide png, gif, jpg)" + echo " --window-pos x y" + echo " set position the folder window" + echo " --window-size width height" + echo " set size of the folder window" + echo " --text-size text_size" + echo " set window text size (10-16)" + echo " --icon-size icon_size" + echo " set window icons size (up to 128)" + echo " --icon file_name x y" + echo " set position of the file's icon" + echo " --hide-extension file_name" + echo " hide the extension of file" + echo " --custom-icon file_name custom_icon_or_sample_file x y" + echo " set position and custom icon" + echo " --app-drop-link x y" + echo " make a drop link to Applications, at location x,y" + echo " --eula eula_file" + echo " attach a license file to the dmg" + echo " --no-internet-enable" + echo " disable automatic mount©" + echo " --version show tool version number" + echo " -h, --help display this help" + exit 0 +} + +WINX=10 +WINY=60 +WINW=500 +WINH=350 +ICON_SIZE=128 +TEXT_SIZE=16 + +while test "${1:0:1}" = "-"; do + case $1 in + --volname) + VOLUME_NAME="$2" + shift; shift;; + --volicon) + VOLUME_ICON_FILE="$2" + shift; shift;; + --background) + BACKGROUND_FILE="$2" + BACKGROUND_FILE_NAME="$(basename $BACKGROUND_FILE)" + BACKGROUND_CLAUSE="set background picture of opts to file \".background:$BACKGROUND_FILE_NAME\"" + REPOSITION_HIDDEN_FILES_CLAUSE="set position of every item to {theBottomRightX + 100, 100}" + shift; shift;; + --icon-size) + ICON_SIZE="$2" + shift; shift;; + --text-size) + TEXT_SIZE="$2" + shift; shift;; + --window-pos) + WINX=$2; WINY=$3 + shift; shift; shift;; + --window-size) + WINW=$2; WINH=$3 + shift; shift; shift;; + --icon) + POSITION_CLAUSE="${POSITION_CLAUSE}set position of item \"$2\" to {$3, $4} +" + shift; shift; shift; shift;; + --hide-extension) + HIDING_CLAUSE="${HIDING_CLAUSE}set the extension hidden of item \"$2\" to true +" + shift; shift;; + --custom-icon) + shift; shift; shift; shift; shift;; + -h | --help) + usage;; + --version) + version; exit 0;; + --pure-version) + pure_version; exit 0;; + --app-drop-link) + APPLICATION_LINK=$2 + APPLICATION_CLAUSE="set position of item \"Applications\" to {$2, $3} +" + shift; shift; shift;; + --eula) + EULA_RSRC=$2 + shift; shift;; + --no-internet-enable) + NOINTERNET=1 + shift;; + -*) + echo "Unknown option $1. Run with --help for help." + exit 1;; + esac +done + +test -z "$2" && { + echo "Not enough arguments. Invoke with --help for help." + exit 1 +} + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +DMG_PATH="$1" +DMG_DIRNAME="$(dirname "$DMG_PATH")" +DMG_DIR="$(cd "$DMG_DIRNAME" > /dev/null; pwd)" +DMG_NAME="$(basename "$DMG_PATH")" +DMG_TEMP_NAME="$DMG_DIR/rw.${DMG_NAME}" +SRC_FOLDER="$(cd "$2" > /dev/null; pwd)" +test -z "$VOLUME_NAME" && VOLUME_NAME="$(basename "$DMG_PATH" .dmg)" + +AUX_PATH="$SCRIPT_DIR/support" + +test -d "$AUX_PATH" || { + echo "Cannot find support directory: $AUX_PATH" + exit 1 +} + +if [ -f "$SRC_FOLDER/.DS_Store" ]; then + echo "Deleting any .DS_Store in source folder" + rm "$SRC_FOLDER/.DS_Store" +fi + +# Create the image +echo "Creating disk image..." +test -f "${DMG_TEMP_NAME}" && rm -f "${DMG_TEMP_NAME}" +ACTUAL_SIZE=`du -sm "$SRC_FOLDER" | sed -e 's/ .*//g'` +DISK_IMAGE_SIZE=$(expr $ACTUAL_SIZE + 20) +hdiutil create -srcfolder "$SRC_FOLDER" -volname "${VOLUME_NAME}" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW -size ${DISK_IMAGE_SIZE}m "${DMG_TEMP_NAME}" + +# mount it +echo "Mounting disk image..." +MOUNT_DIR="/Volumes/${VOLUME_NAME}" + +# try unmount dmg if it was mounted previously (e.g. developer mounted dmg, installed app and forgot to unmount it) +echo "Unmounting disk image..." +DEV_NAME=$(hdiutil info | egrep '^/dev/' | sed 1q | awk '{print $1}') +test -d "${MOUNT_DIR}" && hdiutil detach "${DEV_NAME}" + +echo "Mount directory: $MOUNT_DIR" +DEV_NAME=$(hdiutil attach -readwrite -noverify -noautoopen "${DMG_TEMP_NAME}" | egrep '^/dev/' | sed 1q | awk '{print $1}') +echo "Device name: $DEV_NAME" + +if ! test -z "$BACKGROUND_FILE"; then + echo "Copying background file..." + test -d "$MOUNT_DIR/.background" || mkdir "$MOUNT_DIR/.background" + cp "$BACKGROUND_FILE" "$MOUNT_DIR/.background/$BACKGROUND_FILE_NAME" +fi + +if ! test -z "$APPLICATION_LINK"; then + echo "making link to Applications dir" + echo $MOUNT_DIR + ln -s /Applications "$MOUNT_DIR/Applications" +fi + +if ! test -z "$VOLUME_ICON_FILE"; then + echo "Copying volume icon file '$VOLUME_ICON_FILE'..." + cp "$VOLUME_ICON_FILE" "$MOUNT_DIR/.VolumeIcon.icns" + SetFile -c icnC "$MOUNT_DIR/.VolumeIcon.icns" +fi + +# run applescript +APPLESCRIPT=$(mktemp -t createdmg) +cat "$AUX_PATH/template.applescript" | sed -e "s/WINX/$WINX/g" -e "s/WINY/$WINY/g" -e "s/WINW/$WINW/g" -e "s/WINH/$WINH/g" -e "s/BACKGROUND_CLAUSE/$BACKGROUND_CLAUSE/g" -e "s/REPOSITION_HIDDEN_FILES_CLAUSE/$REPOSITION_HIDDEN_FILES_CLAUSE/g" -e "s/ICON_SIZE/$ICON_SIZE/g" -e "s/TEXT_SIZE/$TEXT_SIZE/g" | perl -pe "s/POSITION_CLAUSE/$POSITION_CLAUSE/g" | perl -pe "s/APPLICATION_CLAUSE/$APPLICATION_CLAUSE/g" | perl -pe "s/HIDING_CLAUSE/$HIDING_CLAUSE/" >"$APPLESCRIPT" + +echo "Running Applescript: /usr/bin/osascript \"${APPLESCRIPT}\" \"${VOLUME_NAME}\"" +"/usr/bin/osascript" "${APPLESCRIPT}" "${VOLUME_NAME}" || true +echo "Done running the applescript..." +sleep 4 + +rm "$APPLESCRIPT" + +# make sure it's not world writeable +echo "Fixing permissions..." +chmod -Rf go-w "${MOUNT_DIR}" &> /dev/null || true +echo "Done fixing permissions." + +# make the top window open itself on mount: +echo "Blessing started" +bless --folder "${MOUNT_DIR}" --openfolder "${MOUNT_DIR}" +echo "Blessing finished" + +if ! test -z "$VOLUME_ICON_FILE"; then + # tell the volume that it has a special file attribute + SetFile -a C "$MOUNT_DIR" +fi + +# unmount +echo "Unmounting disk image..." +hdiutil detach "${DEV_NAME}" + +# compress image +echo "Compressing disk image..." +hdiutil convert "${DMG_TEMP_NAME}" -format UDZO -imagekey zlib-level=9 -o "${DMG_DIR}/${DMG_NAME}" +rm -f "${DMG_TEMP_NAME}" + +# adding EULA resources +if [ ! -z "${EULA_RSRC}" -a "${EULA_RSRC}" != "-null-" ]; then + echo "adding EULA resources" + "${AUX_PATH}/dmg-license.py" "${DMG_DIR}/${DMG_NAME}" "${EULA_RSRC}" +fi + +if [ ! -z "${NOINTERNET}" -a "${NOINTERNET}" == 1 ]; then + echo "not setting 'internet-enable' on the dmg" +else + hdiutil internet-enable -yes "${DMG_DIR}/${DMG_NAME}" +fi + +echo "Disk image done" +exit 0 diff --git a/src/create-dmg/support/dmg-license.py b/src/create-dmg/support/dmg-license.py new file mode 100755 index 0000000000..9003a7c5e7 --- /dev/null +++ b/src/create-dmg/support/dmg-license.py @@ -0,0 +1,163 @@ +#! /usr/bin/env python +""" +This script adds a license file to a DMG. Requires Xcode and a plain ascii text +license file. +Obviously only runs on a Mac. + +Copyright (C) 2011-2013 Jared Hobbs + +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. +""" +import os +import sys +import tempfile +import optparse + + +class Path(str): + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + os.unlink(self) + + +def mktemp(dir=None, suffix=''): + (fd, filename) = tempfile.mkstemp(dir=dir, suffix=suffix) + os.close(fd) + return Path(filename) + + +def main(options, args): + dmgFile, license = args + with mktemp('.') as tmpFile: + with open(tmpFile, 'w') as f: + f.write("""data 'TMPL' (128, "LPic") { + $"1344 6566 6175 6C74 204C 616E 6775 6167" + $"6520 4944 4457 5244 0543 6F75 6E74 4F43" + $"4E54 042A 2A2A 2A4C 5354 430B 7379 7320" + $"6C61 6E67 2049 4444 5752 441E 6C6F 6361" + $"6C20 7265 7320 4944 2028 6F66 6673 6574" + $"2066 726F 6D20 3530 3030 4457 5244 1032" + $"2D62 7974 6520 6C61 6E67 7561 6765 3F44" + $"5752 4404 2A2A 2A2A 4C53 5445" +}; + +data 'LPic' (5000) { + $"0000 0002 0000 0000 0000 0000 0004 0000" +}; + +data 'STR#' (5000, "English buttons") { + $"0006 0D45 6E67 6C69 7368 2074 6573 7431" + $"0541 6772 6565 0844 6973 6167 7265 6505" + $"5072 696E 7407 5361 7665 2E2E 2E7A 4966" + $"2079 6F75 2061 6772 6565 2077 6974 6820" + $"7468 6520 7465 726D 7320 6F66 2074 6869" + $"7320 6C69 6365 6E73 652C 2063 6C69 636B" + $"2022 4167 7265 6522 2074 6F20 6163 6365" + $"7373 2074 6865 2073 6F66 7477 6172 652E" + $"2020 4966 2079 6F75 2064 6F20 6E6F 7420" + $"6167 7265 652C 2070 7265 7373 2022 4469" + $"7361 6772 6565 2E22" +}; + +data 'STR#' (5002, "English") { + $"0006 0745 6E67 6C69 7368 0541 6772 6565" + $"0844 6973 6167 7265 6505 5072 696E 7407" + $"5361 7665 2E2E 2E7B 4966 2079 6F75 2061" + $"6772 6565 2077 6974 6820 7468 6520 7465" + $"726D 7320 6F66 2074 6869 7320 6C69 6365" + $"6E73 652C 2070 7265 7373 2022 4167 7265" + $"6522 2074 6F20 696E 7374 616C 6C20 7468" + $"6520 736F 6674 7761 7265 2E20 2049 6620" + $"796F 7520 646F 206E 6F74 2061 6772 6565" + $"2C20 7072 6573 7320 2244 6973 6167 7265" + $"6522 2E" +};\n\n""") + with open(license, 'r') as l: + kind = 'RTF ' if license.lower().endswith('.rtf') else 'TEXT' + f.write('data \'%s\' (5000, "English") {\n' % kind) + def escape(s): + return s.strip().replace('\\', '\\\\').replace('"', '\\"') + + for line in l: + if len(line) < 1000: + f.write(' "' + escape(line) + '\\n"\n') + else: + for liner in line.split('.'): + f.write(' "' + escape(liner) + '. \\n"\n') + f.write('};\n\n') + f.write("""data 'styl' (5000, "English") { + $"0003 0000 0000 000C 0009 0014 0000 0000" + $"0000 0000 0000 0000 0027 000C 0009 0014" + $"0100 0000 0000 0000 0000 0000 002A 000C" + $"0009 0014 0000 0000 0000 0000 0000" +};\n""") + os.system('hdiutil unflatten -quiet "%s"' % dmgFile) + ret = os.system('%s -a %s -o "%s"' % + (options.rez, tmpFile, dmgFile)) + os.system('hdiutil flatten -quiet "%s"' % dmgFile) + if options.compression is not None: + os.system('cp %s %s.temp.dmg' % (dmgFile, dmgFile)) + os.remove(dmgFile) + if options.compression == "bz2": + os.system('hdiutil convert %s.temp.dmg -format UDBZ -o %s' % + (dmgFile, dmgFile)) + elif options.compression == "gz": + os.system('hdiutil convert %s.temp.dmg -format ' % dmgFile + + 'UDZO -imagekey zlib-devel=9 -o %s' % dmgFile) + os.remove('%s.temp.dmg' % dmgFile) + if ret == 0: + print "Successfully added license to '%s'" % dmgFile + else: + print "Failed to add license to '%s'" % dmgFile + +if __name__ == '__main__': + parser = optparse.OptionParser() + parser.set_usage("""%prog [OPTIONS] + This program adds a software license agreement to a DMG file. + It requires Xcode and either a plain ascii text + or a with the RTF contents. + + See --help for more details.""") + parser.add_option( + '--rez', + '-r', + action='store', + default='/Applications/Xcode.app/Contents/Developer/Tools/Rez', + help='The path to the Rez tool. Defaults to %default' + ) + parser.add_option( + '--compression', + '-c', + action='store', + choices=['bz2', 'gz'], + default=None, + help='Optionally compress dmg using specified compression type. ' + 'Choices are bz2 and gz.' + ) + options, args = parser.parse_args() + cond = len(args) != 2 + if not os.path.exists(options.rez): + print 'Failed to find Rez at "%s"!\n' % options.rez + cond = True + if cond: + parser.print_usage() + sys.exit(1) + main(options, args) diff --git a/src/create-dmg/support/template.applescript b/src/create-dmg/support/template.applescript new file mode 100644 index 0000000000..2a7f2aa0b6 --- /dev/null +++ b/src/create-dmg/support/template.applescript @@ -0,0 +1,79 @@ +on run (volumeName) + tell application "Finder" + tell disk (volumeName as string) + open + + set theXOrigin to WINX + set theYOrigin to WINY + set theWidth to WINW + set theHeight to WINH + + set theBottomRightX to (theXOrigin + theWidth) + set theBottomRightY to (theYOrigin + theHeight) + set dsStore to "\"" & "/Volumes/" & volumeName & "/" & ".DS_STORE\"" + + tell container window + set current view to icon view + set toolbar visible to false + set statusbar visible to false + set the bounds to {theXOrigin, theYOrigin, theBottomRightX, theBottomRightY} + set statusbar visible to false + REPOSITION_HIDDEN_FILES_CLAUSE + end tell + + set opts to the icon view options of container window + tell opts + set icon size to ICON_SIZE + set text size to TEXT_SIZE + set arrangement to not arranged + end tell + BACKGROUND_CLAUSE + + -- Positioning + POSITION_CLAUSE + + -- Hiding + HIDING_CLAUSE + + -- Application Link Clause + APPLICATION_CLAUSE + close + open + + update without registering applications + -- Force saving of the size + delay 1 + + tell container window + set statusbar visible to false + set the bounds to {theXOrigin, theYOrigin, theBottomRightX - 10, theBottomRightY - 10} + end tell + + update without registering applications + end tell + + delay 1 + + tell disk (volumeName as string) + tell container window + set statusbar visible to false + set the bounds to {theXOrigin, theYOrigin, theBottomRightX, theBottomRightY} + end tell + + update without registering applications + end tell + + --give the finder some time to write the .DS_Store file + delay 3 + + set waitTime to 0 + set ejectMe to false + repeat while ejectMe is false + delay 1 + set waitTime to waitTime + 1 + + if (do shell script "[ -f " & dsStore & " ]; echo $?") = "0" then set ejectMe to true + end repeat + log "waited " & waitTime & " seconds for .DS_STORE to be created." + end tell +end run