Increment build number for deployment builds
If we want to distribute “deployment builds” regularly (e.g. to our betatesters) it pays to automate the process. A deployment build can be done from the command line using:
xcodebuild clean
xcodebuild -buildstyle Deployment
But if we do this, we probably also want to bump the version number, or at least the build number, so that we can distinguish between the different builds.
The version string of your program is stored in the Info.plist
file as the CFBundleVersion
key/value pair. By default this file is in XML, but to make it easier to work with, we can convert it to the old-style ascii format using the pl
command. Example:
% pl < Info.plist | grep CFBundleVersion
CFBundleVersion = "1.0b0";
I use “major.minor” followed by a b
(for beta) and then the build number, which is consistent with how Apple wants you to use CFBundleVersion.
To increase this number (from a shell script) we can use the ability in perl
to execute code as part of the format string (when doing regular expression substitution), example:
% pl < Info.plist \
| perl -pe 's/(CFBundleVersion = ".+\D)(\d+)(";)/$1.($2+1).$3/eg' \
| grep CFBundleVersion
CFBundleVersion = "1.0b1";
The regular expression pattern finds the last numeric part of the version number and increments it, so if we’d used “1.0.1” or “1.0” instead, it would also work. I have added the latter grep
only to limit the output here, in your script you’d probably do:
mv Info.plist Info.plist_backup && pl < Info.plist_backup \
| perl -pe > Info.plist 's/(CFBundleVersion = ".+\D)(\d+)(";)/$1.($2+1).$3/eg'
There is one other place where the version number of your program may exist, and that is in the InfoPlist.strings
file, which contain localized versions of your Info.plist
values. I have solved this by having a file called InfoPlist_in.strings
containing the following:
CFBundleName = "TextMate";
CFBundleShortVersionString = "${TM_SHORT_VERSION}";
CFBundleGetInfoString = "TextMate version ${TM_SHORT_VERSION}, Copyright ${TM_YEAR} MacroMates.";
NSHumanReadableCopyright = "Copyright ${TM_YEAR} MacroMates.";
Basically just holding placeholders for the variables. And then to produce the correct file I again turn to perl
and do:
printf > English.lproj/InfoPlist.strings "\xfe\xff"
TM_YEAR=`date +%Y` \
TM_SHORT_VERSION=`sed -n < Info.plist 's/^.*CFBundleVersion = "\(.*\)[abdf].*".*$/\1/p'` \
perl < InfoPlist_in.strings -pe 's/\$\{([^}]*)\}/$ENV{$1}/g' \
| iconv >> English.lproj/InfoPlist.strings -f utf8 -t ucs-2
The first line (the printf
) is just to get a unicode byte order marker (BOM), then I setup a TM_YEAR
and TM_SHORT_VERSION
variable (this is how it is done in bash
) and call perl
to substitute all occurences of ${...}
with the actual value of the variable, and I run this through iconv
to convert the result to ucs-2 (UTF-16).