Two months ago, I started to create xcenv, a tool for grooming your Xcode environment. It is based off the Ruby environment manager rbenv, and works by using version numbers instead. Creating the tool, was really easy, once I recognized that I just had to replace the Ruby logic with Xcode logic in rbenv.
Origin Story
Upgrading your development environment is not so simple when you’re working on real shipping projects. You never know when you have to roll back to an old commit to make a hot-fix or track down a bug, but you don’t want to have to track down what you need to get the project to run. This is similar to my previous post Committing Your Candidate.
For the past 6 months, I’ve been working on an iOS project where we had to upgrade from Xcode 6.4 to Xcode 7.2 and then to Xcode 7.3.1. We wanted to make the change after we shipped the next release because we were just building the Release Candidate stage and didn’t want to introduce the risk. Long story short, we have been having to maintain both Xcodes in our development process for the past 4 months.
One of the biggest problems with maintaining multiple Xcodes, is building on the command line, specially for Jenkins. To solve the problem, we started to commit a file in the branches that pointed Jenkins to the desired Xcode application path. When we start a build, we set the environment variable DEVELOPER_DIR to the contents of the file. The limitations of this solution, is that when we wanted to rename the Xcode application file names, we broke the builds until the file was updated.
How It Works
Xcenv works by inserting a shim into PATH before the real tool would be used. Originally I was hoping just to have to shim xcrun, as it can be used to run every Xcode command line tool desired. However after looking at each file in /usr/bin related to Xcode, I found each is hardcoded with a library related to xcode-select. So to get xcenv to work, I had to shim each tool for Xcode.
Each shim does the same thing, it first figures out what Xcode version you want to use and then sets the DEVELOPER_DIR environment variable and triggers the desired command. The Xcode version is found either by the directory tree, the global version, or just uses the system settings.
Why Not XVM?
A few developers have asked why not base this off the tool RVM and to not start the war over RVM over rbenv, but ultimate decision came based on how RVM, handles changing Ruby versions. RVM alters the cd
command in the shell to watch for when it should change the Ruby version. If xcenv, wanted to do this same mechanism, the two tools would not work together well.