Rake DMG library Build Status Gem Version

DmgTask is a Rake library which aims to ease the building of DMG files for projects, applications and whatever you throw at it.

Basic usage

Firse, install it with:

$ sudo gem install rake_dmg

Then, write something like the following code in a Rakefile:

require 'rake/dmg'

Rake::DmgTask.new 'pimpernel', '0.1.2' do |dmg|
  dmg.source_files.include 'build/**/*'
  dmg.source_files.exclude 'pkg'
  dmg.strip = 'build'
  dmg.extra_source_files = {'resources/ds_store' => '/.DS_Store',
    'resources/background.png' => '/.background/background.png',
    'doc/quickstart.pdf' => 'guide.pdf'}
end

You can:

The last point means you are able to customize the DMG adding documentation, licence file, background images, etc.

Motivations

Building a DMG is rather simple and every library/framework probably has some mechanism to automate the process. For example, RubyCocoa projects and Rucola-based projects (and HotCocoa ones, maybe?) provides Rake tasks like the following ones:

# RubyCocoa
desc "Package the application"
task :package => ["xcode:build:#{DEFAULT_TARGET}:#{RELEASE_CONFIGURATION}", "pkg"] do
  name = "#{APPNAME}.#{APPVERSION}"
  mkdir "image"
  sh %{rubycocoa standaloneify "build/#{DEFAULT_CONFIGURATION}/#{APPNAME}.app" "image/#{APPNAME}.app"}
  puts 'Creating Image...'
  sh %{
  hdiutil create -volname '#{name}' -srcfolder image '#{name}'.dmg
  rm -rf image
  mv '#{name}.dmg' pkg
  }
end

# Rucola
desc "Package the application as a disk image"
task :package => :pkg do
  FileUtils.rm(PKG) if File.exist?(PKG)
  puts 'Creating Image...'
  sh "hdiutil create -volname '#{DEPLOY_NAME}' -srcfolder 'build/Release/#{TARGET}' '#{PKG}'"
  puts ''
end

Both works flowlessly but you cannot customize the final DMG file. Using Rake 0.8.2 or later and this library we can change the situation:

# RubyCocoa
Rake::Task[:package].clear_actions
task :package => :dmg
Rake::DmgTask.new APPNAME, APPVERSION do |p|
  p.source_files.include "build/#{DEFAULT_CONFIGURATION}/#{APPNAME}.app/**/*"
  p.strip = "build/#{DEFAULT_CONFIGURATION}"
  p.extra_source_files = {'extra/LICENCE.rtf' => 'LICENCE.rtf'}
end

# Rucola
Rake::Task['deploy:package'].clear_actions
namespace :deploy do
  task :package => :dmg
  Rake::DmgTask.new APPNAME, APPVERSION do |p|
    p.source_files.include "build/Release/#{TARGET}/**/*"
    p.strip = 'build/Release'
    p.extra_source_files = {'extra/LICENCE.rtf' => 'LICENCE.rtf'}
  end
end

Some notes about basic DMG building

The simplest way to programmatically create the smallest DMG file is:

hdiutil create -srcdir <source directory> \
  -volname <volume name> \
  -uid 99 -gid 99 \
  <image name>

This command create a zlib-compressed DMG file (UDZO format) using the same filesystem of <source directory>, if possibile. The final image file is the smallest one able to contain all the content of <source directory>.

The user and group id values (99 and 99, respectively) map to the “magic” unknown user and group which, if I understand the system documentation correctly, should be “replaced” at mount time by the disk arbitration with the user who mount the DMG.

why the lucky stiff, author of Shoes, uses a rather complex, automatic build system written in Ruby, based on Rake with a Perl script called pkg-dmg which handles all the details of DMG creation; this wonderful script is complex and makes provision for backward compatibility (which this library does not). why uses it in the following way:

pkg-dmg --target pkg/#{PKG}.dmg --source dmg --volname '#{APPNAME}' \
  --copy platform/mac/dmg_ds_store:/.DS_Store --mkdir /.background \
  --copy static/shoes-dmg.jpg:/.background

Here the application to package is inside the dmg directory. The first --copy puts a handmade ds_store file into the directory used to build the final DMG file; this seems to be the only way to customize DMG’s look. The last --copy puts the image used as background, referenced by the custom ds_store file.