Uli's Web Site
[ Zathras.de - Uli's Web Site ]
Other Sites: Stories
Abi 2000
Stargate: Resurgence
Lost? Site Map!
     home | blog | moose | programming | articles >> blog

 Blog Topics

15 Most Recent [RSS]

 Less work through Xcode and shell scripts
2011-12-16 @600
 iTunesCantComplain released
2011-10-28 @954
 Dennis Ritchie deceased
2011-10-13 @359
 Thank you, Steve.
2011-10-06 @374
 Cocoa Text System everywhere...
2011-03-27 @788
 Blog migration
2011-01-29 @520
 All you need to know about the Mac keyboard
2010-08-09 @488
 Review: Sherlock
2010-07-31 @978
 Playing with Objective C on Debian
2010-05-08 @456
 Fruit vs. Obst
2010-05-08 @439
 Mixed-language ambiguity
2010-04-15 @994
 Uli's 12:07 AM Law
2010-04-12 @881
 Uli's 1:24 AM Law
2010-04-12 @874
 Uli's 6:28 AM Law
2010-04-12 @869
 Uli's 3:57 PM Law
2010-04-12 @867


Less work through Xcode and shell scripts

Update:If you like this, you can find more scripting vaguely related to Xcode here.

Like most programmers, I'm not much a fan of repetitive work. I like to do the real work myself, while leaving the computer to take care of the drudgework. Among the most handy tools for this are scripts of all kinds. Having tried to fight AppleScript for a while, I finally realized that, while they may be uglier, shell scripts are a much better tool for this task. Here's a selection of my favorite shell scripts:

Delete Subversion folders

I use Subversion to keep track of my source code and to make it easy for me to undo any bigger changes I make. Sadly, Subversion litters all folders with its ".svn" folders. As of Xcode 1.5, when I add a folder reference to my "Resources" group, Xcode will also copy along those ".svn" folders, which are completely useless to end users and double the size of the executable. So, I've been adding the following bash script to a Shell Script Files build phase in most of my Xcode projects:

sudo find -d "${BUILD_DIR}/${PRODUCT_NAME}.app/Contents/Resources/" -name ".svn" -exec rm -r '{}' \; -print

This scans the generated application's "Resources" directory for any ".svn" folders and deletes them. The -d option is important here: It causes a depth-first traversal, meaning that if the ".svn" folder contains another file of the same name, it will be deleted first. Otherwise you get odd error messages because the deeper file has been deleted by the time find gets to it.

Auto-generating a Help Index

To get an index for your Help Book, and to be able to bring up anchors directly from code, you need to run the Apple Help Indexer on it. Since this is something I easily forget, I use the following script in another Shell Script Files build phase:

open -a /Developer/Applications/Utilities/Apple\ Help\ Indexing\ Tool.app ${BUILD_DIR}/${PRODUCT_NAME}.app/Contents/Resources/${PRODUCT_NAME}\ Help

or on Tiger:

open -a /Developer/Applications/Utilities/Help\ Indexer.app ${BUILD_DIR}/${PRODUCT_NAME}.app/Contents/Resources/${PRODUCT_NAME}\ Help

Note that open launches the indexer asynchronously, which means the build continues (and could finish) while the indexer is running. So, you may have to build the app a second time to make sure you don't get the old index.

Using PHP for your Help Books

One problem with help books is that they are restricted to being plain HTML files plus AppleScripts. There's really no nice way to "#include" a title or navigation area or a common design. PHP would let you do things like that. But PHP files need to be displayed through Apache, with PHP turned on in the httpd.conf. This would require you to install your help book in the user's Sites folder, mess with Apache's configuration, restart Apache and view your help through Safari (which doesn't have Help Viewer's great search feature, nor its facilities for integrating with your program).

But luckily, Apple started shipping along the new PHP command-line tool with MacOS X 10.3. So, if you can live with static content, you can generate HTML files from your PHP scripts through a simple command:

php script.php > page.htm

Of course, we want to automate this. We can use the find command to run this on all php files in a particular folder. But sadly, we can't have a redirect operator (">") in the -exec parameter to find. So, create a new shell script file "php2html.sh" and write the following script into it and chmod +x it:
#! /bin/bash
php "$1" > "$1.html"
This script will take a PHP file path as its parameter and create an html file with the executed script's output next to it. Once that's done, all you need is a shell script build phase:
dir="./${PRODUCT_NAME} Help/"
find -d "$dir" -name '*.php' -exec "${dir}php2html.sh" '{}' \; -print
And after that, maybe another call to find like above that deletes all the PHP source files after copying, or that copies everything but PHP files from the project directory. Neat, huh? Just remember to run your help indexing script after this one so there is something to be indexed.

Including the Subversion Revision in your App

I like to have the current SVN revision number somewhere in my app so there's a way to distinguish copies of the app even if I forget to bump up the version number. To do that, I use the following script:

#! /bin/bash

echo -n "Finding revision in "
revnum=`/usr/local/bin/svnversion . | cut -f '2' -d ':'`
# Now write the constant declaration to the file:
echo "#define SVN_VERSION \"$revnum\"" > svn_version.h
echo "Wrote revision $revnum to svn_version.h"

This creates a file named "svn_version.h" in the project's folder that contains the statement #define SVN_VERSION "46". I.e. you get a string constant that you can use in your C files wherever you want to display the current revision. It's important that this is a string, as a modified working copy gets a version number like "46M", which would cause trouble if you use an int.

Build and Upload File for Deployment

I also have a neat little shell script that switches my project's build style to "Deployment", builds it, compresses it and uploads it to a web server:

#! /bin/bashecho '===== BUILDING FILIE FOR DEPLOYMENT ====='
cd `dirname $0`
xcodebuild -project Filie.xcode -buildstyle Deployment clean build

cd build/
echo '===== CREATING ARCHIVE ====='
tar -czf Filie.tgz Filie.app

echo '===== UPLOADING ARCHIVE ====='
curl --upload-file Filie.tgz ftp://home-up.t-online.de/

echo '===== FINISHED ====='

Note that this script uses Tar/GZip, and thus can't cope with resource forks (though I've heard rumors that Tiger's command line tools have been changed to fix this). Also, you can use man curl to find out what parameters to include to authenticate with the FTP server to which you're uploading if your ISP doesn't pre-authenticate you like mine does.

I've put most of these scripts into files in my central library so I can just call them from Xcode, and to avoid code duplication that would make maintenance hard. I'd be interested in hearing what kinds of scripts you are using.

Reader Comments: (RSS Feed)
Ben writes:
Re: Auto-generating a Help Index 1. Assuming the bundle identifier hasn't changed, would "open -b com.apple.helpindexer ..." work for both Panther and Tiger? 2. If a help book has been localised, is there a way to index each localisation (other than searching for folders with the .lproj extension)?
Uli Kusterer replies:
Ben, 10.3 and earlier don't have the "-b" option in "open". So no, this won't work in Panther. This is a new option with 10.4 "Tiger". And to find other localisations, you'd probably have to use a similar approach as for the ".svn" folders: Use "find" to find all .lprojs in your app, and then base your path to be indexed on that. Or manually code a new indexing statement for each one. I don't know of a way to have Help Indexer find the different languages automatically.
Ben writes:
Thanks, I'll try the "find" command. Re: Delete Subversion folders Is there any difference between "-exec rm -r '{}'" and the "-delete" option?
Uli Kusterer replies:
Only that I couldn't get the "-delete" option to work without spouting dozens of errors. I don't remember exactly what it was -- After all, this was almost a year ago.
Allan Odgaard writes:
Likely �-prune� should be used with �-delete� � this makes it not descend into the current folder (so also use that instead of -b.) E.g.: find "$TARGET" -name .svn -delete -prune Notice also I quoted the shell variable. ALWAYS quote these, otherwise, if they contain a space (or another IFS character) they will expand to multiple parameters. This is AFAIK what happened with the incident where the iTunes installer deleted peoples music library: people who had a space in their path effectively got everything deleted starting from that space (or something like that.) Btw: I don�t think recent versions of Xcode include the .svn folders. At least I haven�t got any for my target, and I did not setup explicit deletion of these (but do e.g. have my Nibs under svn control.)
Zac White writes:
Nice tips! I added the following to the help indexer stuff: sleep 3 osascript -e 'tell app "Help Indexer" to quit' Now it closes automatically. Handy!
Rainer Brockerhoff writes:
Uli, a build script to delete .svn folders, somewhat simpler than yours, was responsible for me losing a few gigabytes of (unfortunately not backed-up) data a couple of years ago; the only time I've lost data in maybe 15 years. I had the habit of prefixing my current folder name with spaces to have it appear first in the Finder - I now use ---. Shell scripting is not my forte, but shouldn't that be find -d "${BUILD_DIR}/${PRODUCT_NAME}.app/Contents/Resources/" -name ".svn" -exec rm -r '{}' \; -print ? Of course I'm not about to try this out on my own system ;-)
Uli Kusterer replies:
Rainer, good point. I've added those, though I don't have any folders to try it on right now. Also, having a quote in one of your folder names would probably still make it choke... While shell scripts may be a lot less annoying than AppleScript, they apparently developed out of someone's very simple search-and-replace scripts, and it shows :-( Allan, I'm pretty sure I tried -prune. Anyway, it's not that important in this case, as recent versions of Xcode all tend to get rid of excess .svn folders. So you probably won't need this script very often.
Uli Kusterer replies:
I remember now, why I used -exec rm -r instead of -delete: -delete silently fails when deleting a folder.
michaK writes:
Hi, Do you think there's any way to change the PRODUCT_NAME automatically as a PreBuild Phase ? I just want to add the svn revision to the ProductName so that each revision of the application as its own independant installation ? Best, M
Or E-Mail Uli privately.
Created: 2005-04-18 @564 Last change: 2024-07-23 @161 | Home | Admin | Edit
© Copyright 2003-2024 by M. Uli Kusterer, all rights reserved.