Rake DMG library <img src=“https://travis-ci.org/baldowl/rake_dmg.png?branch=master” alt=“Build Status” /> <img src=“https://badge.fury.io/rb/rake_dmg.png” alt=“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:

  • specify name and optional version string for the DMG file;

  • specify files to be included using Rake’s really flexible FileList;

  • specify extra files to be added to the final DMG file.

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.