Blog

    Git Hook: Core Data Model Validation

    November 29, 2014

    Committing an unversioned changed to your Core Data model can be a major problem that frequently results in a crash. For this reason, I’ve created the following git commit hook which will validate model updates. Validation uses the following rules:

    • Don't allow modified Core Data models, just adding new ones.
    • If a new model is added, make sure the current model version number has changed. Note that it only checks to see if there was a change and does not attempt to match the version number. This is intended to allow initial commits which may contain many different model versions at once.
    • Attempt to compile the model to make sure there aren't any obvious errors like missing types, etc.
    #!/bin/sh
    
    MODIFIED_XCDATAMODELS=`git diff --staged --name-status|sed -E '/^M[[:space:]]+/!d;/\.xcdatamodel\/contents/!d;s/^M[[:space:]]+//'`
    
    # Modified Models
    if [ ! -z "$MODIFIED_XCDATAMODELS" ]; then
      echo A modified Core Data model was found: `basename $MODIFIED_XCDATAMODELS`
        echo Use model versioning instead of changing models directly.
        exit 1
    fi
    
    # Added Models
    git diff --staged --name-status|sed -E '/^A[[:space:]]+.*\.xcdatamodel\/contents/!d;s/^A[[:space:]]+//;s/\/contents//' | while read MODEL; do
        # Check for an accompanying change to ".xccurrentversion".
        VERSION_UPDATE=`git diff --staged --name-status "$MODEL/../.xccurrentversion"`
        MODEL_NAME=`basename "$MODEL"|sed -E 's/\.xcdatamodel$//'`
    
        if [ -z "$VERSION_UPDATE" ]; then
            echo Model added without a version update: $MODEL_NAME
            exit 1
        fi
    
        TEMP_DIR=`mktemp -d /tmp/momc.XXXXXX`
        TEMP_MOMD="$TEMP_DIR/$MODEL_NAME.momd"
    
        # Make sure it compiles without error.
        xcrun momc "$MODEL" "$TEMP_MOMD"
        MOMC_RESULT=$?
        rm "$TEMP_MOMD"
        rmdir "$TEMP_DIR"
    
        if [ "$MOMC_RESULT" -ne 0 ]; then
            echo Error compiling model: $MODEL_NAME
            exit 1
        fi
    done

    You can install this hook in the normal way, which is to say you should copy it to.git/hooks/pre-commit and make it executable with chmod +x .git/hooks/pre-commit. Happy modeling!

    ipa2itc: Dead Simple iTunes Connect Automated Uploads

    October 31, 2014

    I made what I believe to be the simplest way to upload binaries to iTunes Connect and posted it to github here: https://github.com/emlynmu/ipa2itc

    This will support uploading binaries for Apple's TestFlight using continuous integration. All configuration information about the app is derived so all you need is a binary and your iTunes Connect username/password. The password can be stored in the keychain so you may not even need that.

    Usage

    Best Case Scenario

    $ ipa2itc -u user@server.com MyApp.ipa

    In this scenario you already have your iTunes Connect password on your keychain. OS X will ask you to give permission to ipa2itc to read it.

    Adding your iTunes Connect password to your keychain

    If your iTunes Connect password is not in the keychain, or not in the right keychain (the iCloud keychain won’t work due to entitlements), you can add it with these steps:

    1. Open the Keychain Access application from /Applications/Utilities/Keychain Access.app.
    2. With the login keychain highlighted, click File->New Password Item from the menu.
    3. Use the following settings for your password item:

    Keychain Item Name: https://itunesconnect.apple.com
    Account Name: your iTunes Connect username
    Password: your iTunes Connect password

    Living Dangerously

    If you for some reason can’t get your password into the keychain, or can’t get it into the right keychain in the case of continuous integration, you can always supply your password at the command line. This is not recommended.

    $ ipa2itc -u user@server.com -p yourpassword MyApp.ipa

    Installation

    • Download the installer package.
    • Run through the installer.
    • Application binary will be installed to /usr/local/bin/ipa2itc.
    • You may need to add /usr/local/bin to your path if it is not already present.

    How It Works

    Like many other app uploader, ipa2itc relies on Apple’s iTMSTransporter binary buried in the Xcode package. It finds the active version of Xcode using the xcode-select command line tool. If it can’t find Xcode you may need to use xcode-select to choose the active version like this:

    $ sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

    iTMSTransporter needs a lot of information about your application before you can upload it. ipa2itc finds all of this information for you by inspecting the .ipa package and looking information up directly on the iTunes Connect website.

    Cocoa Coding Style Enforcement

    December 30, 2013

    Some time back, the New York Times's iOS team published Objectively Stylish, an Objective-C style guide. You've probably worked on a project before where every team member has their own unique coding style. While one can argue the relative merits of various stylistic choices, it's hard to argue against having a uniform style. For this reason, most projects should just pick a style and stick with it. But how can you make sure your chosen coding style is being maintained? Through the use of several common open source tools, you can easily enforce your project's coding style.

    The main tool that all of this revolves around is Uncrustify. Uncrustify is a highly customizable code beautifier for C-like languages. Being primarily a command line utility, the easiest way to install and integrate Uncrustify into Xcode is to install the BBUncrustifyPlugin-Xcode plugin. You can download the latest release as a zip file here. After downloading and unzipping the plugin, simply move UncrustifyPlugin.xcplugin into ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins and restart Xcode.

    After restarting Xcode you should notice several new options in the Edit menu:

    Xcode edit menu

    These new options should be fairly self explanatory. They allow you to beautify code with various degrees of scope within Xcode. BBUncrustifyPlugin-Xcode comes with a default set of style standards. If you want to customize these standards you can either go digging in Uncrustify’s configuration file or you can use UncrustifyX’s easy-to-use graphical user interface.

    Customizing Your Style

    UncrustifyX can act as a standalone graphical interface to beautify your code, but its ability to easily customize Uncrustify’s configuration file is of greater interest to us. You can download the latest UncrustifyX release here. After unzipping UncrustifyX and moving UncrustifyX.app to /Applications you will get a fourth new option added to Xcode’s Edit menu:

    Xcode edit menu

    Pick this option and you should be presented with a modal telling you that a custom configuration was not found and giving you the option to create one. Proceeding will copy the bundled Uncrustify configuration file to ~/.uncrustifyconfig and open it in UncrustifyX for customization. Let’s compare some of the recommendations from the NYTimes Objective-C Style Guide to the options provided in UncrustifyX. First, let's take a look at what they have to say about spacing.

    • Indent using 4 spaces. Never indent with tabs. Be sure to set this preference in Xcode.
    • Method braces and other braces (if/else/switch/while etc.) always open on the same line as the statement but close on a new line.

    For example:

    if (user.isHappy) {
    //Do something
    }
    else {
    //Do something else
    }

    Indent using 4 spaces can be set by selecting Indent with tabs to 0 meaning “spaces only”. You’ll also notice that UncrustifyX has a built-in documentation viewer. You can click the “i” button next to each option to read what it does and what its valid values are.

    The default brace style configuration included with BBUncrustifyPlugin-Xcode should already match the style guide. If you’re interested how this is accomplished the following options are set to “Remove”:

    • Newline between function signature and open brace
    • Newline between if and open brace
    • Newline between else and open brace
    • Newline between else if and open brace
    • Newline between while and open brace
    • Newline between switch and open brace

    You can switch your brace indent style to Allman style by changing all of the preceding options to “Add”. Now we'll take a look at the style guide's recommendations for conditionals.

    Conditional bodies should always use braces even when a conditional body could be written without braces (e.g., it is one line only) to prevent errors. These errors include adding a second line and expecting it to be part of the if-statement. Another, even more dangerous defect may happen where the line "inside" the if-statement is commented out, and the next line unwittingly becomes part of the if-statement. In addition, this style is more consistent with all other conditionals, and therefore more easily scannable.

    For example:

    if (!error) {
        return success;
    }

    Not:

    if (!error)
        return success;

    or

    if (!error) return success;

    You can force braces to be added for single line statements by setting the following options to "Add":

    • Braces on single-line do statement
    • Braces on single-line else statement
    • Braces on single-line for statement
    • Braces on single-line while statement

    What no if statement? As of the time of this writing, there is a mislabeling in UncrustifyX. The option labeled "Braces on single-line else statement" also covers if statements.

    When you're happy with your rules, you can save them by choosing "Export". You should save your configuration file to .uncrustifyconfig in your home directory. OS X will warn you that the file will be hidden because of the dot but you can safely click "Use '.'" to save anyway.

    Enforcement

    What we have so far is a code beautifier with some customized rules. This is great, but our real end goal is to make sure that code is never commited which violates these rules. For the enforcement of our rules, we will employ the use of git hooks. GitHub user David Martin has already done the hard work for us of creating a pre-commit-script that does exactly what we want located here. Save the file at the path .git/hooks/pre-commit in the git repository you want to add style enforcement to. Open the pre-commit script you just saved in an editor, because you'll need to modify the following variables from the settings section.

    Setting Value
    UNCRUSTIFY "/Applications/UncrustifyX.app/Contents/Resources/uncrustify"
    CONFIG "$HOME/.uncrustifyconfig"
    SOURCE_LANGUAGE "OC"
    FILE_EXTS ".c .h .cpp .hpp .m .mm"

    You can use the uncrustify binary that comes with UncrustifyX assuming you copied UncrustifyX to /Applications. You can also easily install a standalone uncrustify executable using Homebrew by executing:

    $ brew install uncrustify

    In which case, you'll want to set UNCRUSTIFY to /usr/local/bin/uncrustify. You will also want to make sure your script is executable by executing:

    $ chmod 755 .git/hooks/pre-commit

    The script has a dependency on another script called canonicalize_filename.sh which you can download here. Copy canonicalize_filename.sh into .git/hooks/canonicalize_filename.sh and set its permissions to executable as well.

    $ chmod 755 .git/hooks/canonicalize_filename.sh

    Now that everything is in place, we're ready to break some rules and hope to get caught. I'll try to commit the following simple test.m file which violates the style standards we set above.

    #import <Foundation/Foundation.h>
    
    int main(int argc, char *argv[]) {
        @autoreleasepool {
            NSUInteger i = 1;
    
            if (i < 1)
                NSLog(@"Hello");
    
            if (i < 2)
            {
                NSLog(@"World");
            }
        }
    }

    When attempting to commit, you should get an error similar to what follows.

    $ git add test.m 
    $ git commit -m 'Test commit'
    Parsing: test.m as language OC
    
    The following differences were found between the code to commit and the uncrustify rules:
    
    --- a/test.m    2013-12-29 04:01:46.000000000 -0500
    +++ b/test.m    2013-12-29 04:24:42.000000000 -0500
    @@ -1,15 +1,15 @@
     #import <Foundation/Foundation.h>
    
     int main(int argc, char *argv[]) {
    -    @autoreleasepool {
    -        NSUInteger i = 1;
    -        
    -        if (i < 1)
    -            NSLog(@"Hello");
    -        
    -        if (i < 2)
    -        {
    -            NSLog(@"World");
    -        }
    -    }
    +   @autoreleasepool {
    +       NSUInteger i = 1;
    +
    +       if (i < 1) {
    +           NSLog(@"Hello");
    +       }
    +
    +       if (i < 2) {
    +           NSLog(@"World");
    +       }
    +   }
     }
    
    You can apply these changes with:
     git apply /tmp/pre-commit-uncrustify-1388309082.patch
    (may need to be called from the root directory of your repository)
    Aborting commit. Apply changes and commit again or skip checking with --no-verify (not recommended).
    $

    This pre-commit script is very helpful in that it generates patch files to make the necessary changes for you. In this case, I can follow the error's recommendation and apply the patch.

    $ git apply /tmp/pre-commit-uncrustify-1388309082.patch

    Your patch file will have a different random filename so just refer to the error output. After applying the patch you should be able to inspect the test.m file and see that it has been beautified and now conforms to the style rules.

    #import <Foundation/Foundation.h>
    
    int main(int argc, char *argv[]) {
        @autoreleasepool {
            NSUInteger i = 1;
    
            if (i < 1) {
                NSLog(@"Hello");
            }
    
            if (i < 2) {
                NSLog(@"World");
            }
        }
    }

    After applying the patch, you should now be able to commit to the repository without an error. Congratulations, your style is now being enforced in your local git repository. If you want to enforce the style on a shared git repository, you can follow the exact same procedure, except instead of naming your git hook script .git/hooks/pre-commit, you'll name it .git/hooks/pre-push and it will be located on the remote server instead of your local repository. In this scenario, you'll be able to commit style violations, but the server will not accept them being pushed to it.

    Internet Plus

    November 5, 2013

    HBO Go Logo

    An article has been circulating around the internet recently which describes a mythical cord cutter's dream package, an internet only package which also includes access to HBO Go. Normally to use HBO Go you have to have a cable plan, but this plan promises streaming access to HBO for the same price as an internet only plan. If you read the fine print it's actually an extremely basic cable plan which also includes HBO which is masquerading as a cord-cutter plan, but who cares if the price is right.

    The other fine print on this is that it's an experiment only available in some markets. I'm happy to report that I am in one of those markets and it is awesome. The plan was not listed on the Comcast website. I had to call twice and talk to different people describing the plan in different ways (e.g., by price, speed, etc). They finally found it and it ended up costing me $5 extra per month to get streaming access to HBO.

    There are other response articles circulating about how this is not what it seems because the price listed is an introductory price for new customers, but isn't that how every cable plan is? The bottom line is, in my market it's $39.99 if you're a new customer, $69.99 if you're not, you get 25Mbps internet, access to HBO Go, and access to Comcast's Streampix service. HBO Go is viewable from many devices including Apple TV, Roku, iPhones, iPad, Android devices, and of course desktop computers.

    RIP Google Reader, Long Live Feed Wrangler

    March 19, 2013

    Google Reader Logo

    I've been a longtime user of Google Reader. To back up even further, I've been an even longer time user of RSS. The news of Google deciding to shutdown Reader was a big disappointment to me. Now admittedly, Google Reader is a niche product that Google never quite figured out how to fully monetize, but most of what Google does is a little vague on the monetization details. Google has been shutting down a lot of products, but this should probably be seen more as a sign that they are growing up and learning to focus their efforts. I still haven't quite figured out what Google Glass says about them, but I can't help think Adam Lisagor is onto something when he called it a Segway for your face.

    After hearing the news that David Smith has been working on a Google Reader replacement, I've decided to put aside my disappointment and see Reader's demise as an exciting opportunity to shake things up in the world of RSS aggregation. The one thing I don't want to be, is the one guy still using Eudora) while everyone else has moved on to better things. Although the details are pretty sparse, I'm still excited about Smith's Feed Wrangler. The reason I'm excited about it is that Smith hit all the right notes in his explanation of why he decided to create an RSS aggregator on his podcast Developing Perspective.

    I use Reader almost strictly as a syncing back-end. There are other projects which will seek to recreate Reader's syncing API, but this is probably the wrong approach since it was never intended to be a public API. There are a lot of good apps that interface with Google Reader and I change clients every few months. Smith has said that he'll launch Feed Wrangler with clients for iOS and OS X and will make an API available for 3rd party clients. This exactly matches the way I currently use Google Reader.

    The problem with most traditional RSS readers is they treat RSS like email. What I want from RSS is the ability to aggregate a large number of sources, not miss anything important, but not have to take an action for every single story that appears in a feed. The biggest mistake that most RSS readers make is to use an unread count badge. There is a lot of interesting stuff going on in the space of reformatting RSS content to look more magazine-like. Flipboard gets a lot of stuff right, but isn't in itself a sync framework.

    Taking a cue from App.net, Feed Wrangler will explore a fresh new monetization concept called actually paying for stuff on the internet. In general, I agree with the concept that "if you're not paying for the product, you are the product." This is certainly true in the case of Facebook. We'll have to see exactly what the pricing is like for final judgment. App.net eventually went to a freemium model, which I believe works well for software products with a social component.

    There are of course a lot of other alternatives to Google Reader which already exist and are popping up to fill the void so it's probably still too early to call a winner. So how will I read my feeds in the meantime? I'm using Google Reader because it isn't July 1st yet! Also, did you know they open-sourced Eudora?