Tuesday, 3 August 2010

Eulagise: Adding a EULA to a DMG

My code projects usually include a release script, a shell script that does something like this:
  • cleans the build tree,
  • rebuilds the project,
  • runs the unit tests (stopping if they fail), and
  • packages the project.
It's that last step I'm concerned with here. On Mac OS packaging usually involves building a DMG disk image. Automatically creating a DMG isn't entirely straightforward in a shell script. In fact, it's not straightforward at all. It took me a while to master the process; I bastardised and tweaked part of the Audium build process to perform this feat of engineering.

A recent requirement was to add a EULA to the DMG. If you're a Mac user then you've probably seen them once or twice. They look something like this (this isn't my one, for client confidentiality purposes).

The EULA appears when you double-click the DMG file, if you agree to the EULA then the disk image opens. If you don't agree, then, well you can work out the rest.

Something so simple, and so standard, must be easy to add. Right?

I hate to spoil a good story, but it's a bit tricky. Don't worry, the story has a happy ending.

It's not an easy task because:
  • The EULA has to be in a very particular format.
  • The EULA has to be added to the resource fork of the DMG.
  • You can only add resources (i.e. the EULA) to an unflattened DMG object, use the Rez utility to add resources, and re-flatten the DMG.
  • There are no clear and easy docs on the subject. (That I could find.)
Of course, being a script we want this to be automated, rather than a clicky-draggy process. There are programs that'll do clicky-draggy. We have to rule those out.

Ideally we want a script that takes a text file as input and the DMG to attach it to. Magic invisible elves inside the script do the rest.

I spent some time writing my own script, hitting a number of obstacles each time around, and then research pointed me towards the Seamonkey build system. Seamonkey has a script here that can do it. Hurrah! The script also creates the DMG in the first place, setting icons, volume name, etc. Sounds great, except that it does all the other stuff rather badly. Or at least, less well than the script I already created.

So I removed all the other cruft, and paired Seamonkey's script down into eulagise. Eulagise is a simple (ish) script to add a EULA to a pre-existing DMG. You use it like this:
./eulagise.pl --license MyEula.txt --target MyDiskImage.dmg

You can get the script on gitorious here. I hope to neaten it up, and remove all the extraneous cruft shortly.


karn9872 said...

After a long time searching the net for a solution this was the only thing that I could find that worked. Thank you very much. I'm using the yoursway-create-dmg- script to build and then I have injected your script to create the EULA. Thanks again!

Stephane Perras said...

Hello, your solution looks very interesting as I have just tried it. However it produces an error:

/Developer/Tools/Rez -F Carbon Carbon.r ../DMG/pkg-dmg.2761.OuhvYHYb/license.r -a -o ../DMG/Setup.dmg
failed to find Carbon/Carbon.r
### /Developer/Tools/Rez - SysError 0 during open of "Carbon.r".
Fatal Error!
### /Developer/Tools/Rez - Fatal Error, can't recover.
Carbon.r: ### /Developer/Tools/Rez - Since errors occurred, ../DMG/Setup.dmg's resource fork was not completely updated.
Carbon.r: ### /Developer/Tools/Rez - SysError -43 during set file info.
./eulagise.pl: Rez failed (cleaning up)

I am a seasoned Windows programmer, but fairly new to OSX development, can you help me with what is going wrong here?

OSX 10.6.8, XCode 3.2.6 (64 bits)

Thank you!