Sunday, May 22, 2011

PhantomJS and QUnit Hello World

I'm starting to develop a lot of meaty javascript and I've finally reached my snapping point for endlessly clicking refresh in a browser. My current project makes heavy usage of SQLite on the client-side, so I needed something fairly sophisticated for running the tests. Enter PhantomJS, a headless WebKit browser. My project is also completely in JQuery, so QUnit seemed like a good fit as it's the testing framework used for JQuery itself.

Installing PhantomJS


The suggested install steps worked great for me. First, get the source:
git clone git://github.com/ariya/phantomjs.git

The Qt build tools must also be installed, which was a snap on OSX. Download the build tools from http://qt.nokia.com/. Once installed simply run:
qmake -spec macx-g++ && make

And then add phantomjs/bin/phantomjs.app/Contents/MacOS/phantomjs to your path.

Installing QUnit


Nothing more than getting the source:
git clone http://github.com/jquery/qunit

Now just copy the qunit directory to your web directory. I then added a very simple qunit test directly in an HTML file and then opened it in my browser:
<link rel="stylesheet" href="qunit/qunit.css">
<script src="qunit/qunit.js"></script>
<script>
test("hello", function() {
ok(true, "world");
});
</script>
<h1 id="qunit-header">QUnit Hello World</h1>
<h2 id="qunit-banner"></h2>
<ol id="qunit-tests"></ol>


Headless Hello World test


Now that phantomjs and qunit are both installed and working it's time to mix the two together. I was in the process of writing a simple test runner, but then I came across https://gist.github.com/796548, which did exactly what I wanted. After downloading that running a headless test was as simple as:
phantomjs testrunner.js file://`pwd`/index.html

The point of all of this was/is to develop not only unit tests, but also full integration tests using SQLite in the browser. Details on the full integration tests to come in a later post.

Tuesday, February 22, 2011

OS X Package Management Evolution

Having only a few remaining gigs of free space I've been getting desperate. Everything that can be moved off to an external drive has been. I started to dig into two package management systems that I realize I rarely use any more: Fink and MacPorts.

Removing Fink


Fink has been a good package manager, but I've found the pre-compiled packages less useful for my purposes and I haven't been using it as much since I haven't had to open an X11 application in a long time. It seems like software versions are always a few revs back and I never really got familiar with how things are organized so it's a black box I'm happy to get rid of. It turns out removing fink is a snap:

sudo rm -rf /sw


This removed a bunch of unused stuff, almost 10Gb! Something that easy to remove and well-documented can't be all bad though...

Removing MacPorts


MacPorts is much like Fink, but instead of pre-compiled packages it is built on your system after download. I like this approach, but I still haven't been using it much lately. Removing MacPorts is also really easy. First remove all your installed port files:

sudo port -f uninstall installed


and all the other remnants:

sudo rm -rf /opt/local


There are a number of other directories that the official uninstall documentation recommends, but they didn't really apply to my system.

Now What?


I'm always trying to stay current on the latest technologies, even though I know sometimes the next great thing is nothing more than churn. I randomly came across a cool little utility that I wanted to install (pianobar - a command line interface to Pandora) and the instructions I came across were raving about using Homebrew. It seems like a nice, simple, and well-contained package manager that puts everything where I would anyway (in /usr/local/). Installing couldn't be easier:

curl -L http://github.com/mxcl/homebrew/tarball/master | sudo tar xz --strip 1 -C /usr/local


This puts "brew" in /usr/local/bin. Super easy to use, for example here's how I installed pianobar:

sudo brew install libao faad2 libmad
sudo brew install pianobar


I can see all my new packages happily living in /usr/local/Cellar. Nice.

Thursday, February 3, 2011

Installing MySQL 5.5.8, Apache 2.2.17, and PHP 5.3.5 on Snow Leopard

This was way more of a struggle than I was looking for, especially compiling PHP, so I thought I'd share what worked for me in case somebody else runs into the same problems. Initially, I just hoped to update PHP 5.2.9 to 5.3.5, but I immediately ran into issues so I just updated everything. This was all for an effort to get an instance of SugarCRM 6.1.1 running and it would have been easier to just grab their FastStack installers (http://www.sugarcrm.com/crm/download/sugar-suite.html#installers), but I have other PHP/Apache projects I need to support.

Updating to MySQL 5.5.8

Super easy as I had MySQL 5.0.45 installed previously. Just went to http://www.mysql.com/downloads/ and grabbed the tar.gz file. After mysqldump'ing my old databases I simply ran these steps:

sudo mv ~/Downloads/mysql-5.5.8-osx10.6-x86_64.tar.gz /usr/local
cd /usr/local/
sudo tar -xvf mysql-5.5.8-osx10.6-x86_64.tar.gz
sudo ln -s /usr/local/mysql-5.5.8-osx10.6-x86_64 mysql
cd mysql
sudo chown -R _mysql .
sudo chgrp -R _mysql .
scripts/mysql_install_db --user=mysql
sudo chown -R root .
sudo chown -R _mysql data
sudo /usr/local/mysql/bin/mysqld_safe --user=mysql

I then reimported my data by opening a mysql prompt, creating the database, exiting, and then reimporting my data with mysql -u root -p db name < mysqldump file

Installing Apache 2.2.17

I was upgrading from Apache 2.2.5, but I don't use a lot of compiled modules so this was also straightforward. First grab the latest apache at http://httpd.apache.org/download.cgi Then do:

sudo su
mv ~/httpd-2.2.17.tar.gz /usr/local/src
cd /usr/local/src
tar -xvf httpd-2.2.17.tar.gz
cd httpd-2.2.17
./configure --prefix=/usr/local/apache2
make
sudo make install

This puts everything in /usr/local/apache2.


Installing PHP 5.3.5

This was the biggy and the reason for this post. I use a number of PHP modules: apxs, mysql, zlib, curl, mbstring, soap, openssl, and iconv. iconv was the initial pain.

Updating iconv

First, get the latest PHP release http://www.php.net/downloads.php. I originally was trying to configure with this (note this is stored in config.nice so I tend to edit that directly rather than typing these long strings on the command line):

./configure' \
'--with-apxs2=/usr/local/apache2/bin/apxs' \
'--with-mysql=/usr/local/mysql' \
'--enable-mbstring' \
'--with-zlib' \
'--with-iconv=/sw' \
'--with-curl=/sw' \
"$@"

This immediately spit out:

checking for iconv support... yes
checking for libiconv in -liconv... no
checking for iconv in -liconv... no
configure: error: Please reinstall the iconv library.

This config definitely used to work (I have a PHP 5.2.9 install to prove it), but one of the OS updates must have changed something somewhere. I'm pretty sure I previously installed iconv with fink, but I've sort of given up on using it all the time in favor of compiling things myself. I got make to run through by changing '--with-iconv=/sw' to use '--with-iconv=/usr', but then immediately failed with this:

php5.bundle libs/libphp5.so
Undefined symbols:
"_libiconv_open", referenced from:
__php_iconv_strlen in iconv.o
_php_iconv_string in iconv.o

I continued to hunt and peck for awhile and did a bunch of mindless trial and error. Here's what eventually worked for getting through iconv (I had more problems, which I fixed below):


  1. Download a new iconv at http://www.gnu.org/software/libiconv/#downloading. After getting the software and extracting it I ran:
    ./configure --prefix=/usr/local
    make
    make install
  2. I had to manually edit one of PHP's files, "php-5.3.5/ext/iconv/iconv.c" changing
    #if defined(HAVE_LIBICONV) &amp;&amp; defined(ICONV_ALIASED_LIBICONV)
    #define iconv libiconv
    #endif
    to
    #if defined(HAVE_LIBICONV) &amp;&amp; defined(ICONV_ALIASED_LIBICONV)
    #define iconv iconv
    #endif
  3. I then modified the configure to contain '--with-iconv-dir=/usr/local'

This got the iconv portion working, but I immediately ran into library issues with mysql.

Fixing MySQL

Here was my initial error:

libs/libphp5.bundle libs/libphp5.so
Undefined symbols:
"_res_9_dn_expand", referenced from:
_php_parserr in dns.o
_php_parserr in dns.o

This was a linker issue that was solved by making a few additions to the configure command in config.nice:

CFLAGS='-arch x86_64' \
CXXFLAGS='-arch x86_64' \
LIBS='-lresolv' \
'./configure' \
'--with-apxs2=/usr/local/apache2/bin/apxs' \
'--with-mysql=/usr/local/mysql' \
'--with-iconv=/usr/local' \
'--enable-mbstring' \
'--with-zlib' \
'--with-curl=/sw' \
"$@"

Immediately ran into another error, which was, thankfully, the last hurdle.

libs/libphp5.bundle libs/libphp5.so
Generating phar.phar
dyld: Library not loaded: libmysqlclient.16.dylib
Referenced from: /usr/local/src/php-5.3.5/sapi/cli/php
Reason: image not found
make: *** [ext/phar/phar.phar] Trace/BPT trap

I was able to fix the "make" step by adding "/usr/local/mysql" to my DYDL_LIBRARY_PATH, but "make install" then failed:

Installing PEAR environment: /usr/local/lib/php/
dyld: Library not loaded: libmysqlclient.16.dylib
Referenced from: /usr/local/src/php-5.3.5/sapi/cli/php
Reason: image not found
make[1]: *** [install-pear-installer] Trace/BPT trap
make: *** [install-pear] Error 2

Much more unsuccessful hunting and pecking insued, followed by figuring out the path of mysql shared library was missing. Here was the initial otool output:

$ otool -DX /usr/local/mysql/lib/libmysqlclient.16.dylib
libmysqlclient.16.dylib

Which I fixed by running:

$ sudo install_name_tool -id /usr/local/mysql/lib/libmysqlclient.16.dylib /usr/local/mysql/lib/libmysqlclient.dylib

otool then spit out the full path:

$ otool -DX /usr/local/mysql/lib/libmysqlclient.16.dylib
/usr/local/mysql/lib/libmysqlclient.16.dylib

This was the ticket for me. No doubt I glossed over all the root causes of these problems. Don't forget to run make clean. Whew!