« August 2006 | Main | October 2006 »
September 28, 2006
Bumped from C4
So I had told a few people I was presenting at C4, Wolf's get together next month. I was going to do a presentation on how to organize things around development, and use Trac in a lot of examples.
Unfortunately I've just been bumped from the playlist by whatever snazzy stuff is going on here..
Fear not, I'll still be attending. Or maybe you should fear. Either way, I'll be there.
Posted by Chris Forsythe at 06:27 PM | Comments (0)
DMG creation tips and tricks
Warning: This post is longer than my usual. You may want coffee. The focus of this post is how to make a DMG image with a background in an automated fashion.
About DMG
For those who are reading this who are not aware of it, DMG (Disk Image) is the format commonly used to distribute software on OS X. There are other formats, the more traditional like tar.gz/zip/.sit. For more information specifically about how to distribute software as a DMG, you'll want to read Peter Hosey's how to distribute your software (and his semi-in-depth overview of compression format usage on OS X).
Motivation/History
Quite a while back Adium and Growl both were shipped in dmgs created in a product called FileStorm. At the time, it was buggy and hard to use. It would crash a lot, and in the end was just a pain in the butt.
But we used it anyhow. For a while.
However, it's not automated. It also required that everyone have Filestorm installed and licensed, so for instance only one person could make the dmg on the Growl team (I had the Adium license file), and only one or two on the Adium team could use it.
Everyone jokes about replacing random things with a small shell script, but we pretty much did that. Except this uses Makefiles, Shell, and AppleScript.
So, before I begin writing about how to do this, I would like to state the process before and after the creation of this build system in order to release Growl.
This is the before:
- Change directories into the growlsourceco
- svn up to ensure there are no new changes
- Open Xcode and edit version numbers OR edit version numbers without opening Xcode
- Build Growl
- Open the GrowlTunes Project and build it
- Open the GrowlMail Project and build it
- Open the Beep-Cocoa Project and build it
- Open the Beep-Carbon Project and build it
- Open the GrowlDict Project and build it
- Open the growlnotify Project and build it
- Once Growl and the Extras are built, open Filestorm
- Go into Filestorm and ensure the paths are correct in the dmg project
- Make the dmg
- Test the dmg and upload
This is the process when making a dmg with the build system that was created:
- Change directories into the growlsourceco
- Open Xcode and edit version numbers OR edit version numbers without opening Xcode
- cd Release
- type make
- Test the dmg and upload
There's actually a lot more to the process we used when we used Filestorm, but as I felt that more bullet points would only lead to excessiveness. And besides, you get the point.
Anyhow, on to the nitty gritty. This is how to make your very own DMG Creation System. I am going to run down how the Growl system works, since it is more complicated, and then run through Adium's and Perian's systems. As each application has separate needs, I'll explain decisions behind each item along the way.
Getting Started or The Growl Release System
So with Growl we have a lot of different needs for anything that would build the dmg+projects:
- Something to build a specific target in Xcode
- Something to build multiple projects with multiple targets
- Something that can make a PKG file
- Something which can
- Something that can make a DMG (duh?)
- Something that can put a background on a DMG
- Something that can position icons in the DMG in specific ways.
Pretty early on a script or Makefile seems appropriate here, and we ended up with a Makefile+Applescript, so here's the long and short of the interesting bits. Here is a screenshot of the Growl disk image when mounted:
We can see from this image the requirements listed above., and more. It looks like a mess because it is, but that's more the fault of myself than anything else. For instance, let's look at the Perian DMG for the .5b4 release that I'm building now:
As you can see, the disk image can be made to be either randomized on disk or pretty strict. Let's move on to how to actually do all of this.
Top level Makefile
The first part you have to know about is that the top level directory of your source repo needs to have a file called Makefile in it. For a simple project you should plan ahead, and for a complex one you will appreciate this. At the very end of this blog post I will post the entire dmg making system, so if you'd like you can skip this for now. However, It will not be filled with comments, it will only have what is currently in the Adium/Growl/Perian build systems.
Basically the end result is to get a Makefile at the top level of the source tree that builds your project/targets how you like.
The release system also needs a folder called (unsurprisingly) Release, which will hold the rest of your release system items.
Here is the entire top level Makefile for the .7.4 release of Growl, with explanations along the way:
PREFIX?=
PREFERENCEPANES_DIR=$(PREFIX)/Library/PreferencePanes
Since Growl is a PrefPane, it lives in either ~/Library/PreferencePanes or /Librayr/PreferencePanes
FRAMEWORKS_DIR=$(PREFIX)/Library/Frameworks
GROWL_PREFPANE=Growl.prefPane
GROWL_FRAMEWORK=Growl.framework
This portion sets the framework directory and then the prefpane and framework names
BUILD_DIR=build
GROWL_HELPER_APP=$(PREFERENCEPANES_DIR)/$(GROWL_PREFPANE)/Contents/Resources/GrowlHelperApp.app
HEADERDOC_DIR=Docs/HeaderDoc
Setting some more stuff for use later in the script.
#DEFAULT_BUILDSTYLE=Deployment
DEFAULT_BUILDSTYLE=Development
BUILDSTYLE?=$(DEFAULT_BUILDSTYLE)
Here's where the fun stuff starts to happen. For those who don't follow this, basically this will allow you to change the build style by uncommenting one line and commenting another. If you happen to have 5 build styles, you could list 4 commented out and one uncommented, and easily switch between the whole lot of them.
CP=ditto --rsrc
RM=rm
This bit should be obvious based on the previous stuff.
.PHONY : all growl growlhelperapp growlapplicationbridge growlapplicationbridge-withinstaller frameworks clean install
all: frameworks
xcodebuild -alltargets -buildstyle $(BUILDSTYLE) build
growl:
xcodebuild -target Growl -buildstyle $(BUILDSTYLE) build
growlhelperapp:
xcodebuild -target GrowlHelperApp -buildstyle $(BUILDSTYLE) build
frameworks: growlapplicationbridge growlapplicationbridge-withinstaller
growlapplicationbridge:
xcodebuild -target Growl.framework -buildstyle $(BUILDSTYLE) build
growlapplicationbridge-withinstaller:
xcodebuild -target Growl-WithInstaller.framework -buildstyle $(BUILDSTYLE) build
clean:
xcodebuild -alltargets clean
All of this builds Growl and the frameworks or cleans it. Note the use of $(BUILDSTYLE) here.
install:
killall GrowlHelperApp || true
-$(RM) -rf $(PREFERENCEPANES_DIR)/$(GROWL_PREFPANE) $(FRAMEWORKS_DIR)/$(GROWL_FRAMEWORK)
$(CP) $(BUILD_DIR)/$(GROWL_PREFPANE) $(PREFERENCEPANES_DIR)/$(GROWL_PREFPANE)
open $(GROWL_HELPER_APP)
install-growl:
killall GrowlHelperApp || true
-$(RM) -rf $(PREFERENCEPANES_DIR)/$(GROWL_PREFPANE)
$(CP) $(BUILD_DIR)/$(GROWL_PREFPANE) $(PREFERENCEPANES_DIR)/$(GROWL_PREFPANE)
open $(GROWL_HELPER_APP)
headerdoc:
rm -rf $(HEADERDOC_DIR)
headerdoc2html -C -o $(HEADERDOC_DIR) Common/Source/GrowlDefines.h Common/Source/GrowlDefinesInternal.h Framework/Source/*.h Common/Source/GrowlPathUtil.h Display\ Plugins/GrowlDisplayProtocol.h Framework/Source/Growl.hdoc
gatherheaderdoc $(HEADERDOC_DIR)
uninstall:
killall GrowlHelperApp || true
@if [ -d "/Library/PreferencePanes/Growl.prefPane" ]; then \
echo mv "/Library/PreferencePanes/Growl.prefPane" "$(HOME)/.Trash"; \
mv "/Library/PreferencePanes/Growl.prefPane" "$(HOME)/.Trash"; \
elif [ -d "$(HOME)/Library/PreferencePanes/Growl.prefPane" ]; then \
echo mv "$(HOME)/Library/PreferencePanes/Growl.prefPane" "$(HOME)/.Trash"; \
mv "$(HOME)/Library/PreferencePanes/Growl.prefPane" "$(HOME)/.Trash"; \
fi
@if [ -d "/Library/Frameworks/GrowlAppBridge.framework" ]; then \
echo mv "/Library/Frameworks/GrowlAppBridge.framework" "$(HOME)/.Trash"; \
mv "/Library/Frameworks/GrowlAppBridge.framework" "$(HOME)/.Trash"; \
elif [ -d "$(HOME)/Library/Frameworks/GrowlAppBridge.framework" ]; then \
echo mv "$(HOME)/Library/Frameworks/GrowlAppBridge.framework" "$(HOME)/.Trash"; \
mv "$(HOME)/Library/Frameworks/GrowlAppBridge.framework" "$(HOME)/.Trash"; \
fi
The rest of this should be decently self explanatory. But, basically, the rest covers how to install and uninstall Growl. It's more convenience than anything else for developers, and is not required by any means to make this work.
This Makefile should be different for every project, but overall it should be pretty easy to modify this one for your needs. Besides, the fun bit is inside the Release directory anyhow. Let's move on to that.
The Release Directory, of Doom
Heh, DOOM. So ya, the release directory is what controls everything else here. Let's take a look inside:
growl-0.7/Release chris$ ls -1
Artwork
Get more styles.webloc
Growl Developer Documentation.webloc
Growl Documentation.webloc
Growl version history for developers.webloc
Growl version history.webloc
GrowlMail
GrowlSafari
Makefile
Uninstall Growl.app
dmg_growl.scpt
dmg_sdk.scpt
make-diskimage.sh
Specifically, what's required here to build a dmg with artwork is:
Artwork
Makefile
dmg_growl.scpt
make-diskimage.sh
This system only requires these 4 items and the top level to work. So let's get to the main Makefile, and then cover the other bits after that.
Release Makefile
SRC_DIR=..
BUILD_DIR=build
GROWL_DIR=$(BUILD_DIR)/Growl
SDK_DIR=$(BUILD_DIR)/SDK
RELEASE_NAME=Growl-0.7.5
RELEASE_DIRNAME=$(RELEASE_NAME)
RELEASE_DIR=$(BUILD_DIR)/$(RELEASE_DIRNAME)
CONFIGURATION=Deployment
BUILDFLAGS="CONFIGURATION=$(CONFIGURATION)"
PRODUCT_DIR=$(shell defaults read com.apple.Xcode PBXProductDirectory 2> /dev/null)
This bit here is where you start changing things. Specially, only 2 items, the CONFIGURATION and RELEASE_NAME. There's not much more to it here, as with before we have some settings that tell the script what things are. Some stuff is dynamically set, etc.
ifeq ($(strip $(PRODUCT_DIR)),)
GROWL_BUILD_DIR=$(SRC_DIR)/build/$(CONFIGURATION)
GROWLCTL_BUILD_DIR=$(SRC_DIR)/Extras/growlctl/build/$(CONFIGURATION)
GROWLDICT_BUILD_DIR=$(SRC_DIR)/Extras/GrowlDict/build/$(CONFIGURATION)
GROWLNOTIFY_BUILD_DIR=$(SRC_DIR)/Extras/growlnotify/build/$(CONFIGURATION)
GROWLTUNES_BUILD_DIR=$(SRC_DIR)/Extras/GrowlTunes/build/$(CONFIGURATION)
HARDWAREGROWLER_BUILD_DIR=$(SRC_DIR)/Extras/HardwareGrowler/build/$(CONFIGURATION)
GROWLMAIL_BUILD_DIR=$(SRC_DIR)/Extras/GrowlMail/build/$(CONFIGURATION)
GROWLSAFARI_BUILD_DIR=$(SRC_DIR)/Extras/GrowlSafari/build/$(CONFIGURATION)
RAWRJOUR_BUILD_DIR=$(SRC_DIR)/Extras/Rawr-jour/build/$(BUILDSTYLE)
else
TARGET_BUILD_DIR=$(PRODUCT_DIR)/$(CONFIGURATION)
GROWL_BUILD_DIR=$(TARGET_BUILD_DIR)
GROWLCTL_BUILD_DIR=$(TARGET_BUILD_DIR)
GROWLDICT_BUILD_DIR=$(TARGET_BUILD_DIR)
GROWLNOTIFY_BUILD_DIR=$(TARGET_BUILD_DIR)
GROWLTUNES_BUILD_DIR=$(TARGET_BUILD_DIR)
HARDWAREGROWLER_BUILD_DIR=$(TARGET_BUILD_DIR)
GROWLMAIL_BUILD_DIR=$(TARGET_BUILD_DIR)
RAWRJOUR_BUILD_DIR=$(TARGET_BUILD_DIR)
GROWLSAFARI_BUILD_DIR=$(TARGET_BUILD_DIR)
endif
Growl has a whole list of Extras that we ship (growlctl, GrowlDict, growlnotify, GrowlTunes, HardwareGrowler, GrowlMail, RawrJour, GrowlSafari) along with Growl, so we have to take that into consideration. The build system packages all of them up as well. So here we're telling Xcode (gcc and company) how to build it based on the style setup in Xcode.
# What to do before running this script:
# - Set version number in GHA. You can do this in GrowlController.m. Look for the "static struct Version version" line.
# - Set RELEASE_NAME
# - Edit the following two plist keys
# - Core/Resources/Info.plist
# - Core/Resources/GrowlHelperApp-Info.plist
Just some comments about what to do really.
.PHONY: all compile clean release source
all: compile release source
compile:
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/GrowlMail
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/GrowlSafari
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/GrowlDict
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/growlnotify
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/HardwareGrowler
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/growlctl
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/GrowlWidget
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/GrowlTunes
$(MAKE) $(BUILDFLAGS) -C $(SRC_DIR)/Extras/Rawr-jour
It rubs the lotion on the skin.
clean:
rm -rf $(BUILD_DIR)
Or else it gets the hose again.
source:
rm -rf $(RELEASE_DIR)
mkdir -p $(RELEASE_DIR)
cp -R $(SRC_DIR)/Bindings $(RELEASE_DIR)
cp -R $(SRC_DIR)/Common $(RELEASE_DIR)
cp -R $(SRC_DIR)/Core $(RELEASE_DIR)
cp -R $(SRC_DIR)/Display\ Plugins $(RELEASE_DIR)
cp -R $(SRC_DIR)/Docs $(RELEASE_DIR)
cp -R $(SRC_DIR)/Examples $(RELEASE_DIR)
cp -R $(SRC_DIR)/Extras $(RELEASE_DIR)
cp -R $(SRC_DIR)/Framework $(RELEASE_DIR)
cp -R $(SRC_DIR)/Growl\ Readme.rtfd $(RELEASE_DIR)
cp -R $(SRC_DIR)/Growl.xcodeproj $(RELEASE_DIR)
cp -R $(SRC_DIR)/Prefpane\ TestHarness $(RELEASE_DIR)
cp -R $(SRC_DIR)/Scripts $(RELEASE_DIR)
cp -R $(SRC_DIR)/images $(RELEASE_DIR)
cp $(SRC_DIR)/HACKING.txt $(RELEASE_DIR)
cp $(SRC_DIR)/License.txt $(RELEASE_DIR)
cp $(SRC_DIR)/Makefile $(RELEASE_DIR)
cp $(SRC_DIR)/README.rtf $(RELEASE_DIR)
cp $(SRC_DIR)/build.sh $(RELEASE_DIR)
cp $(SRC_DIR)/changes.txt $(RELEASE_DIR)
cp $(SRC_DIR)/generateSVNRevision.sh $(RELEASE_DIR)
cp $(SRC_DIR)/headerDoc2HTML.config $(RELEASE_DIR)
We really do copy all of this into the 2 dmgs that are produced, the SDK dmg and the Growl.dmg.
find $(RELEASE_DIR) \( -name build -or -name .svn \) -type d -exec rm -rf {} \; -prune
find $(RELEASE_DIR) \( -name "*~" -or -name .DS_Store \) -type f -delete
tar -cj -C $(BUILD_DIR)/ -f $(RELEASE_DIR)-src.tar.bz2 $(RELEASE_DIRNAME)
This is the bit I keep think I'll remove. It doesn't work right. But it's supposed to make a source bzball. The rest is decently commented, so if there's something I think is confusing just email me ( the_tick at this domain).
release:
@# clean build directory
rm -rf $(BUILD_DIR)
mkdir $(BUILD_DIR)
mkdir $(GROWL_DIR)
@#
@# copy uninstaller
@#
cp -R "Uninstall Growl.app" $(GROWL_DIR)
/Developer/Tools/SetFile -a E $(GROWL_DIR)/Uninstall\ Growl.app
@#
@# copy webloc files
@#
cp "Growl Documentation.webloc" "Growl version history.webloc" "Get more styles.webloc" $(GROWL_DIR)
@#
@# hide extensions of webloc files
@#
/Developer/Tools/SetFile -a E $(GROWL_DIR)/*.webloc
@#
@# copy the prefpane
@#
cp -R $(GROWL_BUILD_DIR)/Growl.prefPane $(GROWL_DIR)
@#
@# copy the extras
@#
These bits were all pretty well documented.
mkdir $(GROWL_DIR)/Extras
mkdir $(GROWL_DIR)/Extras/growlctl
cp $(GROWLCTL_BUILD_DIR)/growlctl $(GROWL_DIR)/Extras/growlctl
cp $(SRC_DIR)/Extras/growlctl/growlctl.1 $(GROWL_DIR)/Extras/growlctl
cp $(SRC_DIR)/Extras/growlctl/install.sh $(GROWL_DIR)/Extras/growlctl
Copy in growlctl
mkdir $(GROWL_DIR)/Extras/GrowlDict
cp -R $(GROWLDICT_BUILD_DIR)/GrowlDict.app $(GROWL_DIR)/Extras/GrowlDict
cp $(SRC_DIR)/Extras/GrowlDict/README.txt $(GROWL_DIR)/Extras/GrowlDict
Copy in GrowlDict
mkdir $(GROWL_DIR)/Extras/growlnotify
cp $(GROWLNOTIFY_BUILD_DIR)/growlnotify $(GROWL_DIR)/Extras/growlnotify
cp $(SRC_DIR)/Extras/growlnotify/growlnotify.1 $(GROWL_DIR)/Extras/growlnotify
cp $(SRC_DIR)/Extras/growlnotify/install.sh $(GROWL_DIR)/Extras/growlnotify
cp $(SRC_DIR)/Extras/growlnotify/README.txt $(GROWL_DIR)/Extras/growlnotify
Copy in growlnotify, the cli notification util for Growl.
mkdir $(GROWL_DIR)/Extras/GrowlTunes
cp -R $(GROWLTUNES_BUILD_DIR)/GrowlTunes.app $(GROWL_DIR)/Extras/GrowlTunes
cp -R $(SRC_DIR)/Extras/GrowlTunes/ReadMe.rtfd $(GROWL_DIR)/Extras/GrowlTunes
mkdir $(GROWL_DIR)/Extras/HardwareGrowler
cp -R $(HARDWAREGROWLER_BUILD_DIR)/HardwareGrowler.app $(GROWL_DIR)/Extras/HardwareGrowler
cp $(SRC_DIR)/Extras/HardwareGrowler/readme.txt $(GROWL_DIR)/Extras/HardwareGrowler
mkdir $(GROWL_DIR)/Extras/Rawr-jour
cp -R $(RAWRJOUR_BUILD_DIR)/Rawr-jour.app $(GROWL_DIR)/Extras/Rawr-jour
cp $(SRC_DIR)/Extras/Rawr-jour/Icon\ and\ Readme/Readme.rtf $(GROWL_DIR)/Extras/Rawr-jour
Rawr-Jour, GrowlTunes and HardwareGrowler all get copied in.
@#
@# build GrowlMail package
@#
mkdir $(GROWL_DIR)/Extras/GrowlMail
mkdir $(BUILD_DIR)/GrowlMail
mkdir $(BUILD_DIR)/GrowlMail-Resources
cp -R $(GROWLMAIL_BUILD_DIR)/GrowlMail.mailbundle $(BUILD_DIR)/GrowlMail
cp GrowlMail/InstallationCheck $(BUILD_DIR)/GrowlMail-Resources
cp GrowlMail/postflight $(BUILD_DIR)/GrowlMail-Resources
cp -R GrowlMail/English.lproj $(BUILD_DIR)/GrowlMail-Resources
cp -R GrowlMail/German.lproj $(BUILD_DIR)/GrowlMail-Resources
Copy in GrowlMail stuff to prepare it to be built into a PKG.
say enter your password
sudo chown -Rh root:admin $(BUILD_DIR)/GrowlMail
sudo chmod -R g+w $(BUILD_DIR)/GrowlMail
With PKG's, you have to set some permissions.
/Developer/Tools/packagemaker -build -p $(GROWL_DIR)/Extras/GrowlMail/GrowlMail.pkg -f $(BUILD_DIR)/GrowlMail -ds -v -i GrowlMail/Info.plist -d GrowlMail/Description.plist -r $(BUILD_DIR)/GrowlMail-Resources
Here we build the PKG.
sudo rm -rf $(BUILD_DIR)/GrowlMail
rm -rf $(BUILD_DIR)/GrowlMail-Resources
Some cleanup
cp $(SRC_DIR)/Extras/GrowlMail/GrowlMail\ Installation.rtf $(GROWL_DIR)/Extras/GrowlMail
And we copy in the final bit for GrowlMail, the Installation rtf.
@#
@# build GrowlSafari package
@#
mkdir $(GROWL_DIR)/Extras/GrowlSafari
mkdir $(BUILD_DIR)/GrowlSafari
mkdir $(BUILD_DIR)/GrowlSafari-Resources
cp -R $(GROWLSAFARI_BUILD_DIR)/GrowlSafari $(BUILD_DIR)/GrowlSafari
cp GrowlSafari/postupgrade $(BUILD_DIR)/GrowlSafari-Resources
sudo chown -Rh root:admin $(BUILD_DIR)/GrowlSafari
sudo chmod -R g+w $(BUILD_DIR)/GrowlSafari
/Developer/Tools/packagemaker -build -p $(GROWL_DIR)/Extras/GrowlSafari/GrowlSafari.pkg -f $(BUILD_DIR)/GrowlSafari -ds -v -i GrowlSafari/Info.plist -d GrowlSafari/Description.plist -r $(BUILD_DIR)/GrowlSafari-Resources
sudo rm -rf $(BUILD_DIR)/GrowlSafari
rm -rf $(BUILD_DIR)/GrowlSafari-Resources
cp -R $(SRC_DIR)/Extras/GrowlSafari/README.txt $(GROWL_DIR)/Extras/GrowlSafari
GrowlSafari is also a PKG installer, and is built the same way that GrowlMail is built. The next bit is for building the SDK that contains the Growl.framework, Growl-Withinstaller.framework, and Bindings. It's commented, so I won't go over it. But here it is:
@#
@# build the SDK
@#
mkdir $(SDK_DIR)
@#
@# copy the webloc files
@#
cp "Growl Developer Documentation.webloc" "Growl version history for developers.webloc" $(SDK_DIR)
@#
@# hide extensions of webloc files
@#
/Developer/Tools/SetFile -a E $(SDK_DIR)/*.webloc
@#
@# copy the scripts
@#
cp -R $(SRC_DIR)/Scripts $(GROWL_DIR)
@#
@# copy the frameworks
@#
mkdir $(SDK_DIR)/Frameworks
cp -R $(GROWL_BUILD_DIR)/Growl.framework $(GROWL_BUILD_DIR)/Growl-WithInstaller.framework $(SDK_DIR)/Frameworks
@#
@# copy the bindings
@#
cp -R $(SRC_DIR)/Bindings $(SDK_DIR)
@#
@# remove the AppleScript binding
@#
rm -rf $(SDK_DIR)/Bindings/applescript
Note here, we build the Applescript Bindings right into Growl, so there's no need to ship them on the SDK DMG.
@#
@# remove some symlinks
@#
rm $(SDK_DIR)/Bindings/realbasic/GrowlDefines.h
rm $(SDK_DIR)/Bindings/tcl/GrowlDefines.h
rm $(SDK_DIR)/Bindings/tcl/GrowlApplicationBridge.h
rm $(SDK_DIR)/Bindings/tcl/GrowlApplicationBridge.m
Wheeee, symlinks bad!
@#
@# delete svn and backup files
@#
find $(BUILD_DIR) -name ".svn" -type d -exec rm -rf {} \; -prune
find $(BUILD_DIR) \( -name "*~" -or -name .DS_Store -or -name classes.nib -or -name info.nib \) -type f -delete
This bit is always fun. Removing these should be part of your build system no matter what you end up doing. Or at least I would remove them :)
@#
@# make Growl disk image
@#
mkdir $(GROWL_DIR)/.background
cp $(SRC_DIR)/images/dmg/growl075DMGBackground.png $(GROWL_DIR)/.background
./make-diskimage.sh $(BUILD_DIR)/$(RELEASE_NAME).dmg $(GROWL_DIR) Growl dmg_growl.scpt
Here's the important bits. Basically in order for this to work you have to make a folder called .background and copy the image you want into it. Then you run the disk image shell script and it's done.
@#
@# make SDK disk image
@#
mkdir $(SDK_DIR)/.background
cp $(SRC_DIR)/images/dmg/growlSDK.png $(SDK_DIR)/.background
./make-diskimage.sh $(BUILD_DIR)/$(RELEASE_NAME)-SDK.dmg $(SDK_DIR) Growl-SDK dmg_sdk.scpt
@echo Build finished
The AppleScript
That's it for the Makefile. but what about the AppleScript and Shell script? I'll be including those in the zip file at the end of this post, but would like to review the AppleScript here. The shell script will not be gone through, it's pretty self explanatory.
tell application "Finder"
tell disk "Growl" open
tell container window
set current view to icon view set toolbar visible to false
set statusbar visible to false set the bounds to {30, 50, 485, 350}
end tell
This portion tells the finder how big to make the dmg. You're specifically interested in the second 2 numbers. This basically sets the width and height of the window.
close set opts to the icon view options of container window
tell opts
set icon size to 56
Here we can set the icon size of all of the items on the dmg.
set arrangement to not arranged
end tell
set background picture of opts to file ".background:growl075DMGBackground.png"
This is where you enter the name of the background artwork you are going to be using.
set position of item "Growl.prefPane" to {45, 41}
set position of item "Extras" to {162, 33}
set position of item "Scripts" to {36, 153}
set position of item "Growl Documentation.webloc" to {128, 123}
set position of item "Growl version history.webloc" to {265, 41}
set position of item "Get more styles.webloc" to {383, 41}
set position of item "Uninstall Growl.app" to {383, 123}
This sets the location of each of the icons on the DMG.
update without registering applications
tell container window
set the bounds to {31, 50, 480, 350}
set the bounds to {30, 50, 480, 350}
end tell
I believe this portion also tells the finder how to set the size of the window when mounted, albeit I'm not 100% on that. You'll need to play around with it.
update without registering applications
end tell
--give the finder some time to write the .DS_Store file
delay 5
This bit is important. The .DS_Store stores a lot of this info, so we
end tell
That's really all there is to this. The dmg shell script builds the rest and then the process is complete. No more need for Filestorm or other applications, plus this makes life a ton easier.
Auto Versioning
You can even automate versioning as well. The Adium MakeFile has this little tidbit:
PLIST_DIR=`pwd`/../Plists
ADIUM_PLIST=$(PLIST_DIR)/Adium_2
CRASH_REPORTER_PLIST=$(PLIST_DIR)/Adium\ Crash\ Reporter-Info
version:
@# update the plists
defaults write $(ADIUM_PLIST) CFBundleGetInfoString '$(VERSION), Copyright 2001-2007 The Adium Team'
defaults write $(ADIUM_PLIST) CFBundleVersion '$(VERSION)'
defaults write $(ADIUM_PLIST) CFBundleShortVersionString '$(VERSION)'
defaults write $(CRASH_REPORTER_PLIST) CFBundleGetInfoString '$(VERSION), Copyright 2001-2007 The Adium Team'
defaults write $(CRASH_REPORTER_PLIST) CFBundleVersion '$(VERSION)'
defaults write $(CRASH_REPORTER_PLIST) CFBundleShortVersionString '$(VERSION)'
plutil -convert xml1 $(ADIUM_PLIST).plist
plutil -convert xml1 $(CRASH_REPORTER_PLIST).plist
This writes the version out to to 2 plists, along with copyright information. So you'd set the version in the Makefile, hit Make, and this handles the rest.
openUp
Last and not least, before I go, I need to talk about a utility called openUp. The openUp utility won't exactly be required for this to all work, but it'll help (i.e. you want it). The scripts assume it is installed into /usr/local/bin, but you can modify that. I've included it in the Utilities folder on the zip file.
For what it does, I'll just copy and paste the comments from the .c file:
/*
* Shantonu Sen <<EMAIL REMOVED>>
* openUp.c - program to set the "first-open-window" field of a volume
*
* Get the directory ID for the first argument, and set it as word 2
* of the Finder Info fields for the volume it lives on
*
* cc -o openUp openUp.c
* Usage: openUp /Volumes/Foo/OpenMe/
*
*/
The end
Well, that's it. I hope this has been informative. Oh, here's the zip (2.4 mb).
Also, this is my first attempt at posting with the newer versions of Ecto. I rather like this, and will probably purchase it.
Posted by Chris Forsythe at 02:27 PM | Comments (1)
September 19, 2006
Old svn client == bad
If you ever update your or make a fresh repo with svnadmin, and then get the following errors:
svn ls file:///path/to/testrepo/
svn: Unable to open an ra_local session to URL svn: Unable to open repository 'file:///path/to/testrepo' svn: Expected format '3' of repository; found format '5'
Be sure to check your client version.
For instance, oooh.. running svn version 1.2.3 with a repo version 1.4.0 (which I did) would be bad.
Posted by Chris Forsythe at 04:45 AM | Comments (0)
September 10, 2006
Cocoadevhouse was postponed
So CDH Texas was post-poned. I don't know when it's rescheduled, and I don't know if I'll be able to attend.
However, mini-vacation-06 was great. The wife and I went into the bowels of the underworld (if 180 feet are considered bowels) and then back up.
Posted by Chris Forsythe at 05:39 PM | Comments (0)

