Keith Smiley - Who?

Objective-C on Travis-CI

Recently Travis added support for Objective-C and there for OS X and iOS projects for continuous integration testing. I gather that people have previously done this with self-hosted dedicated Jenkins machines but since Apple is so aggressive about dropping support for previous versions of the OS it seems like a pain to have to replace your build server every few years. Enter Travis, a great hosted continuous integration server that hosts a huge amount of open source projects. I figured with this new support I could host some of my smaller libraries just to set how well it worked. The initial setup process was a bit tedious but I eventually got it to work.

Assumtions:

  • You have a test framework already integrated with your project (I like Specta/Expecta)
  • You have your project on Github in a public repository. Travis offers a pro account if you'd rather

Steps

  • Create a .travis.yml file in the root of your repository (leading dot is intentional). For many projects a file may just look like:
language: objective-c

By default Travis runs this script for Objective-C projects I was informed on Twitter that the current script that runs Objective-C projects is actually located here. It was originally created by Justin Spahr-Summers here. This script seems to run my projects without any issue, they just occasionally require more initial setup (we'll get to that).

  • Enable your repository in Travis' settings. From your Travis profile page (after signing in with Github) you should see a list of your repositories, you may have to press 'Sync now', where you can switch on the repository you're planning on adding.

  • Configure your project within Xcode. As I assumed above you already have a test target setup. You do have to do a few things in Xcode to make everything work correctly.

    1. Go to 'Manage Schemes' in Xcode. Manage Schemes
    2. Check the 'Shared' box for the scheme that needs to be run. Shared Scheme
    3. Click 'Edit...' in the bottom left and go to your build action. Edit Scheme
    4. On the row of your Tests target check the box in the 'Run' column. Run Test
  • At this point for a simple project or a project using CocoaPods you should be good to go. If Travis finds a Podfile in the root of your repository it automatically runs pod install to get your dependencies (from their docs). Otherwise there are a ton of configuration options for your .travis.yml depending on how your repo is setup.

For one of my projects I created a setup.sh file at the root of my repo that looks like this:

#!/usr/bin/env bash

git submodule update --init --recursive
echo "Setting up test frameworks..."
cd Example/Vendor/Specta; rake > /dev/null
cd ../Expecta; rake > /dev/null
echo "Done"
cd ../../../

This script which I run using the before_install: ./setup.sh option in my .travis.yml gets all my submodules, sets up Specta and Expecta and then goes back to the root directory for running. If you just have a few simple steps you can also have multiple before_install actions like:

before_install:
  - cd Example
  - make

You can read more about other Travis configuration options in their documentation.

OS X + ZFS

For a long time people have talked about how horrible HFS+ is. Most notably, in my opinion, Linus Torvalds (the creator of Linux and Git) who said "Their file system is complete and utter crap, which is scary." John Siracusa also wrote about the problems with HFS+ in his 10.7 review along with talking about it on his podcast, Hypercritical in episodes 56 and 57.

The gist of all this really is that Apple needs a new filesystem. It has been a while since Apple had ZFS support on their website for release in Snow Leopard. After which Apple dropped ZFS support because of licensing issues. There had been talks of Apple developing their own file system, although I think that's the wrong way to go. I think Apple needs to approach file systems the way they approached Safari with Webkit. I think they would be best served by picking up a liberally open source file system, such as BTRFS, or grabbing up one of the ZFS ports and continuing development while leaving it open for anyone to use. One of the great things about this approach is exactly what happened with Webkit and Google Chrome. Google decided to use the Webkit engine to make a product that competes with the main developers of the Webkit project. By doing this with a file system other vendors could use the same implementation and therefore increase development and in turn stability of whichever system was chosen (not to mention compatibility).

One thing is for sure. People who understand how integral a file system is want something modern.

Terminal Shortcut in OS X

One of my favorite defaults in some Linux distros is the ability to use CTRL+ALT+T to open a new terminal window. I wanted to enable this same functionality in OS X using Quicksilver. I did this using iTerm 2 but you can do it with the default Terminal if that's what you want.

  1. Enable the Terminal and iTerm2 Quicksilver plugins. Quicksilver plugins

  2. Create a new custom hotkey trigger. Using the Home directory with the action Open Directory in Terminal Quicksilver trigger

  3. Set it's hotkey using the drawer to whatever you want. Quicksilver hotkey

  4. Set your default Command Line Interface Trigger to iTerm (if that's what you want) Quicksilver CLI

You're done! Now you can easily press your hotkey and pull up a new iTerm/Terminal window whenever and wherever.

Automated Google Reader Backups

I spend a lot of time in my RSS Reeder (see what I did there?). I still find Google Reader to be the best and easiest way to manage my subscriptions, although I've been wanting to switch to Fever for a while.

One thing I wanted to do when I launched my new site (the one you're reading) was to have a downloadable up to date export of my Google Reader OPML file (which of course I never did). I looked around for good ways to automate this and I found a simple Python script to do it with (sorry I couldn't find it again for this post). I decided to rewrite it in Ruby and set it up on my server as an automated cron job.

To run the script I came up with use something like:

ruby path/to/googleReaderOPML.rb username@gmail.com SekretPassword

To add it to your crontab (to run every Sunday at 1:01am) use something like:

1 1 * * 7 ruby path/to/googleReaderOPML.rb username@gmail.com SekretPassword
#!/usr/bin/env ruby

#
# => This script will authorize your Google credentials and download your Google Reader subscriptions
# => Usage: ./googleReaderOPML.rb GOOGLEUSERNAME PASSWORD
#

# The required networking shenanigans
require 'uri'
require 'net/http'
require 'open-uri'

require 'rubygems'
# This requires the 'colorize' gem. Install with '[sudo] gem install colorize'
require 'colorize'


# The base Google URLs for callback, authentication, and subscription export
$GOOGLE_URL = "http://www.google.com"
$LOGIN_URL = "https://www.google.com/accounts/ClientLogin"
$READER_URL = "http://www.google.com/reader/subscriptions/export"

# The user agent string, for some reason this is required, feel free to change it
$SOURCE = "keith.so"

# The default output filename, it is automatically overwritten if one already exists
$FILE_NAME = "googlereadersubscriptions.opml"


# Make sure there is the correct number of arguments
if ARGV.count != 2
    # Print the instruction
    puts "Usage: ./#{ File.basename(__FILE__) } USERNAME PASSWORD".red
    exit
end

# Build the request URL
uri = URI.parse($LOGIN_URL)

# Setup the Parameters
params = { Email: ARGV.first, Passwd: ARGV.last, service: "reader", source: $SOURCE, continue: $GOOGLE_URL }

# Add the user-agent string, my website (feel free to replace it) to the headers
headers = { "User-agent" => $SOURCE }

# Encode the parameters into the url
uri.query = URI.encode_www_form(params)

# Create a new NET:HTTP object with the request URL
http = Net::HTTP.new(uri.host, uri.port)

# Require HTTPS without this net/http will not be happy with you
http.use_ssl = true

# Execute the request
request = Net::HTTP::Get.new(uri.request_uri, headers)

# Get the data from the request
response = http.request(request)

# Check for valid response code, should ONLY be 200
if response.code != '200'
    puts "Google returned #{ response.code }, check your username and password".red
    exit
end

# split each token into a different item then load them each into a hash with the key as the token key
auth_hash = Hash.new
response.body.split(/\n/).each do |token|
    split_array = token.split('=')
    auth_hash[split_array.first.downcase] = split_array.last
end

# Create a header hash for the request of the XML file
headers = { "user-agent" => $SOURCE, "cookie" => "Name=SID;SID=#{ auth_hash['sid'] };Domain=.google.com;Path=/;Expires=160000000000", "authorization" => "GoogleLogin auth=#{ auth_hash['auth'] }" }

# Open the URL for the Google Reader export with the setup headers
request = open($READER_URL, headers)

# Open the received XML feeds file
google_reader_file = File.open(request, 'r')

# Read the entire feeds file into 'subscriptions'
subscriptions = google_reader_file.read

# Close the downloaded file
google_reader_file.close()

# Open a new file with the global filename to write to, overwrite it if it exists
subscriptions_file = File.open($FILE_NAME, 'w')

# Verify the file was created
if File.exists?(subscriptions_file)
    # Write the subscriptions to the file and close it
    subscriptions_file.write(subscriptions)
    subscriptions_file.close()

    # Display a success message
    puts "Wrote Google Reader subscriptions to #{ $FILE_NAME }".green
else
    # If the file wasn't created print an error
    puts "Couldn't write to #{ $FILE_NAME } (the process running this script may not have sufficient privileges".red
end

Boredom

Working as a developer full-time can be very exciting. Dealing with new interesting problems gets me up in the morning. But I still find that after a few months of a specific project I find myself less and less interested with it. Not only projects but concepts and languages start to become less interesting. First it was websites then Objective-C then Ruby then C and now who knows. This scares me. At this point in my life I hope to work in this field for my 'career' meaning a significant amount of time. Yet I can't even keep myself working on a single project now, much less one that doesn't interest me.

I typically blame this on the difficulty of the project. As a lone developer I find that most projects I work on are pretty small in scope, since I just don't have the time or people-power to work on anything larger. Therefore I look at most of my projects without interest. I'm not sure what it will take to keep myself engaged and interested on my next project.