|
| 1 | +#! /bin/bash |
| 2 | + |
| 3 | +# Create a read-only disk image of the contents of a folder |
| 4 | + |
| 5 | +set -e; |
| 6 | + |
| 7 | +function pure_version() { |
| 8 | + echo '1.0.0.2' |
| 9 | +} |
| 10 | + |
| 11 | +function version() { |
| 12 | + echo "create-dmg $(pure_version)" |
| 13 | +} |
| 14 | + |
| 15 | +function usage() { |
| 16 | + version |
| 17 | + echo "Creates a fancy DMG file." |
| 18 | + echo "Usage: $(basename $0) options... image.dmg source_folder" |
| 19 | + echo "All contents of source_folder will be copied into the disk image." |
| 20 | + echo "Options:" |
| 21 | + echo " --volname name" |
| 22 | + echo " set volume name (displayed in the Finder sidebar and window title)" |
| 23 | + echo " --volicon icon.icns" |
| 24 | + echo " set volume icon" |
| 25 | + echo " --background pic.png" |
| 26 | + echo " set folder background image (provide png, gif, jpg)" |
| 27 | + echo " --window-pos x y" |
| 28 | + echo " set position the folder window" |
| 29 | + echo " --window-size width height" |
| 30 | + echo " set size of the folder window" |
| 31 | + echo " --text-size text_size" |
| 32 | + echo " set window text size (10-16)" |
| 33 | + echo " --icon-size icon_size" |
| 34 | + echo " set window icons size (up to 128)" |
| 35 | + echo " --icon file_name x y" |
| 36 | + echo " set position of the file's icon" |
| 37 | + echo " --hide-extension file_name" |
| 38 | + echo " hide the extension of file" |
| 39 | + echo " --custom-icon file_name custom_icon_or_sample_file x y" |
| 40 | + echo " set position and custom icon" |
| 41 | + echo " --app-drop-link x y" |
| 42 | + echo " make a drop link to Applications, at location x,y" |
| 43 | + echo " --eula eula_file" |
| 44 | + echo " attach a license file to the dmg" |
| 45 | + echo " --no-internet-enable" |
| 46 | + echo " disable automatic mount©" |
| 47 | + echo " --version show tool version number" |
| 48 | + echo " -h, --help display this help" |
| 49 | + exit 0 |
| 50 | +} |
| 51 | + |
| 52 | +WINX=10 |
| 53 | +WINY=60 |
| 54 | +WINW=500 |
| 55 | +WINH=350 |
| 56 | +ICON_SIZE=128 |
| 57 | +TEXT_SIZE=16 |
| 58 | + |
| 59 | +while test "${1:0:1}" = "-"; do |
| 60 | + case $1 in |
| 61 | + --volname) |
| 62 | + VOLUME_NAME="$2" |
| 63 | + shift; shift;; |
| 64 | + --volicon) |
| 65 | + VOLUME_ICON_FILE="$2" |
| 66 | + shift; shift;; |
| 67 | + --background) |
| 68 | + BACKGROUND_FILE="$2" |
| 69 | + BACKGROUND_FILE_NAME="$(basename $BACKGROUND_FILE)" |
| 70 | + BACKGROUND_CLAUSE="set background picture of opts to file \".background:$BACKGROUND_FILE_NAME\"" |
| 71 | + REPOSITION_HIDDEN_FILES_CLAUSE="set position of every item to {theBottomRightX + 100, 100}" |
| 72 | + shift; shift;; |
| 73 | + --icon-size) |
| 74 | + ICON_SIZE="$2" |
| 75 | + shift; shift;; |
| 76 | + --text-size) |
| 77 | + TEXT_SIZE="$2" |
| 78 | + shift; shift;; |
| 79 | + --window-pos) |
| 80 | + WINX=$2; WINY=$3 |
| 81 | + shift; shift; shift;; |
| 82 | + --window-size) |
| 83 | + WINW=$2; WINH=$3 |
| 84 | + shift; shift; shift;; |
| 85 | + --icon) |
| 86 | + POSITION_CLAUSE="${POSITION_CLAUSE}set position of item \"$2\" to {$3, $4} |
| 87 | +" |
| 88 | + shift; shift; shift; shift;; |
| 89 | + --hide-extension) |
| 90 | + HIDING_CLAUSE="${HIDING_CLAUSE}set the extension hidden of item \"$2\" to true |
| 91 | +" |
| 92 | + shift; shift;; |
| 93 | + --custom-icon) |
| 94 | + shift; shift; shift; shift; shift;; |
| 95 | + -h | --help) |
| 96 | + usage;; |
| 97 | + --version) |
| 98 | + version; exit 0;; |
| 99 | + --pure-version) |
| 100 | + pure_version; exit 0;; |
| 101 | + --app-drop-link) |
| 102 | + APPLICATION_LINK=$2 |
| 103 | + APPLICATION_CLAUSE="set position of item \"Applications\" to {$2, $3} |
| 104 | +" |
| 105 | + shift; shift; shift;; |
| 106 | + --eula) |
| 107 | + EULA_RSRC=$2 |
| 108 | + shift; shift;; |
| 109 | + --no-internet-enable) |
| 110 | + NOINTERNET=1 |
| 111 | + shift;; |
| 112 | + -*) |
| 113 | + echo "Unknown option $1. Run with --help for help." |
| 114 | + exit 1;; |
| 115 | + esac |
| 116 | +done |
| 117 | + |
| 118 | +test -z "$2" && { |
| 119 | + echo "Not enough arguments. Invoke with --help for help." |
| 120 | + exit 1 |
| 121 | +} |
| 122 | + |
| 123 | +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
| 124 | +DMG_PATH="$1" |
| 125 | +DMG_DIRNAME="$(dirname "$DMG_PATH")" |
| 126 | +DMG_DIR="$(cd "$DMG_DIRNAME" > /dev/null; pwd)" |
| 127 | +DMG_NAME="$(basename "$DMG_PATH")" |
| 128 | +DMG_TEMP_NAME="$DMG_DIR/rw.${DMG_NAME}" |
| 129 | +SRC_FOLDER="$(cd "$2" > /dev/null; pwd)" |
| 130 | +test -z "$VOLUME_NAME" && VOLUME_NAME="$(basename "$DMG_PATH" .dmg)" |
| 131 | + |
| 132 | +AUX_PATH="$SCRIPT_DIR/support" |
| 133 | + |
| 134 | +test -d "$AUX_PATH" || { |
| 135 | + echo "Cannot find support directory: $AUX_PATH" |
| 136 | + exit 1 |
| 137 | +} |
| 138 | + |
| 139 | +if [ -f "$SRC_FOLDER/.DS_Store" ]; then |
| 140 | + echo "Deleting any .DS_Store in source folder" |
| 141 | + rm "$SRC_FOLDER/.DS_Store" |
| 142 | +fi |
| 143 | + |
| 144 | +# Create the image |
| 145 | +echo "Creating disk image..." |
| 146 | +test -f "${DMG_TEMP_NAME}" && rm -f "${DMG_TEMP_NAME}" |
| 147 | +ACTUAL_SIZE=`du -sm "$SRC_FOLDER" | sed -e 's/ .*//g'` |
| 148 | +DISK_IMAGE_SIZE=$(expr $ACTUAL_SIZE + 20) |
| 149 | +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}" |
| 150 | + |
| 151 | +# mount it |
| 152 | +echo "Mounting disk image..." |
| 153 | +MOUNT_DIR="/Volumes/${VOLUME_NAME}" |
| 154 | + |
| 155 | +# try unmount dmg if it was mounted previously (e.g. developer mounted dmg, installed app and forgot to unmount it) |
| 156 | +echo "Unmounting disk image..." |
| 157 | +DEV_NAME=$(hdiutil info | egrep '^/dev/' | sed 1q | awk '{print $1}') |
| 158 | +test -d "${MOUNT_DIR}" && hdiutil detach "${DEV_NAME}" |
| 159 | + |
| 160 | +echo "Mount directory: $MOUNT_DIR" |
| 161 | +DEV_NAME=$(hdiutil attach -readwrite -noverify -noautoopen "${DMG_TEMP_NAME}" | egrep '^/dev/' | sed 1q | awk '{print $1}') |
| 162 | +echo "Device name: $DEV_NAME" |
| 163 | + |
| 164 | +if ! test -z "$BACKGROUND_FILE"; then |
| 165 | + echo "Copying background file..." |
| 166 | + test -d "$MOUNT_DIR/.background" || mkdir "$MOUNT_DIR/.background" |
| 167 | + cp "$BACKGROUND_FILE" "$MOUNT_DIR/.background/$BACKGROUND_FILE_NAME" |
| 168 | +fi |
| 169 | + |
| 170 | +if ! test -z "$APPLICATION_LINK"; then |
| 171 | + echo "making link to Applications dir" |
| 172 | + echo $MOUNT_DIR |
| 173 | + ln -s /Applications "$MOUNT_DIR/Applications" |
| 174 | +fi |
| 175 | + |
| 176 | +if ! test -z "$VOLUME_ICON_FILE"; then |
| 177 | + echo "Copying volume icon file '$VOLUME_ICON_FILE'..." |
| 178 | + cp "$VOLUME_ICON_FILE" "$MOUNT_DIR/.VolumeIcon.icns" |
| 179 | + SetFile -c icnC "$MOUNT_DIR/.VolumeIcon.icns" |
| 180 | +fi |
| 181 | + |
| 182 | +# run applescript |
| 183 | +APPLESCRIPT=$(mktemp -t createdmg) |
| 184 | +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" |
| 185 | + |
| 186 | +echo "Running Applescript: /usr/bin/osascript \"${APPLESCRIPT}\" \"${VOLUME_NAME}\"" |
| 187 | +"/usr/bin/osascript" "${APPLESCRIPT}" "${VOLUME_NAME}" || true |
| 188 | +echo "Done running the applescript..." |
| 189 | +sleep 4 |
| 190 | + |
| 191 | +rm "$APPLESCRIPT" |
| 192 | + |
| 193 | +# make sure it's not world writeable |
| 194 | +echo "Fixing permissions..." |
| 195 | +chmod -Rf go-w "${MOUNT_DIR}" &> /dev/null || true |
| 196 | +echo "Done fixing permissions." |
| 197 | + |
| 198 | +# make the top window open itself on mount: |
| 199 | +echo "Blessing started" |
| 200 | +bless --folder "${MOUNT_DIR}" --openfolder "${MOUNT_DIR}" |
| 201 | +echo "Blessing finished" |
| 202 | + |
| 203 | +if ! test -z "$VOLUME_ICON_FILE"; then |
| 204 | + # tell the volume that it has a special file attribute |
| 205 | + SetFile -a C "$MOUNT_DIR" |
| 206 | +fi |
| 207 | + |
| 208 | +# unmount |
| 209 | +echo "Unmounting disk image..." |
| 210 | +hdiutil detach "${DEV_NAME}" |
| 211 | + |
| 212 | +# compress image |
| 213 | +echo "Compressing disk image..." |
| 214 | +hdiutil convert "${DMG_TEMP_NAME}" -format UDZO -imagekey zlib-level=9 -o "${DMG_DIR}/${DMG_NAME}" |
| 215 | +rm -f "${DMG_TEMP_NAME}" |
| 216 | + |
| 217 | +# adding EULA resources |
| 218 | +if [ ! -z "${EULA_RSRC}" -a "${EULA_RSRC}" != "-null-" ]; then |
| 219 | + echo "adding EULA resources" |
| 220 | + "${AUX_PATH}/dmg-license.py" "${DMG_DIR}/${DMG_NAME}" "${EULA_RSRC}" |
| 221 | +fi |
| 222 | + |
| 223 | +if [ ! -z "${NOINTERNET}" -a "${NOINTERNET}" == 1 ]; then |
| 224 | + echo "not setting 'internet-enable' on the dmg" |
| 225 | +else |
| 226 | + hdiutil internet-enable -yes "${DMG_DIR}/${DMG_NAME}" |
| 227 | +fi |
| 228 | + |
| 229 | +echo "Disk image done" |
| 230 | +exit 0 |
0 commit comments