aa82588d60e61403f537ad105b175b7f085940f0
[sface.git] / macos / build-dmg.sh
1 #!/bin/sh
2
3 # PURPOSE
4 # package a combination of sfa+sface into a dmg install disk
5 # supports leopard and snow leopard
6
7 # REQUIREMENTS
8 # sface-skel-snow-leopard<arch>.dmg is the skeleton that has Qt and all the other third-party software
9 #   it is expected to be found in the local directory
10 #   otherwise, or if -f is specified, it gets fetched 
11 #     from http://mirror.onelab.eu/third-party/ 
12 # the script expects the taglevels for both sfa and sface, 
13 #   in order to retrieve the corresponding code and to label the resulting package properly
14 #   alternatively, a build-dir and tags file can be used instead
15 # Should have the folowing tools installed
16 #   git: to retrieve code
17 #   rpm: to retrieve the version numbers in specfiles
18
19 # NOTES
20 # we initially leveraged the first similar packaging initially made by Baris Metin
21 # as of sface-0.1-9 we have bootstrapped our own skeleton images, 
22 #   i.e. you can use vn as a skeleton for vn+1
23 # about that, the way the background image gets (or not) found 
24 #   on the final system is as follows 
25 #   before compressing the image, you should open the image through the finder
26 #   and tweak it, as described in http://el-tramo.be/guides/fancy-dmg
27 #   that's the raison d'ĂȘtre for the -i option
28 # basically: open two finder windows, one on the .backgrounf dir (use cmd-shift G)
29 #   and one on the image itself; then using Finder->view->show view options
30 #   drag the background image as appropriate
31 # the important point being that the filename for the background must 
32 #   exist - and so be the same - on the target system.
33 # that's why the image 'volname' is constant across versions
34
35 # the place to search for the  skeleton
36 SKEL_REPO=http://mirror.onelab.eu/third-party
37
38 # default is snow-leopard
39 DEFAULT_ARCH=snow-leopard
40 ALL_ARCHS="leopard snow-leopard"
41
42 # does not affect final dmg size as it's compressed
43 DISK_SIZE=100M
44
45 ########################################
46 COMMAND=$(basename $0)
47
48 # extract the tag part of a GITPATH
49 function git_url () { echo $1 | cut -d @ -f 1 ; }
50 function git_tag () { echo $1 | cut -d @ -f 2 ; }
51
52 # go in $dest and retrieve module into provided path
53 # git_retrieve git://git.onelab.eu/sface.git@sface-0.1-5 /tmp/sfa-module
54 function git_retrieve () {
55     gitpath="$1"; shift
56     dest="$1"; shift
57
58     giturl=$(git_url $gitpath)
59     gittag=$(git_tag $gitpath)
60     [ -d "$dest" ] || mkdir -p "$dest"
61     pushd "$dest" >& /dev/null
62     git archive --remote=${giturl} ${gittag} | tar -xf - 
63     popd >& /dev/null
64 }
65
66 function die () {
67     echo "$@" "- exiting" 
68     exit 1
69 }
70
71 function package () {
72     
73     sface_GITPATH=$1; shift
74     sfa_GITPATH=$1; shift
75     arch=$1; shift
76
77     skel_name=sface-skel-${arch}
78     skel_dmg=./${skel_name}.dmg
79     skel_mnt="/Volumes/${skel_name}"
80
81     sfa_release=sfa-$(git_tag $sfa_GITPATH | sed -e s,sfa-,,)
82     sface_release=sface-$(git_tag $sface_GITPATH | sed -e s,sface-,,)
83     release=$(git_tag $sfa_GITPATH)-$(git_tag $sface_GITPATH)
84
85     img_name=${sface_release}-${sfa_release}-${arch}
86     img_dmg=./${img_name}.dmg
87     img_raw_dmg=./${img_name}.raw.dmg
88     img_mnt_name="sface ($arch)"
89     img_mnt="/Volumes/${img_mnt_name}"
90
91     # check we're clear
92     if [ -f $img_dmg ] ; then
93         [ -z "$FORCE_REWRITE" ] && die "output dmg $img_dmg already exists"
94         echo "Trashing (force_rewrite) former output $img_dmg"
95         rm -f $img_dmg
96     fi
97     if [ -f $img_raw_dmg ] ; then
98         [ -z "$FORCE_REWRITE" ] && die "please clean up tmp file $img_raw_dmg"
99         echo "Cleaning (force_rewrite) former tmp file $img_raw_dmg"
100         rm -f $img_raw_dmg
101     fi
102
103     if [ -n "$FORCE_DOWNLOAD" ] ; then
104         [ -d "$skel_mnt" ] && hdiutil unmount "$skel_mnt"
105         [ -f "$skel_dmg" ] && rm -f "$skel_dmg"
106     fi
107
108     # mount the skeleton if not yet avail.
109     if [ ! -d "$skel_mnt" ] ; then
110         # locate skel dmg
111         if [ ! -f $skel_dmg ] ; then
112             echo "Retrieving $skel_dmg from $SKEL_REPO"
113             curl -O $SKEL_REPO/$skel_dmg
114         fi
115         # needless to check for existence as curl will have created on anyway
116         echo "Mounting skeleton"
117         if ! hdiutil mount -quiet -mountpoint $skel_mnt $skel_dmg ; then
118             die "Could not mount $skel_dmg
119 Please check it is published at $SKEL_REPO
120 Also make sure to trash the current one before retrying"
121         fi
122     fi
123     [ -d "$skel_mnt" ] || die "Could not mount skeleton $skel_dmg"
124
125     # if image already mounted, it's an old run
126     [ -d "$img_mnt" ] && die "Image already mounted on $img_mnt"
127
128     echo "Initializing image ..."
129     hdiutil create -quiet -size $DISK_SIZE -fs HFS -volname "${img_mnt_name}" $img_raw_dmg 
130     hdiutil attach -readwrite -mount required "$img_raw_dmg"
131     
132     # copy skeleton as-is
133     echo "Populating from  skeleton.."
134     ( cd "$skel_mnt" ; find . 2> /dev/null | cpio --quiet -c -o) | ( cd "$img_mnt" ; cpio -diu )
135
136     # places relative to mount point
137     app=sface.app
138     # xxx tmp
139     skelapp_path=$(ls -d "$skel_mnt"/*.app)
140     skelapp=$(basename "$skelapp_path")
141     if [ "$skelapp" != "$app" ] ; then
142         mv "$img_mnt/$skelapp" "$img_mnt/$app"
143     fi
144     # unmount the skeleton
145     hdiutil unmount "$skel_mnt"
146
147     # 
148     resource_path=$app/Contents/Resources
149     bin_path=$app/Contents/MacOS
150
151     # retrieve sfa and sface full repos in a temp dir
152     temp=$(mktemp -d -t sface-dmg)
153
154     git_retrieve $sfa_GITPATH $temp/sfa
155     git_retrieve $sface_GITPATH $temp/sface
156
157     # retrieve version number, and run make version
158     sfa_spec=$temp/sfa/sfa.spec
159     # use newlines and keep only the first line, for multiple packages
160     sfa_version=$(rpm -q --specfile $sfa_spec --qf '%{version}\n' | head -1)
161     # cannot extract taglevel, issues lots of 'error: incorrect format: unknown tag'
162     # turns out release is the same in our case as we haven't computed header.spec
163     sfa_release=$(rpm -q --specfile $sfa_spec --qf '%{release}\n' | head -1 | cut -d. -f1)
164     sfa_tag=${sfa_version}-${sfa_release}
165     make -C $temp/sfa VERSIONTAG="${sfa_tag}" SCMURL="${sfa_GITPATH}" version
166
167     sface_spec=$temp/sface/sface.spec
168     sface_version=$(rpm -q --specfile $sface_spec --qf '%{version}\n' | head -1)
169     sface_release=$(rpm -q --specfile $sface_spec --qf '%{release}\n' | head -1 | cut -d. -f1)
170     sface_tag=${sface_version}-${sface_release}
171     make -C $temp/sface VERSIONTAG="${sface_tag}" SCMURL="${sface_GITPATH}" version
172
173     # copy sfa/ and sface/ subdirs in image
174     rm -rf "$img_mnt"/$resource_path/{sfa,sface}
175     tar -C $temp/sfa -cf - sfa | tar -C "$img_mnt"/$resource_path/ -xf -
176     tar -C $temp/sface -cf - sface | tar -C "$img_mnt"/$resource_path/ -xf -
177
178     # copy binaries from sface to the bin dir
179     for bin in sface.bin sface-run; do 
180         cp $temp/sface/$bin "$img_mnt"/$bin_path
181     done
182
183     ### install background and app icons
184     # clean up any 'background' dir if exists
185     rm -rf "$img_mnt"/{,.}background 
186     mkdir -p "$img_mnt"/.background "$img_mnt"/$resource_path/sface/images
187     cp $temp/sface/macos/graphic-install-background.png "$img_mnt"/.background/background.png
188     cp $temp/sface/macos/graphic-sfa.icns "$img_mnt"/$resource_path/appIcon.icns
189     cp $temp/sface/macos/graphic-sfa.png "$img_mnt"/$resource_path/sface/images
190     # the volume icons won't work - who cares
191 #    cp $temp/sface/macos/graphic-vol-sface.icns "$img_mnt"/.background/volumeIcon.icns
192 #    cp $temp/sface/macos/graphic-vol-sface.png "$img_mnt"/.background/volumeIcon.png
193
194     # clean up just in case
195     find "$img_mnt" -name '*pyc' | xargs rm -f
196     find "$img_mnt" -name '*~' | xargs rm -f
197
198     if [ -n "$INTERACTIVE" ] ; then
199         echo "Please tweak icons layout in $img_mnt under Finder, and press enter when done ..."
200         read _
201     fi
202
203     rm -rf $temp 
204
205     hdiutil detach "$img_mnt"
206     rm -f $img_dmg
207     echo "Compressing..."
208     hdiutil convert -quiet -format UDZO -imagekey zlib-level=9 -o $img_dmg $img_raw_dmg 
209     # clean up the raw image
210     rm -f $img_raw_dmg
211
212     echo "=================================================="
213     echo "Install image ready in $img_dmg"
214     echo "You may publish it by running e.g."
215     echo "rsync -av $img_dmg root@build.onelab.eu:/build/sface"
216     echo "=================================================="
217
218 }
219
220 ########################################
221 # either provide a build dir and tags file
222 # or sface-GITPATH sfa-GITPATH 
223 function usage () {
224     echo "$COMMAND -b <build-dir> -t <tags-file>"
225     echo " or"
226     echo "$COMMAND -c <sface-GITPATH> -s <sfa-GITPATH>"
227     echo ""
228     echo "Common options"
229     echo " -i : interactive : let you align icons properly in the image before it gets wrapped"
230     echo " -f : force download of the skeleton package"
231     echo " -F : force overwrite if output already exists"
232     echo " -a leopard|snow-leopard"
233     echo " -A : run on all known archs"
234     echo " -n : dry-run"
235     echo " -v : verbose"
236     echo " -h : this help"
237 }
238
239 DEFAULT_BUILD_DIR=$HOME/git/build
240 DEFAULT_TAGS_FILE=onelab-k32-tags.mk
241
242 function main () {
243     while getopts "b:t:c:s:ifFa:Anvh" opt ; do
244         case $opt in 
245             b) BUILD_DIR=$OPTARG;;
246             t) TAGS_FILE=$OPTARG;;
247             c) sface_GITPATH=$OPTARG;;
248             s) sfa_GITPATH=$OPTARG;;
249             i) INTERACTIVE=true;;
250             f) FORCE_DOWNLOAD=true;;
251             F) FORCE_REWRITE=true ;;
252             a) ARCHS="$ARCHS $OPTARG";;
253             A) ARCHS="leopard snow-leopard";;
254             n) dry_run=true;;
255             v) set -x;;
256             h) usage; exit 1 ;;
257         esac
258     done
259     shift $(($OPTIND - 1))
260
261     [ -z "$BUILD_DIR" ] && BUILD_DIR=$DEFAULT_BUILD_DIR
262     [ -z "$TAGS_FILE" ] && TAGS_FILE=$DEFAULT_TAGS_FILE
263     [ -z "$ARCHS" ] && ARCHS=$DEFAULT_ARCH
264     [[ -n "$@" ]] && { usage ; exit 1; }
265     if [ -z "$sface_GITPATH" ] ; then
266         sface_GITPATH=$(make -C $BUILD_DIR stage1=true PLDISTROTAGS=$TAGS_FILE +sface-GITPATH 2> /dev/null)
267         echo "Retrieved from $BUILD_DIR/$TAGS_FILE.."
268         echo " sface_GITPATH=$sface_GITPATH"
269     fi
270     if [ -z "$sfa_GITPATH" ] ; then
271         sfa_GITPATH=$(make -C $BUILD_DIR stage1=true PLDISTROTAGS=$TAGS_FILE +sfa-GITPATH 2> /dev/null)
272         echo "Retrieved from $BUILD_DIR/$TAGS_FILE.."
273         echo " sfa_GITPATH=$sfa_GITPATH"
274     fi
275     for ARCH in $ARCHS; do 
276         if [ -z "$dry_run" ] ; then
277             package $sface_GITPATH $sfa_GITPATH $ARCH
278         else
279             echo "Would run package $sface_GITPATH $sfa_GITPATH $ARCH"
280         fi
281     done
282         
283 }
284
285 main "$@"