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