Creating a self contained gem installation

My most recent challenge was to create a self contained RubyGem installation for my client. We had been using `gem install testmunk` over NSTask to install the gems to date, however, as we let more and more people try it out we found that a lot of the people got an error while downloading and installing the gems. After a lot of research, we had several options which we could take on forward:

1. Vagrant
2. Omnibus Installer – https://github.com/opscode/omnibus-ruby
3. Tokaido – https://github.com/tokaido

All three of them offered more or less the same thing, a statically compiled version of ruby. The advantage of a statically compiled build is that the build becomes independent of the configuration on the users machine. With Vagrant we were not actually creating a virtual machine, we were just stripping the ruby packaged within its installer.

For my project, I chose Tokaido, mainly because I was dealing with a Cocoa app and they had a fully implemented example already available [https://github.com/tokaido/tokaidoapp]. From this point on, it was fairly easy – I had to build the gems using this statically compiled gem executable and then modify their native extensions to use the environment ruby instead of the path to the version of the ruby used. For this, I opened the native extension (in $GEM_HOME/bin) in a code editor and changed the first line from what ever is there to “#!/usr/bin/env ruby” [without quotes]. This will use the ruby version in the current environment.

Finally, some configurations in my Cocoa app, and my contained gem installation we ready to be deployed! The only disadvantage that I have come across for using the self contained gem install is that I need to source the bash script (SetupTokaido.sh) every time I need to use this contained setup in my terminal. Other than that it has managed to fix all the issues we were having from gem install!

Installing Ruby Gems without ‘sudo’

It was yet another fine day here in Karachi, Pakistan, when I found that the AppleScript I was using to install some gems (with administrator privileges) was no longer working on Mavericks. The script would get stuck, and would never return. I tried a few other combinations, but after some time I gave up and started looking for alternatives. One of the things I have briefly come across before was to install gems without any authentication at all. Although initially it looked very trivial to implement, it took me a few hours to tweak it and get it working right.

The basic idea of installing gems without authentication is very simple, you simply define an install directory which the user has access to (eg. ~/.somegems). However I ran into two issues with that, firstly I had to set the GEMPATH and PATH variables so the gem executable could find the installed gems, and somehow I had to load them in when running NSTask (since NSTask does not load the .bashprofile).

The implementation turned out to be fairly simple. We will use the following command to install the gems:

gem install GEM_NAME –install-dir DIR_PATH —verbose

We will add the following lines in the .bash_profile:

export GEM_PATH=$GEM_PATH:DIRPATH
export PATH=$PATH:DIRPATH/bin

And we are all set! If you are accessing this via NSTask in Cocoa, you can use the following command to make sure these variables are loaded from .bash_profile (or you can add them in the command it self.

NSTask launchedTaskWithLaunchPath:@”/bin/bash” arguments:@[@”-lc”,@”command”]

 

 

Getting battery related information in Cocoa (OSX) development

I recently read a nice Quora answer on shallow charging and wanted to give it a try with my new Macbook Pro Retina. The core problem that I continuously faced was I would forget to plug the charger back in, or take it off and the charge would slide down below 35% or up to 100%. What I need was something that would remind me if the charge percentage would go above or below the limits. I did some research, but could not find anything in the Mac app store or in any of the open source projects. Since I was limited on time, I then setup a crude implementation using automator.

Its been three months since I implemented that crude implementation, and I finally got some time to develop an improved version.  At its core is a simple battery information API [BatteryInfo.h] which queries the system using ioreg tool via NSTask. I have even implemented a simple caching system which reduces the number of NSTask calls to the system.

The ioreg contains a lot of data, which is why I grep out only the things I need. The API can be easily extended by adding the additional keywords in the grep pattern.

The following information is available over the ioreg:

  • “TimeRemaining” = 271
  • “AvgTimeToEmpty” = 271
  • “ExternalChargeCapable” = No
  • “CellVoltage” = (3971,3976,3970,0)
  • “PermanentFailureStatus” = 0
  • “BatteryInvalidWakeSeconds” = 30
  • “MaxCapacity” = 8112
  • “Voltage” = 11917
  • “DesignCycleCount70” = 65535
  • “Manufacturer” = “SMP”
  • “CurrentCapacity” = 6917
  • “LegacyBatteryInfo” = {“Amperage”=18446744073709550084,”Flags”=4,”Capacity”=8112,”Current”=6917,”Voltage”=11917,”Cycle Count”=325}
  • “BatteryInstalled” = Yes
  • “CycleCount” = 325
  • “DesignCapacity” = 8460
  • “OperationStatus” = 58435
  • “ManufactureDate” = 16687
  • “AvgTimeToFull” = 65535
  • “PostDischargeWaitSeconds” = 120
  • “Temperature” = 3094
  • “FullyCharged” = No
  • “InstantAmperage” = 18446744073709550178
  • “Amperage” = 18446744073709550084
  • “IsCharging” = No
  • “DesignCycleCount9C” = 1000
  • “PostChargeWaitSeconds” = 120
  • “ExternalConnected” = No

A word of caution though, calls like isCharging can take a few seconds to update, I still have not been able to figure out why. Thus, should be safe to poll a few times before confirming the change.

Shalby icon

References:
Quora Answer

Project Repo

Malware2.0

A client emailed me today about an issue they were having. The problem was that if they visited their website via Facebook, the website would redirect to a different URL. However when they visited the website directly it worked fine. This took me by surprise for a few seconds, the malware was only acting if the user can from an external link? First thought was that the client’s system was infected by some sort of malware, however, when I tried their link from Facebook, the same thing happened on my end. So the issue was not only on client’s machine, either it was on Facebook (unlikely) or the client’s hosting server was compromised.

So I quickly opened Chrome Inspector and started observing the network tab as I clicked the link on Facebook. There it was, a “301 Moved Permanently” header which redirected the website to the malware website. The next obvious place to check was the .htaccess and bam! there it was:

The code itself is simple and elegant, if the referrer is anyone of the listed above, redirect to the malware URL. The brilliance about this hack is that the probability the client will find out directly is very low, in fact it was probably by chance they clicked on their own link on Facebook and saw this issue (or one of their viewers informed them).

So why did this happen? An unprotected .htaccess. Even if the hosting server was infected, the chances of malware actually having root access is fairly low. Thus, a simple chmod has secured this file from further abuse!

iOS: Distributing your Simulator Build file

A few weeks ago, I wrote a post on how to create an iOS IPA file using the terminal command xcodebuild. You can use use the same command to create an APP file for the simulator, but you can also distribute the APP file which was created when you ran the app in the simulator. All the apps installed in a specific simulator can be found under

~/Library/Application Support/iPhone Simulator/IPHONE_SIMULATOR_VERSION/Applications

Each application is in a directory will a random ID, and inside each folder contains the application data including the APP file. All you need to do is to zip this folder (only the APP file will work too, but then you will need to create the folder structure again when deploying it) and transfer it to the other computer. Then you will simply unzip the folder in the same version of the simulator and it will appear when it starts.

If there is already a folder there with the same name, you can rename this folder by changing the last character. Since the ID is a HEX String anything character between 0-9A-F should work. Running the same APP file on different versions can cause issues, generally when if we run a higher built for version (ie build for iOS 6) on a lower SDK version, it will run fine (not always!), there will be more issues if you try doing the opposite.

Piping output from NSTask (Cocoa)

I was working on one of my Cocoa apps when I realized I need to store the output some NSTasks in a file. I also needed the output inside the application to do some validation. Instead of taking the output and writing it to a file manually, I piped my output to a file directly – and since I was piping it I got the output back in the app as well!

In the code above, two things need to be noticed. First I have added a trivial command (echo Hello), which will only output Hello in the file and return that as well. This is mainly useful if you want constant feedback on the command you have just initiated instead of waiting for the NSTask to return. There could be a more direct way, I have not figured it out yet, so this is what I am using for now. I can then tail the text file to see the status of the task currently running.

Secondly, the command I used to write to a file was “tee”, you can use another equivalent as well. The -a parameter is for appending to the file, if you want it to overwrite (every time you run this task) then remove this parameter.

One major mistake I was making while implementing this was not putting the second argument as a single argument. If there are variables, use NSString’s stringWithFormat to inject the variables and send it as a single argument. Otherwise the pipe will not work.

Also, piping is not to be confused with NSPipe. I am talking about the Unix Pipeline [http://en.wikipedia.org/wiki/Pipeline_(Unix)]

Styling NSTextFields (Cocoa Development)

While working on the a Cocoa app the other day, I had to implement a custom designed NSTextField and a NSSecureTextField. Since I have worked with iOS before, I thought this would be pretty straight but turns out NSTextField != UITextField.

I had four main changes to make to the field, firstly add a light blue background, secondly add a light grey border (the default one available was too dark), third increase width and height and finally add some padding to the text.

The correct way to implement all of the above is to subclass NSTextFieldCell (Yes, NOT NSTextField) and then implement two methods, drawWithFrame:inView: and selectWithFrame:inView:editor:delegate:start:length:. The first one is where you will implement the drawing for the background, the borders and the padding. In the second one you need to redefine the padding once the user selects the textfield. And ofcourse, don’t forget to call the super functions.

To set the subclassed NSTexFieldCell you will need to unfold the TextField object in the Document Outline (the tray with the First Responder object on the left) and then select the cell below. Open the identity inspector from the right sidebar and set the name of your custom class there.

Another note of warning, if you have added a NSSecureTextField, subclassing it’s NSSecureTextFieldCell wont work (the methods are somehow protected). The trick I used here (thanks to some answer on StackOverflow) is to set the textfield object as NSTextField, and set its cell as a NSSecureTextFieldCell.

Here is the implementation code for my cell class:

 

Here is how the final version looks:

Screen Shot 2013-01-01 at 8.31.23 PM

Xcode tricks: Building and Archiving programmatically (from Terminal)

Recently, I was working on a project where I needed to fully automate the client’s Xcode build and archive process. Since my client had a number of apps, and they kept changing, they wanted a dynamic solution (this was being used for testing). So I set about the task and found a few nice command line tools which help with the process.

Beginning from the first of the two staged process, building the application. This is fairly straight forward, just need to pass in the correct parameters, since I wanted a generic script, I went for the simplest technique:

/usr/bin/xcodebuild -target $TARGET -sdk iphoneos -configuration Release

The code above only required me to be present in the project directory, and then extract the target from that project. Extracting the target seems tricky at first, but turned out to be equally trivial:

/usr/bin/xcodebuild -list

The command above lists the targets, schemes and the configurations for the available project. Some neat pattern matching and I had the information I wanted.

Next up was archiving, is slightly tricky, but not very. The command to call here is xcrun, which converts your .app file into a code-signed IPA. The command I used was:

/usr/bin/xcrun -sdk iphoneos PackageApplication -v “${TARGET}.app” -o “${OUTDIR}/${TARGET}.ipa” –sign “${IDENTITY}” –embed “${PROVISONING_PROFILE}”

In my case, this worked fine – however if you want you can drop the –sign and –embed params and it will use the settings already provided in Xcode (or give an error if there are none). You can get the $IDENTITY variable from the Keychain Chain app. Get info for your Developer certificate and the Common Name value is the value for Identity. Make sure you copy paste it properly else you shall run into errors. The $PROVISIONING_PROFILE variable is the path to apps provisioning profile (I was using the * one for all the apps).

And thats it! You can also build using schemes for xcodebuild and there are other ways mentioned in the documentation. Xcode build also has two other nifty functions which I did not use:

xcodebuild -showsdks

xcodebuild -showBuildSettings

Documentation:
xcodebuild: https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html

xcrun: http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/xcrun.1.html

Helpful resource:
http://stackoverflow.com/questions/5640776/xcode4-alternative-way-to-build-ipas

Using DatePicker view in Calabash iOS [iOS6]

Functional testing is getting big, especially since our mobile applications are getting more and more complex. Manually checking the views by hand can be cumbersome and annoying. Calabash is one of the tools available which helps you automate your functional testing. It is based on Cucumber, so writing tests is not very difficult and its flexible functions make it easier to maintain your scripts.

One of the problems I came across recently was to test some dates using UIDatePicker view. There are currently no built in functions available for you to select your date easily, so I ventured out to the web to see if I could find some nice way to do this. I soon came across a full implementation for the date picker, all I had to do was to include the file and make the checks. The gist is linked below:

Gist for controlling the DatePicker

However it turned out that the code did not support the DatePicker in iOS6. This meant I had to see what was wrong and try to fix it. I was still researching when I came across another relavent post, where I found the script which did the work for me. The link to the group and the code I used are pasted below:

Calash Google Group Post

Cocoa: Install using ‘gem’ and Authorization Services (sudo)

I have been working on an app which required me to install another application using the ‘gem’ tool. The bigger problem however, was to run the tool with sudo since that would require the app to prompt the user for the password. My first incline was to implement NSTasks, however, even when using the deprecated Authorization Services technique, it still kept failing. Then I started reading about the new way  (using the Bless helper tool) to getting higher privileges and still could not see a clean way to implement the setup.

After constantly doing research on this for over one week, I stumbled across the solution: use AppleScript to run the ‘sudo gem install’ script. If you add “with authorization privileges” to the script, the OS handles the whole task for getting authorization and running the script. And thats it, three lines of code and the problem was solved! And another good thing is that the call is synchronous, which was good for me since I wanted to wait for the install to finish before moving on.

Here is the code which I used:

ProTip: You can wrap the above code in dispatch_async to free up the main thread, so you can show some loading animation on it until its being done.