A sensible way to increment bundle version (CFBundleVersion) in Xcode

tl;dr: Automatically set your app’s bundle version based on the number of git commits up to that point. Skip to the code!

The Problem
When I started working with Feathr over a year ago, one of the first issues I ran into was what to use as the bundle version (what I often refer to as the ‘build number’) in our apps. Originally, we were ignoring it until we had to change it – whenever it was time to submit a new version of an app, the new build number had to be higher than the previous submission. Pretty soon this got annoying, and I had the feeling we weren’t using the field to its full potential.

Research + Tactics
With a bit of Googling, I found a few ways people were automating changing the bundle version. Some people were auto-incrementing the field every time a build was run, but I might build my project a hundred times in a day if I’m trying to work out a small UI issue! That would quickly put my build number into the thousands, and if I continued to work on a project for any length of time it could become unnecessarily large. Plus, that number in itself would be useless to me, and I like my version numbers to mean something. Some SVN users put the current repository revision number as the build number… now that was something! The build number would point to something discrete – a specific revision of code – and wouldn’t change unnecessarily. If someone was having a problem with the app, all the developer needs is the build number – easily obtainable in tools like Crashlytics and easy to show somewhere in-app – to know the exact revision that the user is working with. This is a big win both during testing and when live apps are having issues.

The Snags
Alright, that is it, that is what I want to do. BUT WAIT… we use git for our source control. I won’t go into why I think git is superior to SVN (plenty of others have argued both sides of that), but the salient issue is that git, unlike SVN, does not give perfect integer revision numbers that increment on each commit. Instead, git hashes the commit data and uses that as a unique identifier of the commit. That means one commit could be 8d844d8dce7fbd0fe5b2bf8232ff1b82c8244648 and the next f1728db451a8a409215fa450d90d145ee77f9a4c, which is incomprehensible AND unusable as a bundle version.

The Compromise
Why not make a virtual “revision number” based on the number of commits that exist on a certain branch? Since I base all my work on a ‘development’ branch, I can simply have git count the number of commits on development and use that as my build number. I’m anchoring it to a specific branch so that the revision number is consistent: even if I check out another branch – to work on a new feature, for example – the number always points to the same commit and won’t differ between branches. This of course requires the branch used for counting to be long-lasting, and it’s only really useful if it’s where you distribute most of your builds from.

The Paradox (+ the fix)
One more problem: if you change the build number every time you add a commit (and you’re tracking the file that holds said build number in git), you’ll infinitely recurse into an update build number, commit updated-build-number, update build number again, commit again loop of horror. You could simply .gitignore the info.plist file, but that means you have to remove it from your repo (otherwise, modifications show even if it is .gitignored). To get around this (thanks to a suggestion I saw on StackOverflow1) we can leave the source-controlled info.plist file alone, and update the bundle version directly in the target build directory’s info.plist file. This means that the value of CFBundleVersion seen in Xcode is not used anywhere, since it is not overwritten until after info.plist is copied to the target build directory.

The Code


  1. Put this file in your repository (somewhere like /scripts/)
  2. In Xcode, create a Run Script build phase AFTER the Copy Bundle Resources phase
  3. In the Run Script, call path/to/update_build_number.sh [branch] where [branch] is the branch you want the count based on. If not supplied, master is used.

If no branch is supplied (via command-line argument) then the script defaults to ‘master’. It uses git rev-list [branch] --count to get the number of commits on [branch], BUT it subtracts out the number of commits behind said branch that you are currently (with git rev-list HEAD..[branch] --count). This is so that if you aren’t at the tip of the branch (e.g. you’re checked out a few commits behind to find a problem), the build number will still be accurate to what you’re currently running. Also, instead of updating the info.plist file in your source directory, it modifies the info.plist in the target build directory; this way, you don’t have to check-in a constantly-modifying info.plist.

Wait a minute…
I know what you’re thinking: “Hey! You implied we’d be able to get back to a given build number’s code easily, but I can’t just git checkout [build number] to get to the [build number]th commit!”. This is true, however… There’s A Script For That™2. Just do nth-commit.sh build_number branch. Enjoy!

  1. SO answer that suggests editing the info.plist after it is copied to the target build directory 

  2. Modified from this gist 

Build KeePassX In OSX Mountain Lion (without MacPorts!)

Recently, I wanted to try out an addition to KeePassX 2.0 that is currently sitting as a pull request on GitHub. I cloned the code, but quickly realized it wouldn’t be as easy as opening in Xcode and clicking ‘Run’ (yes, I’m spoiled :p).

I looked at the INSTALL file, which helpfully has a section called “Building on Mac OS X”. However, the first task gave me pause: install MacPorts. I won’t profess to have a lot of experience using MacPorts, but I’ve read some negative things regarding its complexity and brittleness. Not to mention I’m already knee-deep in brew kegs, which in my experience have been downright pleasing to install and use.

Naturally, I decided to try and get all of the dependencies from brew and build KeePassX without MacPorts.

Step 1: Prerequisites

This, surprisingly – or unsurprisingly if you have as much faith in brew as I do – was easy. I adapted the dependency install instructions from MacPorts to brew very easily (the only difference was qt-4mac became qt).

brew install cmake qt4 libgcrypt zlib

Might as well get into the build folder while we’re at it (this assumes you’re already in the KeePassX code root):

mkdir build
cd build

NOTE: Everything below this line is outdated and has been fixed in recent commits to the repo (the app can now be built with Clang!). To finish compilation, just run

make package

I will leave the below instructions for posterity.

Step 2: cmake the makefile

Up front I should say I am a bit unfamiliar with makefiles and cmake and the like. As an iOS developer, I am mostly sheltered from that level of compiler interaction. So when I ran the command as given in INSTALL and got a strange error, I almost gave up. The error I got was:

-- Performing Test ZLIB_SUPPORTS_GZIP - Failed
CMake Error at CMakeLists.txt:181 (message):
  zlib 1.2.x or higher is required to use the gzip format

-- Configuring incomplete, errors occurred!

Googling was almost zero help, but I did find one mention of simply commenting out that test in CMakeLists.txt and moving on. So I did, by commenting the following three lines with a #:

#  message(FATAL_ERROR "zlib 1.2.x or higher is required to use the gzip format")

I also decided to specify the location of the brew-installed zlib (instead of letting it use the OSX-supplied version), which according to brew was in /usr/local/opt/zlib/lib. So I added -DZLIB_ROOT=/usr/local/opt/zlib/lib to the call.

After doing these things, cmake completed successfully, but make package (the next step) failed rather quickly with a warning about unsupported compiler flags:

clang (LLVM option parsing): Unknown command line argument '-stack-protector-buffer-size=4'.  Try: 'clang (LLVM option parsing) -help'
clang (LLVM option parsing): Did you mean '-path-profile-verifier-file=4'?
make[2]: *** [src/http/qjson/CMakeFiles/qjson.dir/parser.cpp.o] Error 1
make[1]: *** [src/http/qjson/CMakeFiles/qjson.dir/all] Error 2
make: *** [all] Error 2

This is because cmake set up the makefile to use the system default compiler, which happens to be clang, while the build scripts are all expecting to use gcc. To change this, we pass a few extra command line options to cmake and explicitly tell it to use gcc and c++.

Here’s what the final cmake invocation looks like:

cmake .. -DCMAKE_OSX_ARCHITECTURES="x86_64" -DZLIB_ROOT=/usr/local/opt/zlib/lib -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++

Step 3: make package

… that’s it! If that completes successfully, you are left with a .pkg file that has KeePassX.app in it, ready to be put in /Applications and opened! Congrats!


  • If you re-run cmake at any point, make sure you clear its cache by destroying and re-creating the build folder. If you don’t, strange things can happen.
  • If you don’t have gcc/g++ (run which gcc and see if there is output), download the Xcode Command Line Tools.


Fun with Sublime Text

Sublime Text is the greatest thing since sliced bread. Here’s how I set it up to get the most out of it.

Step 1: Install the Package Manager!

  1. Open Sublime
  2. Toggle the Sublime console with ctrl ` (Control + backtick)
  3. Run the command on this page: http://wbond.net/sublime_packages/package_control/installation

Step 2: Syncing Via Dropbox

I use multiple computers, and want to sync my settings across them to have a consistent experience in Sublime. Make sure Sublime is closed for this part!

  1. Move your Sublime Text Package folders into Dropbox (I used Dropbox/settings/Sublime Text 2)
  2. Symlink the Dropbox-synced folders back to their original location

Here’s how I did it:
First, move the Sublime Package folders to Dropbox.

 $ mkdir ~/Dropbox/settings/Sublime\ Text\ 2
 $ cd ~/Dropbox/settings/Sublime\ Text\ 2
 $ mv ~/Library/Application\ Support/Sublime\ Text\ 2/Installed\ Packages/ .
 $ mv ~/Library/Application\ Support/Sublime\ Text\ 2/Packages/ .
 $ mv ~/Library/Application\ Support/Sublime\ Text\ 2/Pristine\ Packages/ .

Then symlink them back into place!

 $ cd ~/Library/Application\ Support/Sublime\ Text\ 2/
 $ ln -s ~/Dropbox/settings/Sublime\ Text\ 2/Installed\ Packages Installed\ Packages
 $ ln -s ~/Dropbox/settings/Sublime\ Text\ 2/Packages Packages
 $ ln -s ~/Dropbox/settings/Sublime\ Text\ 2/Pristine\ Packages Pristine\ Packages

Step 3: Install Cool Packages!

To install a package, open the package manager (⌘+SHIFT+P), type “Install Package”, hit enter, then type the package name and enter.
Check out these packages:

  • SideBarEnhancements
  • AllAutocomplete
  • TrailingSpaces
  • SublimeLinter
  • Git

Step 4: Configure Settings (all of these go into Sublime’s User Settings: ⌘+,)

  • Tabs and Spaces
    	"tab_size": 4,
    	"translate_tabs_to_spaces": false
  • Ensure Newline at EOF
    "ensure_newline_at_eof_on_save": true
  • Trim trailing whitespace on save
    "trim_trailing_white_space_on_save": true
  • If you use TrailingSpaces, set some sensible settings in Preferences -> Package Settings -> TrailingSpaces:
    	"trailing_spaces_include_current_line": false


Convert SVN Repo to Multiple Git Repositories, the Simple Way

I was faced with a (pretty common) scenario recently: I had been using one giant SVN repository for all of my various projects, and I realized it was time to step into the 21st century and get those projects into separate git repositories. I’ll admit, I was originally hesitant to use git; I thought SVN would be all I ever needed. However, I had to learn it due to my work with Drupal, and after a bit of forced exposure I realized just how nice it was to have the entire repository right there on my computer.

I did a lot of research, and tried a bunch of different ways to convert an SVN repository to multiple git repositories. Here’s what I came up with as the easiest way (this tutorial assumes you have git installed and are familiar with the command line). Note that if your SVN has gone through any major re-organizations, this probably won’t preserve the full history, and you’re probably off trying something more complicated. This process also works best with simple SVN setups that don’t have branches (but should work with branches as well).

Step 1: Setup authors-transform.txt
In order to translate the SVN usernames to meaningful git commit/author name+email addresses, we will make a text file that maps the former to the latter. If it’s a personal repo, you probably know the few usernames that had access, and can thus create the file from memory. If not, you might want to use a script to grab all users from the repo. Either way, you want a text file that looks like this:

[old SVN username] = [New Name] <[new@email.com]>

an example:

Tommy = Tommy Goode 
Scott = Scott Mann 

Step 2: Clone a project from the SVN repository into git
This step will be repeated once for each sub-project in the repo. Get yourself into an empty (except for authors-transform.txt) folder and run the following command:
[crayon lang=”sh”]git svn clone [base svn url] –no-metadata -A authors-transform.txt –trunk=[relative/path/to/project/trunk][/crayon]
If you have branches, add --branches=[relative/path/to/project/branches]. Git will do it’s thing, and then BOOM, you have a git repo with all of your SVN commits. Do a simple [crayon lang=”bash”]git branch -rd trunk[/crayon] to get rid of the remote branch reference. You may also want to pack the repo, since as a brand new git repository it has not yet been optimized. [crayon lang=”bash”]git repack -d[/crayon]

Hooray! No more SVN. If you want to push it to a remote repo, just do a
[crayon lang=”bash”]git remote add origin [remote url]
git push -u[/crayon]

Use SVN 1.7 in XCode 4.3+

tl;dr: Skip to the good part!

A while back, Subversion 1.7 was released. It was a major upgrade, and included an entirely new way of internally keeping track of local working copies. Unfortunately, the svn tools in XCode 4 are not compatible with the new format, and thus could not read the status of (or commit) code on the server.

Luckily, someone figured out a way to ‘patch’ Apple’s default SVN files with the new version. I first saw this on StackOverflow, and used it successfully for a few months waiting patiently for XCode to be updated.

Soon enough, there was a new version of XCode! And it was available through the Mac AppStore! And I had to spend a ridiculous amount of time working on my Hackintosh to get it upgraded to 10.7.3 so I could use the new version! …But that’s a story for another time.

After installing 10.7.3 and downloading XCode 4.3.1 from the Mac AppStore, I started it and immediately went to the repositories section, expecting to see my working copies listed and ready to be updated and committed. Unfortunately, what I got instead was a bunch of errors and “Cannot connect to repository” messages. I realized that the AppStore verson of XCode included it’s own copies of the SVN binaries, and wasn’t even using the ones that I had patched earlier. After looking a bit further, I realized that the new version of XCode had the SVN binaries packaged inside XCode.app. So how could those be updated to the new version?

The Good Part (AKA How To Upgrade to SVN 1.7 in XCode 4.3.x)

The good news is, upgrading SVN inside the XCode.app package isn’t too different from upgrading the old way.

This assumes you already have SVN 1.7 installed to /opt/subversion. You can get it from WANdisco (scroll down to the Vanilla Subversion section).

First, open Terminal and get an elevated shell using {shell}sudo -s{/shell} and typing in your password.
tommylaptop:~ Tommy$ sudo -s

Then, cd to inside the XCode.app package, to where the SVN binaries are.
[shell]bash-3.2# cd /Applications/Xcode.app/Contents/Developer/usr/bin/[/shell]

Make a backup directory and move the old SVN files into it
bash-3.2# mkdir bup
bash-3.2# mv svn* bup/

Lastly, symbolically link the new files into the package:
[shell]bash-3.2# ln -s /opt/subversion/bin/svn* ./[/shell]

That’s it! Note that this doesn’t seem to work 100% of the time (I still get random error messages sometimes), but it’s still nice to see the working copy status next to each file in the project, and be able to commit/revert from inside XCode. Also note that an update to XCode could break this – hopefully, by upgrading the SVN components *cough* – but the same procedure will probably work to restore SVN 1.7 functionality if the next update fails to deliver.

JQTouch and CSS position: fixed; Issue on iOS 5

I recently finished a marathon CSS debugging session, where I was working on figuring out why a simple position:fixed; wasn’t working in my iOS 5 (the first iOS version to support the property) project that also included a (potentially outdated version of) JQTouch.

I quickly figured out that I could get it to work if I removed JQTouch from my project, but as that was not an option, I had to delve into the JQTouch files and figure out the issue. Removing the main jqtouch.css file from the page worked also, so I narrowed my search to that file.

I performed what amounted to a log(n) search, commenting out half of the file to figure out which half held the problematic code. I repeated this on the half that fixed the error until I narrowed the culprit to the following lines:

[crayon lang=”css” toolbar=”false” nums=”false”]#jqt.supports3d{-webkit-perspective:1000}
#jqt.supports3d > *{-webkit-transform:translate3d(0, 0, 0) rotate(0) scale(1)}[/crayon]

No part of that looked familiar to me, but since commenting out those 2 lines fixed my problem, I wasn’t too concerned. It appears that supports3d is a class added and used by the JS in jqtouch.js, presumably to make the page look better when it is supported. This also tells me that it’s not necessarily the best way to fix the error (since the supports3d class will still be added by the JavaScript); but again, since it works, I’m not complaining.

Note also that I’m not sure that this is even a complete solution to the issue, because the behavior I observe using this is still suboptimal: the element is fixed during normal scrolling, but if the screen is ‘flicked’, the element scrolls with the screen and then repositions itself when the screen comes to a stop.

Run Trac alongside another CMS

Recently I was setting up SVN and Trac on one of my domains. The domain was already running Drupal in the root directory (accessible at mysite.com), and the Trac installer was configured to place trac in mysite.com/trac. However, Drupal was picking up all web requests for /trac and redirecting them to a 404 error page. I found out that some small tweaks needed to be made to the Drupal-provided .htaccess file at the root of my site.

How to Fix 404 error when Trac is in a
subdirectory of another CMS

Note: This should work with many CMS/frameworks such as Drupal, WordPress, CakePHP, etc.

The file to edit is .htaccess, which should be in the root of your CMS installation. Make a backup before modifying this file!

Open the file and look for the section beginning with [crayon nums=”false” toolbar=”false”]RewriteEngine On[/crayon]

There should be one or more RewriteCond statements followed by a RewriteRule. On a new line right before the RewriteRule, add the following (assumes Trac is located in /trac)
[crayon nums=”false” toolbar=”false”]RewriteCond %{REQUEST_URI} !^/trac*[/crayon]
This line tells the rewrite engine to ignore any requests for /trac.

Here is the standard Drupal (6) .htaccess file (starting at line 73) with the line above added in and highlighted.

[crayon start-line=”73″ marking=”true” mark=”35″ toolbar=”false”]
# Various rewrite rules.

RewriteEngine on

# If your site can be accessed both with and without the ‘www.’ prefix, you
# can use one of the following settings to redirect users to your preferred
# URL, either WITH or WITHOUT the ‘www.’ prefix. Choose ONLY one option:
# To redirect all users to access the site WITH the ‘www.’ prefix,
# (http://example.com/… will be redirected to http://www.example.com/…)
# adapt and uncomment the following:
# RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
# RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
# To redirect all users to access the site WITHOUT the ‘www.’ prefix,
# (http://www.example.com/… will be redirected to http://example.com/…)
# uncomment and adapt the following:
# RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
# RewriteRule ^(.*)$ http://example.com/$1 [L,R=301]

# Modify the RewriteBase if you are using Drupal in a subdirectory or in a
# VirtualDocumentRoot and the rewrite rules are not working properly.
# For example if your site is at http://example.com/drupal uncomment and
# modify the following line:
# RewriteBase /drupal
# If your site is running in a VirtualDocumentRoot at http://example.com/,
# uncomment the following line:
# RewriteBase /

# Rewrite URLs of the form ‘x’ to the form ‘index.php?q=x’.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !^/trac*
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

We also have to add in a line of code to allow Trac to handle basic http authentication. At the top of .htaccess, below
[crayon nums=”false” toolbar=”false”]
# Make Drupal handle any 404 errors.
ErrorDocument 404 /index.php

add the following code:
[crayon nums=”false” toolbar=”false”]
# Make Trac handle 401 errors
ErrorDocument 401 /401.html

You then need to create the file 401.html in your root directory. It can be empty, or you can add a message letting the user know that authentication is required.

Voila! Trac now works in a subdomain of your existing CMS.

Important note: Changes to .htaccess will probably be wiped out on any subsequent update to the CMS. Make sure you keep a backup copy once Trac is working, or just follow these instructions after each update.




Dropbox is easily one of my favorite programs. I regularly use 3 computers, plus a virtual machine, plus an iPhone, and before Dropbox I was carrying everything on a USB thumb drive and juggling multiple revisions of documents across all of my devices. With Dropbox, I can take for granted not only having the most recent version of all documents handy, but that it is all backed up in the “cloud” for safety. Sharing a folder with another Dropbox user is drop-dead simple as well. Add to that the ability to view previous revisions, and a great group of developers and support personnel, and Dropbox has a winning formula in my book! I wholeheartedly recommend Dropbox to anyone who uses multiple computers, a mobile device, or needs to be able to access their documents from anywhere via the internet.

Dropbox’s free plan gives 2GB of space, and can be upgraded by referring people, completing some basic account tasks, and/or paying money.

Click here to sign up for Dropbox.
disclaimer: this is my referral link, and you and I both will receive extra space if you use it to sign up.