Eunichs Archives

June 18, 2007

Eye of the Tiger

For the last 6 months I've been acclimating to OS X on my MacBook Pro. Having a day job that necessitates having a modicum of Windows familiarity and a strong affinity for the most masochistic of Linux distributions (Slackware, for those in the know), I've found in Tiger, the holy grail of my various OS meanderings (albeit a rather battered and less then golden artifact).

Let me say it right now: OS X is not perfect.

Although the idea of having a single place to do open source development with the robustness of UNIX, and an end-user experience second to none, definitely appeals to me, I shy away from outright Mac-boy fanaticism that characterizes most Mac owners. The reasons are simple: there are some glaring deficiencies that irk me and interfere with my rather specific usage of my machine. Notice that I use the word "irk" here. They are truly minor annoyances; not enough for me to flee back Windows/Linux. More on these problems later.

Although Boot Camp has been available for some time now, I've been pleasantly surprised by my utter disinterest in dual booting into another OS. Almost everything I need is available for OS X, and if its not, there is nothing stopping you from finding a suitable alternative in the form of pre-compiled binaries or source code. I subscribe to half-empty-kitchen-sink philosophy so this state of affairs suits me just fine. For those who absolutely must install every visual gadget, this setup may seem less ideal.

There is an additional unexpected benefit in my shift: the Mac really does allow you to focus on the task at hand without all the visual distractions that are common in Windows. In other words, it lets you focus on work. Its not quite as spare as the command line, but pr0n just doesnt't look great in ASCII ;^p. For someone who had a definite preference for the command line, this came as quite a surprise. The uniform application of anti-aliased text as well as the ability to set the back light to the low radiation/stun only setting has noticeably improved my reading speed when using my Mac. Although the Windows equivalent Clear-Text is available for WinXP and newer, there is definitely a difference in their implementations.

A new user may be tempted to splurge on purchasing Mac software and although the base Mac installation is already feature rich, there are just a few necessities missing. Image manipulation, package management for open source software, and a productivity suite for manipulating Microsoft Office documents, are just a few of the shortcomings. Although, iWork addresses a few of these issues, I opted to use software that is available in the widest number of environments (Linux/Microsoft/OSX). The following list fills the software gap on the Mac without compromising anything in terms of quality or functionality:

  • XCode

    Having come from a Microsoft Visual Studio environment, I was pleased by the availability of developer tools for OS X without the additional cost of having to purchase and IDE. Just poke around the installation to CDs to find this great collection of tools. This package is required if you plan on compiling your own programs for OS X.

  • X11

    There are just some applications that do not have native Aqua support. This allows those applications to run side by side with your native OS X apps. Granted these apps do not make use of the Aqua UI elements, but it is a small compromise to run some great software.

  • Parallels

    The environment of last resort. If you can't find a native OS X version and it can't be compiled from source, you will have to rely on a virtualized Windows environment. Surprisingly, things like passable tax software are difficult to find for OS X. Never fear; their is an alternative for these situations as well.

  • Fink

    Portage on steriods. If you don't that open source app on your system, fear not. Fink allows for compiles directly from source with dependency tracking.

  • Open Office

    I've used prior version 1.x of this suite and was always disappointed with the format mangling that inevitably occurred when trying to open native Office docs. This is no longer a problem. Compatibility is almost near perfect; your colleagues will be able to tell that any of your docs where authored outside of Microserfdom.

  • SeaMonkey

    MOAB (Mother of all Browsers). I know that Firefox and Thunderbird are getting all the press at the moment, but harken back to the heyday of Mozilla and you will appreciate the full-featured power of this next-generation online suite. It has all the advantages of its derivative offspring without the misfeaturism which mars the beautiful simplicity found in SeaMonkey. If you value stability over showy spectacle, this is the browser for you.

Now, onto my litany of grievances. As I stated, OS X is not perfect. The following represent a smattering of the issues that I've encountered :

  • Bluetooth

    The idea of a personal area network has been realized with Bluetooth enabled devices and although I love the idea, having used the Wireless Keyboard and Mighty Mouse, the Apple implementation leaves something to be desired. Firstly, their is an ongoing issue regarding bluetooth and sleep/suspend modes. Despite numerous system updates, this issue remains unresolved. Suspending OS X and having it detect the presence, or lack thereof of bluetooth devices should be seamless. Given the relatively small variation present in Apple's product offerings, I would think it would fairly easy to standardize hardware used in their machines. You would think that having a relatively homogeneous hardware platform would translate in to better driver support, but not so. Bluetooth is one of the few components on OS X that can get the system to kernel panic requiring a hard restart.

    In addition, the latest wireless 802.11n updates have introduced signal jitter on connected bluetooth devices when transferring at high throughtput. Since Bluetooth and Wireless BGN share the same frequency spectrum (2.4 Ghz), I suspect the two are related. You ask, why not use the 5Ghz wireless frequency? This brings us to the next of my gripes ...

  • Airport Extreme 802.11.n support

    Theoretically, 802.11n should allow for roughly 500Mbs of wireless throughput in either the 2.4 or 5 Ghz frequency spectrums. This is 5x faster than 100Mb wired Ethernet, or approximately 10x faster that wireless 54G. So much for theory. I bought the Extreme in the hopes that it would improve the speed of my wireless connections by being compatible with the wireless 802.11n adapter in my MacBook Pro. It has improved in speed, if at a more modest 2x increase. Not only that, the latest updates seem to have throttled the top speed to 300Mbs. The network manager reports this throughput despite the fact that my machine is no further than a few inches away from the base station. There are other annoyances as well: Why is channel selection disabled for 802.11n? Why does 802.11n fail at relatively short distances when using the 5Ghz spectrum in my 800 ft/sq space? It literally allows for connectivity only as far as the room where my access point is located Why are there no diagnostic tools to help determine possible causes of signal interference?

    I understand the complexities of creating OS device drivers, but I wish Apple would perform more extensive QA testing before rolling out "fixes" which actually degrade either performance or functionality. At the very least, they should be forthcoming in the compromises between various updates.

  • Lack of network signal strength / wireless info

    This is a no-brainer, and for the record I am already aware of third party utilities that accomplish this task. The problem I have is that this feature should be something built into OS X. A bit of browsing on the Apple Forums reveals a pattern of wireless connectivity issues related to the installation of third party utilities. It stands to reason that avoiding anything that touches the network stack is a "good thing" given the prevalence of these types of issues. At the bare minimum, Apple should introduce a wireless connectivity tool that allows you to view networks within range and their associated security info and signal strength.

  • Hidden files in Finder

    The ability to control which files are displayed in Finder should be customizable. It should not require a Finder/Terminal hack to create/use Unix . files. I understand the necessity to isolate the less experienced user from the Unix internals, but this should be customizable through some mechanism such as a defaults setting. There are a number of legitimate uses for . files and more experienced users should not have to suffer for "perceived" security considerations with no real merit.

    This "feature" was particularly problematic for me when I attempted to relocate my iTunes library to a Samba network share. Unknown to me, OS X stores directory metadata in a readwriteable file .DS_Store. If you prevent the creation of . files on the Samba share, OS X will fail mysteriously. Just keep in mind that . files are useful for normal system operation as well.

  • Runaway processess

    There is no way other than having top run in a Terminal or the Activity Monitor running constantly in the background to know that a system process has failed unexpectedly and is running your CPUs at full throttle. The more astute will notice the Chernobyl-Like-Heat radiating beneath sweaty palms, but the common user will only notice the disastrous after effects of such a system.

    The number of heat related posts in the Apple Forum are staggering. Being able to identify and terminate a runaway process is a sure way to maintain the longevity of your system. There's nothing like having full CPU utilization and both fans running to drain the battery prematurely as well.

    If the two system monitoring alternatives presented above don't appeal to you, I recommend downloading the iStat widget. Not only can you configure it display the most resource intensive processes on you machine, but it also provides a host of additional information such as the temperature of various thermal sensors in your machine.

  • Half-baked updates

    This is a peeve which I carried over from Windows and did not expect to have to deal with in OS X. If updates are to be release for public consumption, at the very LEAST, some regression testing should be done on the updates so that at the minimum they do no harm to an existing system by destabilizing it, and at most, they actually fix the problems they purport to fix. Lateral progress is to be expected sometimes, but retrograde progress is a definite no-no.

  • Safari

    What can I say? As the default browser of OS X, I found Safari somewhat underwhelming. There is nothing here that you can't get with the more capable SeaMonkey. The truly, truly crappy part about Safari is that the system wide browser settings (such as the default browser) are embedded in the Safari Preferences. How about putting these settings in the System Preferences so that we can remove the necessity to have Safari run on the system at all?

  • Mail

    This application is far from being useful and is targeted towards the light-weight/casual email user. Its perennial speed issues as well as its inability to deal with large mailbox sizes (think in the tens of thousands of messages) makes this probably the most useless OS X app for me. I didn't even last a day with Mail before deciding that SeaMonkey was the way to go. Unless there is a compelling reason for Apple to develop Mail and Safari, users would be well advised to avoid them entirely.

Apple is not Microsoft and for that, I am grateful. But if they continue in this vane, the quality that distinguishes them may become diluted and eventually lost. As Apple users, we must insist on a level of hardware/software integration that exceeds user expectation by simply working. I realize that this is idealistic, but I believe this to be the core of the public's perception of Apple, and should not be disregarded lightly. If Apple is to have any chance to grow their market share in the personal computing segment, they should avoid disabusing their relatively tolerant user base who have paid a premium for their product on the assumption that they would be entitled to a hassle-free computing experience.

November 22, 2007

Leopard

The introduction of Leopard is a watershed moment in computing history which will mark a turning point in how we view operating systems and their role in the computer-application-user triumvirate. Instead of the OS being simply a platform to support the computer-application relationship, focus will shift to its role between the user and the application.

In this context the operating system will change from being a hardware enabler to being an application enabler. In this regard, OS X with its Unix heritage is perfectly suited to this role.

The beauty of OS X is that it does not pander to the lowest common denominator with regards to the User. Inexperienced users value discoverability. Advanced users value transparency. The inexperienced want to be able to intuit the operation of an application without having to read lengthy manuals. Advanced users want an application that does not prevent them from using efficiencies gained through experience to accomplish tasks.

There is the implicit acknowledgment in OS X's design that the technology quotient of its users will run the gamut. The operating system's role is to provide a suitable framework to orient the user experience regardless of his/her technical ability. By not forcing a choice, OS X meets the primary requirement of "Users"; usability unencumbered by singular vision of compromise. By challenging the viability of a single OS monoculture and embracing the strengths of both Linux and Windows, Leopard reveals the truth about the power of multiplicity and diversity.

The principle of focusing not only on "what-it-can-do" but "what-you-can-do-with-it" is something which pervades Unix and indirectly OS X. Utility and usability. Given the right combination of hardware and software, anything is possible but it is the intent that characterizes the system. I'm inclined to believe that the harmony between utility and usability is the source of intangible "quality" that pervades OS X. Unix in one incarnation or another has evolved since in inception 30+ years ago as a platform for innovation. This quality is why Steveo's had his heart set on having a commercially viable Unix alternative. With Leopard, I believe that his wish which began with NeXT has finally been realized with Leopard.

How do OS X's rivals fare in comparison?

Although OS X shares a lot of functionality found in most commercial Linux distributions, Linux by and large is still focused on the computer-application relationship. With the exception of the Digerati, this focus prevents true widespread adoption. Until the usability gamut is addressed without diminishing its strengths, it will be relegated to infrastructure products and not the desktop. Although these weaknesses are being addressed by various commercial Linux vendors (SUSE / Redhat / Ubuntu), Linux as an application platform is still far from maturity. Until Linux moves away from mimicking equivalent functionality found in its competitors and rids itself of its preoccupation with superfluous eye candy, no true innovation can occur.

Surprisingly, Linux's weakness is also Microsoft's. By constantly pandering to self-serving industry initiatives (i.e. DRM, Genuine Validation, etc), they too have focused disproportionately on the utilitarian aspects of the Vista at the expense of the User. Vista is simply Microsoft's expression of innovation envy without the innovation. Is their any justifiable reason for upgrading from XP to Vista other than to enforce the digital rights of media companies and mitigate Microsoft's less than stellar security track record? Not from the initial reports of early Vista adopters. It is simply hubris that a company can manipulate is user base into paying for the privilege of beta testing its software. Despite the large (contractually enforced) install base, Vista is shaping up to be another Windows ME debacle for Microsoft.

March 11, 2008

Configuring PostgreSQL 8.2 in OS X Leopard via Fink

I spent a bit of time trying to figure this out, and instead of having to relearn this painful lesson in the future, I thought I would preserve my tribulations for prosperity. There were a number of resources that provide partial guidance in discovering the solution (which I've included here), but here is the solution laid out in full:

1. Install Fink

If you haven't already, install Fink. As per the Fink install instructions, you will also need the Apple Developer Tools. The package tools which come with Fink are second to none. To pull down the latest version of a package, simply install it using FinkCommander from source or binaries.

2. Install PostgreSQL

At the time of writing this, the latest version of PostgreSQL is 8.2.6. It is highly recommended that you use the latest available stable release of PostgreSQL as it usually includes a number of security and stability fixes which are a prerequisite for maintaining a stable, secure installation. To install PostgreSQL from the command line, you could also run the following command:

$ /sw/bin/fink install postgres

Simply follow the prompts to complete the installation.

3. Create PostgreSQL account

I found that previous versions of PostgreSQL left some stranded permissions on my system. Unfortunately, none of these mechanisms allowed me to sudo into the postgres account. Given the change in user management tools in Leopard, it is recommended that you use the new Directory Service commands provided in 10.5.x to add the PostgreSQL user to the system. If you have a previous version of PostgreSQL installed that you are not currently using, I recommend removing it and any associated users from the system. Exercise caution doing this if you have an existing installation as it has the potential to loose your data if you are not careful. As the PostgreSQL account used to manage the database should behave like other system accounts, you will need to associate with an unused user and group ID which is less than 500. This will prevent it from being displayed in the Login Screen. I modified Pat Maddox's instructions to determine which whether or not a particular ID is currently in use by issuing the following commands:

$ dscl . -list /Groups PrimaryGroupID | awk '{print $2}' | grep user_id
$ dscl . -list /Users UniqueID | awk '{print $2}' | grep group_id

where user_id and group_id are the IDs you would like to check. If the command returns a value, then the ID is already in use. In most cases, user/group ID 499 is available for use. The rest of this example uses this for the PostgreSQL user/group ID. To create the PostgreSQL group account issue the following command:

$ sudo dseditgroup -o create -i 499 -r "Postgres Admin User" pgsql

To create the PostgreSQL user account issue the following commands:

$ sudo dscl .
> create /Users/pgsql
> create /Users/pgsql UniqueID 102
> create /Users/pgsql UserShell /bin/bash
> create /Users/pgsql RealName "Postgres Administrator"
> create /Users/pgsql NFSHomeDirectory /usr/local/pgsql
> create /Users/pgsql PrimaryGroupID 102
> create /Users/pgsql Password *
> quit

4. Configure directories

This is where Maddox's instructions (based on MacPorts) and mine diverge. Fink typically installs packages under the /sw directory. The main PostgreSQL binaries should be located in the bin subdirectory with the database files installed in the var subdirectory. The database directory usually has a version suffix. Once you've located the database directory, you will need to reassign it's ownership to the newly created pgsql user. I usually provide a symbolic link which points to the most recent version installed on the system to provide a short-cut as well as indicate which version is being used (when more than one version is installed).

$ sudo chown -R pgsql:pgsql /sw/var/postgresql-8.2
$ cd /sw/var
$ sudo ln -s postgresql-8.2 postgresql

You will notice that PostgreSQL was not installed in /usr/local by Fink. This avoids potential conflicts which might arise with other 3rd party packages installed on the system. You will also notice that when we created the PostgreSQL account, the NFSHomeDirectory attribute was set to /usr/local/pgsql. This was intentional. By creating a symbolic link from this directory to the one created by Fink, we can integrate the Fink installation seemlessly in with the rest of the system without introducing conflicts or dependencies. I usually prefer relative paths in this circumstance:

$ cd /usr/local
$ sudo ln -s ../../sw/var/postgresql ./pgsql

By pointing to the original symbolic link, simply changing that link will automatically update the NFSHomeDirectory attribute associated with the PostgreSQL user.

5. Access caveats

Resist the urge to associate a password with the pgsql user. Using sudo to assume privileges will allow you to limit who can access your PostgreSQL installation locally. If you require remote administrative privileges, configure accounts through PostgreSQL directly instead of delegating privileges to system accounts.

6. Configure database

At this point, you should be able to switch to the pgsql user. Check your identity and privileges:

$ sudo su - pgsql
$ whoami
$ id pgsql

To initialize the database issue the following commands:

$ /sw/bin/initdb -D /usr/local/pgsql/data -E utf8

This will create the initial postgres database which will support UTF8 (for international character sets). Once the database is initialized, you can start it by issuing the following command:

$ /sw/bin/pg_ctl -D /usr/local/pgsql/data -l /usr/local/pgsql/logfile start

To stop the server:

$ /sw/bin/pg_ctl -D /usr/local/pgsql/data stop

To enable the procedural language for all databases derived from template1:

$ /sw/bin/createlang-8.2 plpgsql template1

You should now be able to connect to the postgres database:

$ psql -d postgres

7. Security

At this point you might want to spend some time securing your PostgreSQL installation. There are a few pointers in the Installing PostgreSQL on Mac OS X article, but as with all things Postgres, please refer to the Manual for definitive answers regarding security. One of the few things I did to secure my installation was to modify the data/pg_hba.conf file to support a default administrative user that required password authentication. This prevents a local user from automatically gaining access to the database by compromising the PostgreSQL user account. This required first assigning a password to the PostgreSQL user account. This is accomplished by connecting to the newly created postgres database and executing a SQL statement which assigns the user a password:

$ psql -d postgres
#postgres=# ALTER USER pgsql PASSWORD 'secret';
#postgres=# \q

where secret is the password that you've selected. The password itself will be stored as an MD5 checksum so that when you authenticate against the PostgreSQL server, it is never transmitted in plain text. Next, the data/pg_hba.conf file needs to be modified to support authentication for the PostgreSQL user account. Use an editor to add the following lines:

local    all         pgsql                             md5
# IPv4 local connections:
host    all         pgsql     127.0.0.1/32             md5
# IPv6 local connections:
host    all         pgsql        ::1/128               md5

After these changes, a server restart will be required:

$ pgctl -D /sw/var/postgres/data reload

When logging into the default database you should now be prompted for a password. Be careful if lines such as the above already exist in your configuration. You may need to replace them in order for this to work.

8. Tuning

As this database is going to be used for development purposes, a lot of cruft will accumulate in the database as tables are create and destroyed and data is modified. To save the trouble of having to automatically clean up the database, you can modify the data/postgresql.conf file to support auto-vacuuming to recover space in the background. The following lines should be placed in the file:

stats_start_collector = on
stats_row_level = on
autovacuum = on 

As the postgresql.conf file is installed with defaults on a fresh PostgreSQL install, you may need to simply comment out these lines.

9. System service configuration

The last step requires configuring the PostgreSQL install to start and stop as other OS X system services do. This will require creating a StartupItem entry for PostgreSQL. These basis of these instructions are courtesy of Robert Crews and wmaus. First create a directory to store the initialization script for PostgreSQL:

$ sudo mkdir /Library/StartupItems/PostgreSQL

Create the PostgreSQL script under this directory with the following code:

#!/bin/sh

# Source common setup, including /etc/hostconfig
. /etc/rc.common

FINK_BIN='/sw/bin';
PGSQL_HOME='/sw/var/postgresql';
PGSQL_USER='pgsql';

StartService ( ) {
    # Don't start unless PostgreSQL is enabled in /etc/hostconfig
    if [ "${POSTGRESQL:-NO-}" = "-YES-" ]; then
        ConsoleMessage "Starting PostgreSQL"
        sudo -u ${PGSQL_USER} ${FINK_BIN}/pg_ctl \
            -D ${PGSQL_HOME}/data \
            -l ${PGSQL_HOME}/logfile start
    fi
}

StopService ( ) {
    ConsoleMessage "Stopping PostgreSQL"
    sudo -u ${PGSQL_USER} ${FINK_BIN}/pg_ctl -D ${PGSQL_HOME}/data stop
}

RestartService ( ) {
    if [ "${POSTGRESQL:-NO-}" = "-YES-" ]; then
        ConsoleMessage "Restarting PostgreSQL"
        StopService
        StartService
    else
        StopService
    fi
}

RunService "$1"

Obviously, replace the constants at the beginning of the script to match your installation if they are different from the ones here. There is one step that is not described in the Crew's instructions which is required to allow the SystemStarter to manage the service. A PostgreSQL.loc file in the same directory as the script which contains the path to the postgres binary and provide the execution context for pg_ctl must be created. In the case of a Fink installed PostgreSQL installation, this file should contain the following line:

/sw/bin

Without this .loc file, the SystemStarter will throw an error when invoked.

The last step requires adding a PostgreSQL entry in the /etc/hostconfig file. It's always a good idea to save a copy of the original config file before modifying it. Add the following entry to the file:

POSTGRESQL=-YES-

This will ensure that PostgreSQL is started when you boot your machine. You can also manage the service using the following commands:

$ sudo SystemStarter stop PostgreSQL
$ sudo SystemStarter start PostgreSQL
$ sudo SystemStarter restart PostgreSQL

Drop me a line if you find this useful or if you find any mistakes in the method outlined above.

March 26, 2008

Ruby in OS X Leopard

If you are using Ruby in OS X, I suggest NOT managing it through Fink. OS X comes with Ruby pre-installed. All that is required is to update and install a number of gems as per the Apple Developer Instructions. The instructions also cover configuring Xcode to use for Rails development. After trying both Aptana and the Rails plugin for Eclipse, I suggest the path of least resistance. Xcode is particularly elegant and uncumbersome.

# sudo gem update --system
# sudo gem install rails
# sudo gem update rake
# sudo gem update sqlite3-ruby

Building the PostgreSQL gem requires an additional step as the installed database is managed through Fink (thanks to Roy Hooper fom this one):

# export PATH=/sw/lib/postgresql82/bin/:$PATH
# sudo env ARCHFLAGS="-arch i386" gem install --remote postgres

Modify the environment.rb file to reflect the version of rails installed above. For example, the default scaffold built by the rails command assumes that the version is 2.0.2. To prevent the following error:

Missing the Rails 2.0.2 gem. Please `gem install -v=2.0.2 rails`, 
update your RAILS_GEM_VERSION setting in config/environment.rb for 
the Rails version you do have installed, or comment out RAILS_GEM_VERSION 
to use the latest version installed.

I had to append .9097 to bring the rails version to 2.0.2.9097 for this rails release at the time of writing this article. This will most likely be different for newer versions of rails. The version option for the rails command returns version 2.0.2, but the issuing the following command will return the release number :

# gems list

If you update your gems, you will have to update the environment.rb file with the release version.

I also do not recommend using Aptana. Although it is tempting to use an integrated IDE, there is a bunch of functionality that is buggy (such as the Generators).

April 16, 2008

The Secret Sauce

If it isn't already obvious, OS X is the foundation that will provide Apple their future competitive advantage. Although hardware makers will inevitably try to emulate Apple's minimalism, without a complimentary environment to host the device's primary application (i.e. phone or media player), they will never approach the unquantifiable elegance embodied in all Apple products. With this in mind, expect Apple to continue their hard-line persecution of vendors which attempt to port OS X to commodity hardware, or in the case of Psystar, offering commercial alternatives for OS X. By preserving a common vocabulary for interaction across their devices based on OS X interface, Apple will acclimate users to a standard set of usability conventions. By virtue, OS X's Darwin kernel and Unix pedigree will serve it well as it morphs to fill the Apple embedded universe. By allowing modular functionality, only as much of OS X that is necessary to support the device's primary function need be made available. This OS X strategy will provide both device specialization and familiarity for its users. Contrast this with Windows, which has devolved into a monolithic mess which makes it patently unsuitable for this transition into the embedded space.

Despite the superficial similarity of products trying to emulate Apple, without this crucial component, competitors will only be pale imitations. Just look at the functional envy which birthed Vista. Despite having significantly broader hardware resources to exploit, and more time to develop, Vista on any hardware platform is still inferior to a comparable Mac/OS X system in terms of user experience. The only way to emulate Apple is to develop a hardware/software synergy that speaks to the user experience as opposed to developing either in isolation and hoping for coincidental synergies to manifest. In this respect, the Android platform may become the first real contender if implemented with the right focus.

Oh well, so much for my dreams of having OS X supported on the X300 ThinkPad.

June 15, 2008

OSX - Missing Feature : Time Vault

Considering how much hype surrounded Time Capsule and the apparently seamless way it integrates into OSX, it is surprising that not more attention has been focused on the obvious incompatibility between itself and File Vault. Although Time Capsule is intended for data integrity and File Vault intended for data security, it would seem logical that using both together would be the ideal solution - secure data that is backed up incrementally. This unfortunately, is not the case. Having a user directory secured by File Vault means that no incremental Time Capsule backups can occur unless the user logs out of his/her current session. WTF !!! You can have either Time Capsule back ups, or you can have secure user directories with File Vault, but not both. For those who think that logging out to perform backups is a viable work around, let me remind you that syncing is incredibly time consuming (doubly so for an encrypted disk image). Data integrity and security should not be mutually exclusive issues. If the recent spate of data losses/breaches escalates, it will be no great leap to steal confidential data from personal Time Capsules (specially from the technically inept). More worrying is the idea of your backups being used by authorities for the purposes of self-incrimination.

Not all is lost. Apple promises Snow Leopard (10.6) to be a performance and stability release. With any luck, they will be able to fit in the time to rectify this egregious oversite. The best of both worlds would provide a true universal backup solution. I christen thee Time Vault.

November 9, 2008

Ruby Deja Vu

Having recently upgraded my laptop to a new spanky Hitatchi 7K320, I've had the opportunity to build my Ruby development platform from scratch (and hopefully jettison some unwanted cruft) as well as relearn the in's and out's of Ruby on OS X. A clean install provides you with ruby 1.8.4 as well as an older rails 1.1.2. The challenge is to get the latest and greatest. With that in mind, I've outline the steps that I need to follow to get there:

# sudo gem update --system
# sudo gem update

Instead of the cumbersome update of individual components, a simple update will catch all the necessary updates and bring your system up to speed (rails 2.2.0).

Now on to see if installing PostgreSQL is any easier ....

November 10, 2008

Reboot !!!

I usually avoid rebooting as a matter of principle. It always seemed like using a hammer to swat a fly, and the inferiority of an OS is directly related to the number of reboots required to get it to function civilly. That being said, I've run into a number of situations during my OS X re-installation where a reboot was quite necessary.

The first involved an application called TextExpander - a great little app that performs macro expansion at the OS level for all applications and meshes well with QuickSilver and Ubiquity for Firefox. The beauty of these applications is that almost everything is accessible via the keyboard as opposed to having to switch input methods (the old keyboard, mouse conundrum). This allow you preserve flow when you are working without being distracted by the cognitive changes required to switch input methods.

Anyway, the problem I experienced was with the way TextExpander choose to install itself. Although the instructions are pretty straight forward, nothing in the installation docs mentioned the application's requirement of a custom daemon - textexpanderd. Unfortunately, the installer, while correctly copying the daemon onto the System, failed to enable the associated Login item. The system logs provided the very unhelpful messages consisting of the following lines :


Nov 10 18:57:31 aleph kernel[0]: Finder[109] Unable to clear quarantine 
`TextExpander.prefPane': 30
Nov 10 18:57:37 aleph [0x0-0x1a01a].com.apple.systempreferences[188]: 
No matching processes belonging to you were found
Nov 10 18:57:38 aleph textexpanderd[191]: textexpanderd 2.5 
at your service

Luckily, I managed to decipher this gobbledegook, and a handy reboot allowed the daemon to start without issue. It is documented here for others who might one day run into the same problem.

The other situation I found I need to bounce the machine was with the installation of PostgreSQL. In my orginal instructions, I outlined the steps to create a user account using the dscl command line utility. I unfortunately forgot to include the caveat that a reboot is required to make the user account visible to the system. Yet again, a less than insightful error message was displayed when attempting to initialize the database. I've lost the message, but the gist of it was the inability for postgres to proceed with the initialization because of inadequate shared memory configured on the system. This, needless to say, is not one of the limitations of my machine. Note to self: if the user is not visible from the User dialog, but available from the terminal, this is the issue.

Oh well, such is life.

November 11, 2008

PostgreSQL Addendum

As I installed PostgreSQL using Fink, the user account that I originally create using my previous instructions is not aware of these binaries. The simplest way for pgsql account to be aware of these new binaries is to create a custom .bash_profile file which appends the /sw/bin directory to the PATH environment variable. Create a .bash_profile file in the home directory of the pgsql account with the following contents:

PATH=$PATH:/sw/bin

This should allow you to refer to the PostgreSQL binaries within the Fink installation directory without have to use full qualified path names.

In addtiion, the original startup script required modification of the PGSQL_HOME variable to reflect the new installation's location(/usr/local/pgsql) as well as ensuring that the correct file permissions were enabled on both the service directory and script (which happen to have the same name):

# chmod 555 PostgreSQL

The only other thing that bit me in the ass was the fact that my copy and paste operation didn't work out quite as well as I expected and I was missing the shebang at the top of the script as well as having an orphaned comment. Always check the validity of the script contents.

November 25, 2008

Installing OpenBSD 4.4 on a Soekris 4801

Not a very sexy title, but entirely to the point. It's been a while since I installed on my trusty Soekris 4801 and time has been both kind and capricious by dulling my memory regarding the arcana required to make this combo work. To save myself future frustration, I've decided to document the steps and commit them to the collective unconscious.

Just a little background; I began this project when I retired my rather thirsty and ancient Pentium Pro that served as my personal firewall/gateway for my home LAN a couple of years ago. I wanted a device that would not compromise on security and flexibility (hence the requirement to support OpenBSD) but also consume a reasonable amount of power. Enter the Soekris 4801 - an AMD Geode based embedded system. Base power consumption is 5W - 12W at peek. Not a powerful machine by modern standards, but certainly more powerful than my old system and more than sufficient for my needs. This system was cutting edge in the embedded systems space when I got it, but has been superceded by the newer 5501-60. For the record, the 4801-60 has the following specifications:

  • 233 Mhz i386 compatible AMD Geode CPU
  • 128 Mbyte SDRAM (embedded)
  • 3 SIS 10/100BaseT Ethernet ports (embeded)
  • 2 RS232 Serial extensions with a single 9 pin port
  • 1 32-bit Compact Flash socket
  • 1 44 pin IDE 66 connector
  • 1 Mini-PCI socket
  • 1 3.3V PCI connector
  • 1 1621 dual port SIS 10/100BaseT Ethernet card attached to the PCI connector

Soekris Engineering also manufactures an add-in mini-PCI VPN accelerator (vpn1411), but I haven't gotten around to installing one of these yet. Although, the Soekris is ideally suited for flash based firewall distros, I opted to have a full version of OpenBSD. Storage for the OS is provided through a CF adapter which houses a 6GB Hitachi Microdrive.

Like most embedded systems, there is no built-in support for external peripherals, such as keyboards, mice, and video. All communications happens through one of the two serial ports. Thankfully, the engineers at Soekris were kind enough to wire up a port, otherwise you'd be left to your own devices to rig one up for yourself. The 4801 supports comBIOS, meaning you can use a null serial cable and a communications program (such as minicom) to manage the device through its entire boot cycle. This brings us to my first tidbit; communication parameters. The 4801 supports the following :

19200 8N1
hardware and software flowcontrol off 

Be sure that your communication software is configured with these parameters - their importance will become apparent when we attempt to update the 4801 with the latest BIOS firmware. It is good practice to use the latest vendor supplied firmware to reduce the possibility of potential hardware conflicts. However, without the correct parameters, attempting to update the firmware using the built-in BIOS monitor is impossible and will result in spurious cryptic errors being thrown. There were sites which suggested that the following xmodem parameters be changed to enable communications compatibility with the 4801:

/usr/sbin/sx -vv -b -X

but from my experience, disabling hardware flow control was sufficient to ensure seemless serial communications.

The process for updating the firmware is as follows and assumes that you are already connected to the 4801 through a serial cable :

  1. Download the latest firmware from Soekris.
  2. Reboot the 4801. At the boot prompt, interrupt the boot process using CTRL-P. This will bring up the boot monitor.
  3. The official documentation refers to the download command to initiate file transfer. There is an undocumented option to this command however which will correctly initialize the file transfer session.

    download -

    Failing to provide the additional - argument will result in NAK errors when attempting to establish the communications channel.

  4. Once the file has been uploaded, issue the following command:

    flashupdate
  5. Reboot.

For more detailed instructions, please see the Updating the Soekris BIOS.

As there is no direct way to supply install media directly to the 4801, updating the 4801 requires configuration for PXE booting. At this point, I'd like to point out my second major caveat regarding the upgrade process:

The Soekris 4801 does not support PXE booting on any other interface other than the first ethernet port (ETH1).

I wasted a precious amount of time learning this lesson. Heed it well. This limitation also implies that to upgrade the 4801 requires it being in a network environment where the primary network interface can be configured. If this is not the case (such as when the 4801 resides on the network boundary), you will have to move it. Kiss goodbye to an in-place upgrade.

There are two services that are required to facilitate PXE booting - tftp and dhcp. The DHCP server has to be configured to supply an optional filename to a lease request made from the 4801's primary network interface. This implies that you know the MAC address of this interface. If you do not already have it, you can get it by forcing the 4801 into booting off the network using the BIOS monitor. See below.

The following is an example of a dhcpd.conf file that supports PXE booting

# dhcpd.conf
#
# Configuration file for ISC dhcpd (see 'man dhcpd.conf')
#

## GLOBAL OPTIONS
ddns-update-style ad-hoc;
default-lease-time 1200;
max-lease-time 9600;

subnet 10.0.1.0 netmask 255.255.255.0 
	{
		range 10.0.1.101 10.0.1.200;
		option broadcast-address 10.0.1.255;
		option routers 10.0.1.1;
		option domain-name "domain.com";
	}

host soekris
	{
		hardware ethernet 00:00:24:c3:90:f8;
		fixed-address 10.0.1.100;
		filename "pxeboot";
		option host-name "soekris";
		next-server 10.0.1.10;
	}

Please note the following :

  • The argument to filename is not an absolute path. It is simply the name of the pxeboot file.
  • The next-server option is required.
  • The ddns-update-style global option is required for newer versions of dhcpd.

Following these guidelines when configuring dhcpd will save you from needless troubleshooting.

TFTP is usually managed through inetd/xinetd. Unfortunately, this results in arp network issues. It is recommended that tftpd run in standalone mode to avoid these issues.

The last part of the tftpd configuration requires creating a directory to serve out the pxeboot and bsd.rd files. Keep in mind that by default, tftpd runs as an unprivileged user (such as nobody). Ensure that wherever you place these PXE files, they have appropriate permissions for the daemon to access. Because we are using the console to manage the boot process, this PXE installation also requires an etc directory with a boot.conf file to configure the installer to use the console. The contents of the file are as follows:

stty com0 19200
set tty com0
boot bsd.rd

The order of these configuration parameters is important. The stty must come before the set command.

Believe it or not, at this point, you are ready to install OpenBSD. To get the 4801 to boot over the network requires the following steps:

  1. Reboot. Interrupt the boot process using CTRL-P to enter the BIOS monitor.
  2. Issue the following boot command:

    boot f0
    

I won't belabor the install details; you can get these directly from the main OpenBSD site. There is however one last caveat in this upgrade process: when the installer has completed unpacking the file sets, you are asked whether you want to set the current serial console as the default terminal. Say Yes! If you don't, when the 4801 reboots, it will hang attempting to load the kernel. This unfortunately leads to the boot process simply hanging at the following message:

entry point at 0x200120

Took me a while to figure this out. Hopefully others will not have to suffer quite as much as I did. Thankfully, OpenBSD has finally "modernized" and supplied a cleaner upgrade path than in previous releases. Hurray!!! About fucking time.

November 26, 2008

OpenBSD Cheat Sheet

I always find myself having to dig out the following commands after I've upgraded my systems. Here's my contribution to working smarter, not harder.

Ports

  • Unpack ports.tgz in the /usr directory.
  • The following command will update the ports tree using anonymous cvs:

    # cvs -q -d anoncvs@anoncvs3.usa.openbsd.org:/cvs up -r \
    OPENBSD_4_4 -Pd
    

    For a list of anoncvs servers look here.

  • To find where a package lives in the ports tree, use the following command:

    # make search key=programName
    

    Beats visual grepping all the port directories.

  • To show available package flavors:

    # make show=FLAVORS
    

    To build a flavor:

    # env FLAVOR="flavorName" make install
    

Base System Source Code

  • Unpack src.tgz and sys.tgz in the /usr/src. Do NOT unpack these archives in the /usr directory unless you want trouble.
  • Apply patches from the top of the source tree - /usr/src using the following command:

    # patch -p0 < pathToPatch/001_patchname
    

    The instructions are fairly clear with regards what needs to happen after application of the patch. Don't skip any steps or bad shit will happen.

  • Rebuild the kernel using the following commands:

    # cd /usr/src/sys/arch/i386/conf && config GENERIC && \
    cd ../compile/GENERIC && make depend bsd && mv /bsd /bsd.old && \
    cp bsd /
    

    I usually put this into an executable script in the /usr/src directory so that I can easily rebuild the kernel. You might want to install screen from ports before attempting to run this command on a Soekris 4801 or have the patience of a saint. If you've applied of patches in succession, you can issue a single rebuild instead of rebuilding per patch. That's just masochistic.

December 7, 2008

Subversion Primer

There comes a time when version control becomes a necessity; that's when Subversion comes to the rescue. Having worked with both CVS and Subversion, I recommend avoiding the baroque intricacies of CVS for the simplicity of Subversion. This is specially true if you have a project with an evolving source tree. Follow the links above for an introduction to Subversion.

There are a few things to note however, when attempting to use Xcode 3.1 with Subversion 1.5.x. It seems that Xcode is hardwired to verify the repository version. A repository created with the 1.4 version of the svnadmin returns a version identifier of 2, whereas the 1.5 of the command creates a version 3 repository. This may have to do with the back end databases used by the repository. Without significant hacking, it seems like a lot of work with marginal benefit. For now, I'd recommend using the packaged 1.4.4 that comes with OS X 10.5.5.

One last thing: it seems that launchctl will be the default method for managing startup daemons going forward in OS X. This means that the older SystemStarter service will be deprecated in the near future. There is an article at The Wishing Line which discussed a method for automating svnserve startups using launchctl. Be sure to modify the .plist to use the correct paths for your binaries and repository. As with PostgreSQL, I created symbol links from /usr/local to the actual repository to keep a clean separation between the system defaults versus any customizations that I introduce into my computing environment through 3rd party applications.

With OS X 10.5.5, I found that the 1.4.4 version of svnserve included with the developer tools was located in the /usr/bin directory. You can verify this on your system with the following command:

# which svnserve

Take note of the path returned by this command; it is necessary for the .plist file.

One last customization to the .plist file was changing the default --daemon command argument and replacing it with the --tunnel argument to support svn+ssh. If you plan to use this feature for a network accessible Subversion server, keep in mind that you will also have to enable the Remote Login privilege to be enabled on your machine under System Preferences -> Sharing.

For the sake of completeness, here is my modified .plist file:





	Label
	org.tigris.Subversion
	ProgramArguments
	
		/usr/bin/svnserve
		--tunnel
		--root
		/usr/local/svn
	
	RunAtLoad
	
	ServiceDescription
	Subversion Server
	StandardErrorPath
	/dev/null
	UserName
	root


As with all these articles, please feel free to comment if you find and error or wish to add something that I've overlooked.

December 8, 2008

RailRoad

Here are some notes I've collected as I've worked through developing my application on Rails:

PostgreSQL

I generally prefer using PostgreSQL for my personal projects. PostgreSQL's pedigree and consistent level of technical superiority means that I'll never have to second guess my decision regarding the database as an application's use begins to scale. Given Monty Widenius' rant against MySQL 5.1, I don't foresee it approaching the capabilities of PostgreSQL anytime soon.

Rails Database Adapters

That being said, there were a few caveats to keep in mind for Rails to use PostgreSQL as a back end store. The first is clarification on which gem adapter module is required for rails configuration. There are two - one which is a pure ruby driver, the other a compiled native driver. The postgres-pr (the pure ruby PostgreSQL driver) worked right out of the box. The pros of this driver is it is implemented in ruby; the con however, is that it is relatively slow compared to the native driver.

With the latest version of rails (2.2.2), I found that the postgresql gem is no longer recognized. It has been superceded by the postgres native adapter. Attempting to compile the postgres gem against my Fink managed PostgreSQL 8.3 installation resulted in the following errors:

Building native extensions.  This could take a while...
ERROR:  Error installing postgres:
	ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb install postgres

===========   WARNING   ===========

You are building this extension on OS X without setting the
ARCHFLAGS environment variable, and PostgreSQL does not appear
to have been built as a universal binary. If you are seeing this
message, that means that the build will probably fail.

Try setting the environment variable ARCHFLAGS
to '-arch i386' before building.

For example:
(in bash) $ export ARCHFLAGS='-arch i386'
(in tcsh) $ setenv ARCHFLAGS '-arch i386'

Then try building again.

===================================
checking for main() in -lpq... yes
checking for libpq-fe.h... yes
checking for libpq/libpq-fs.h... yes
checking for PQsetClientEncoding()... no
checking for pg_encoding_to_char()... no
checking for PQfreemem()... no
checking for PQserverVersion()... no
checking for PQescapeString()... no
creating Makefile

make
gcc -I. -I. -I/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0 -I. -DHAVE_LIBPQ_FE_H -DHAVE_LIBPQ_LIBPQ_FS_H -I/sw/include/postgresql  -fno-common -arch ppc -arch i386 -Os -pipe -fno-common  -c libpq-compat.c
libpq-compat.c: In function 'PQescapeBytea':
libpq-compat.c:104: warning: incompatible implicit declaration of built-in function 'sprintf'
libpq-compat.c:104: warning: pointer targets in passing argument 1 of 'sprintf' differ in signedness
libpq-compat.c: In function 'PQunescapeBytea':
libpq-compat.c:158: warning: incompatible implicit declaration of built-in function 'strlen'
libpq-compat.c:158: warning: pointer targets in passing argument 1 of 'strlen' differ in signedness
libpq-compat.c: In function 'PQescapeBytea':
libpq-compat.c:104: warning: incompatible implicit declaration of built-in function 'sprintf'
libpq-compat.c:104: warning: pointer targets in passing argument 1 of 'sprintf' differ in signedness
libpq-compat.c: In function 'PQunescapeBytea':
libpq-compat.c:158: warning: incompatible implicit declaration of built-in function 'strlen'
libpq-compat.c:158: warning: pointer targets in passing argument 1 of 'strlen' differ in signedness
gcc -I. -I. -I/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0 -I. -DHAVE_LIBPQ_FE_H -DHAVE_LIBPQ_LIBPQ_FS_H -I/sw/include/postgresql  -fno-common -arch ppc -arch i386 -Os -pipe -fno-common  -c postgres.c
postgres.c:41: error: static declaration of 'PQserverVersion' follows non-static declaration
/sw/include/postgresql/libpq-fe.h:262: error: previous declaration of 'PQserverVersion' was here
postgres.c:41: error: static declaration of 'PQserverVersion' follows non-static declaration
/sw/include/postgresql/libpq-fe.h:262: error: previous declaration of 'PQserverVersion' was here
postgres.c: In function 'Init_postgres':
postgres.c:2676: error: 'pgconn_protocol_version' undeclared (first use in this function)
postgres.c:2676: error: (Each undeclared identifier is reported only once
postgres.c:2676: error: for each function it appears in.)
postgres.c:2677: error: 'pgconn_server_version' undeclared (first use in this function)
postgres.c: In function 'Init_postgres':
postgres.c:2676: error: 'pgconn_protocol_version' undeclared (first use in this function)
postgres.c:2676: error: (Each undeclared identifier is reported only once
postgres.c:2676: error: for each function it appears in.)
postgres.c:2677: error: 'pgconn_server_version' undeclared (first use in this function)
lipo: can't open input file: /var/tmp//ccZF2c6t.out (No such file or directory)
make: *** [postgres.o] Error 1

The error appeared despite setting the ARCHFLAGS environment variable and supplying the POSTGRES_INCLUDE argument to the gem install command. I finally got it to compile correctly after a bit of digging:

# sudo env ARCHFLAGS="-arch i386" gem install postgres

Note how the ARCHFLAGS needed to be passed into sudo. Good to know someone out there already figured it out.

To use either of these database adapters, you will need to ensure that the config/database.yml file specifies postgresql for the adapter parameter. The default is sqlite3. It's probably a good idea to have only either the ruby or native driver installed at any given time.

In addition, you should remove the database parameter from the database.yml file. These are only required for SQLite databases.

PostgreSQL Application Accounts

The last bit of configuration requires each of the different releases (development, test, and production) have their own database users. It is generally good practice to completely keep these environments isolated from one another to avoid accidental loss of data. The config/database.yml file requires additional information to configure these separate connections. Each entry in the database.yml should have the following parameters:

host : machine_name
username : database_user
password : database_password

Due to the sensitive nature of the information contained in the database.yml file, it is highly recommended that this file be NOT world readable.

All of this configuration is fruitless without actual PostgreSQL users. Use the following commands to create a database and user for each of these environments (these commands assume that you are the local PostgreSQL user):

# createuser -SdRlEP development
# createuser -SdRlEP test
# createuser -SdRlEP production

The options will result in PostgreSQL users which will not have superuser privileges or the ability to create new roles, but have privileges to create databases (for scaffold creation/teardown) and log in. As well, the account will have an encrypted password.

Once these accounts have been created, you will need databases to associate with each of them:

# createdb -E UTF8 -O development dev_database_name
# createdb -E UTF8 -O test test_database_name
# createdb -E UTF8 -O production prod_database_name

The last step requires enabling psql local machine connections so that you can inspect the structure of the database for each of these releases are the evolve over the development process. This requires modifying the data/pg_hba.conf file for PostgreSQL. There should be entries for each user and database for each local address group (localhost / local IPV4 / local IP6).

# "local" is for Unix domain socket connections only
local        dev_database_name              development	md5
local 	test_database_name            	test   		md5
local 	prod_database_name        	production	md5

# IPv4 local connections:
host 	dev_database_name	development	127.0.0.1/32	md5
host 	test_database_name	test   		127.0.0.1/32	md5
host 	prod_database_name	production	127.0.0.1/32	md5

# IPv6 local connections:
host 	dev_database_name	development	::1/128		md5
host 	test_database_name	test	        	::1/128		md5
host 	prod_database_name	production	::1/128		md5

By specifying the encrypt password option when creating the database roles, you ensure that passwords are never transmitted in clear text. As a consequence, you must use the MD5 authentication method in the pg_hba.conf file.

As with any configuration changes, you will have to restart the server for the changes to be applied. Test the accounts by making local psql connections by specifying both the user and database as options:

# psql -U development -d dev_database_name

If you plan on making the PostgreSQL account accessible over the network it is highly recommended that you secure your connections using SSL. Please refer to the PostgreSQL documentation to configure the server with OpenSSL certificates.

Here are some useful PostgreSQL/Ruby links:

Rails

Gem Management

Here are some useful commands for rails:

Get the a remote list of gems available.

# gem list --remote

Find a gem either in the local or remote repository.

# gem search --both name_of_gem

Display a remote gem's specifications.

# gem specification --remote name_of_gem

Search for remote generator gems which can be installed.

# gem search -r generator

Here are a list of useful gems:

  • ruby-debug

Rails Scaffolding

Rails excels as a tool for rapid prototyping with a focus on web applications which adhere to the Model-View-Controller (MVC) design paradigm. Using a relatively succinct number of ruby scripts, project scaffolding can be generated quickly and efficiently. Before projects can be automatically run in Xcode, the project must first be configured for use. This requires the following steps:

  1. Generate the basic project framework using the following command:

    # rails project_name
    

    This will generate a core project scaffold which contains all the required files and default configuration for a basic rails application.

  2. Open Xcode and drag the generated application directory into the Project & Sources category in the Organizer window.
  3. Click the Run icon and select Edit Actions ...
  4. Create a new item named.
    • Create a new item named start server.
    • In the Directory drop down, select the Top Level Organizer Item option.
    • In the Command text box, enter the following command : script/server. This corresponds to a ruby script located in the script directory generated by the initial rails scaffolding command.
    • Ensure that there are no Arguments.
    • Click OK to save the Run Action.
  5. At this point, clicking the Run icon should start the ruby application on your local machine. Pointing a browser to the http://localhost:3000 address should display the default web page for the application.

By default, Rails uses the Active Record pattern to persist application objects to a relational database.

To generate scaffolding for application objects which create default entries for each of the MVC components issue the following command from the top of the application directory:

# ./script/generate scaffold object_name property:data_type property:data_type

where:

  • the object_name is the class of application object you wish to create scaffolding for.
  • the property is a property or attribute of the application object.
  • the data_type is the storage data type of property.

In addition to the MVC files, the scaffold generate script also creates a migration file which allows database schema to upgraded/downgraded as the application is developed. In addition, by specifying different development, test, and production databases in the configuration, these separate environments remain isolated.

Caveats

2.2.2 Release Notes

There are number of significant changes introduced to Rails 2.2.2. These result in older applications being unable to run in the new Rails environment. It is highly recommended that you read the Release Notes for 2.2.2 to be sure that your application is not broken by this upgrade. The following is a list of a number of issues that I encountered.


The following command is deprecated in Rails 2.2.2 in config/environments/development.rb:

config.action_view.cache_template_extensions = false

Using Inflectors requires a change to the default inflections.rb in Rails 2.2.2 :

 ActiveSupport::Inflector.inflections do |inflect|
   inflect.plural /^(ox)$/i, '\1en'
   inflect.singular /^(ox)en/i, '\1'
 end

Failing to add the ActiveSupport namespace qualifier will result in the following initialization error :

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:445:in `load_missing_constant': uninitialized constant Inflector (NameError)
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:77:in `const_missing'
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:89:in `const_missing'
	from /Users/mel/Documents/Workspace/vuespace/src/config/initializers/inflections.rb:5
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in `load_without_new_constant_marking'
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in `load'
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:521:in `new_constants_in'
	from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in `load'
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/initializer.rb:550:in `load_application_initializers'
	 ... 32 levels...
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/commands/server.rb:49
	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
	from /Users/mel/Documents/Workspace/vuespace/src/script/server:3

Rails now supports database connection pooling to support larger numbers of concurrent users. This feature is enabled by default in the supplied database.yml file where the pool parameter (which specifies the maximum number of connections to use) is specified with a default. In addition, configuration now also supports the wait_timeout (the amount of time to wait before trying another connection; the default is 5 seconds) parameter.

January 12, 2009

RailRoad II

Here are a few additional notes regarding my experiences with Ruby on Rails. Although there is veritable dearth of information on these topics, the difficulty as ever lies in having a single consolidated reference for these issues. At best, documentation on the web is complete with examples and thoughtful explanations; at worst, it is completely misleading and full of uninformed assumptions.

Required database.yml parameter : database

The database.yml file requires the database : parameter in order to establish a valid connection to the database for a given user. This parameter was not present in earlier versions of the database.yml configuration file. See below for more details documentation regarding the PostgreSQL connection adapter parameters.

Database Adapters: pg versus postgres

At the time of writing this (against rails 2.2.2), there still seems to be a preference in the Rails framework for the pg driver over the postgres driver. Without the pg driver installed, the following error is displayed to the user :

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/abstract/connection_specification.rb:74:in `establish_connection': Please install the postgresql adapter: `gem install activerecord-postgresql-adapter` (no such file to load -- pg) (RuntimeError)
	from /Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/abstract/connection_specification.rb:58:in `establish_connection'
	from /Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/abstract/connection_specification.rb:53:in `establish_connection'
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/initializer.rb:392:in `initialize_database'
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/initializer.rb:139:in `process'
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/initializer.rb:112:in `send'
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/initializer.rb:112:in `run'
	from /Users/mel/Documents/Workspace/vuespace/src/config/environment.rb:13
	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
	from /Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/commands/generate.rb:1
	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
	from ./script/generate:3
aleph:src mel$ gem install activerecord-postgresql-adapter
ERROR:  could not find gem activerecord-postgresql-adapter locally or in a repository
aleph:src mel$ sudo gem install activerecord-postgresql-adapter
Password:
ERROR:  could not find gem activerecord-postgresql-adapter locally or in a repository
aleph:src mel$ sudo gem install activerecord-postgresql-adapter
ERROR:  could not find gem activerecord-postgresql-adapter locally or in a repository
aleph:src mel$ sudo gem -r install activerecord-postgresql-adapter
ERROR:  Invalid option: -r.  See 'gem --help'.
aleph:src mel$ sudo gem install -r activerecord-postgresql-adapter
ERROR:  could not find gem activerecord-postgresql-adapter locally or in a repository

To install the correct the correct pg gem, use the following command:

# sudo env ARCHFLAGS="-arch i386" gem install pg

There seems to be a version difference between the two difference postgres adapeters : pg (0.7.9.2008.10.13) versus postgres (0.7.9.2008.01.28). Only time will tell if this will lead to framework incompatibilities.

ActiveRecord

To use the scaffolding in any meaningful manner requires a clear object model that can be used to represent system objects. The ActiveRecord::Migration class provides detailed usage information that is required to generate these classes and the associated database types. However, details such as the rails type to database type mappings are not easily found in Rails API. The following links highlight the most important features of ActiveRecord objects which will hopefully allow more informed use of this fundamental Rails object.

Object Associations

As ever, the initial challenge when creating an application is to create an object model that reflects the system being designed without imposing unnecessary limitations. There are a number of relationships that can be modeled through Rails, but it is important to understand both the usage and limitation of these mechanisms.

  • Rails only supports Single Table Inheritance - By default only Single Table inheritance is supported by Rails. Essentially, different subclasses are represented by a :type field in the database table. To avoid confusion, treat type as a Rails keyword an only use it when you want to model Inheritance.

  • Polymorphism is supported through the :has_many :has_one/ :as mechanism - common functionality can be shared amongst objects by implementing an interface. This requires the implementing object to have interface_id:integer and interface_type:string columns within their database models.

  • The difference between :has_one and :belongs_to is largely where the foreign key resides. - The :belongs_to implementation should have the corresponding foreign key to the referenced object.

  • Many-to-many relationships can be modeled in a number of ways. Direct relationships can be modeled using has_and_belongs_to_many. If the association needs to be manipulated independently, the has_many :through relationship will do provided a join table is created to associate the two models.

  • Secondary associations using :through. Both the has_one and has_many associations support secondary references through intermediate objects.

Object Hierarchies

There are built-in mechanisms with Rails to model ordered lists, trees, and hierarchies.

  • :act_as_list - allows a collection of object to function as an ordered list. This requires a position column within the model.
  • :act_as_tree - allows a collection to behave as a tree. Requires the parent_id column within the model.
  • :act_as_nested_set - allows a collection to behave as a hierarchy. The advantage over :act_as_tree is that individual nodes can be retrieved with their dependent objects. This model requires the use of the following columns : parent_id, lft, rgt.

Validations

Data sanitation is paramount to preventing a whole host of database injection attacks. Always assume that any publicly submitted data can be used to compromise the system. To mitigate these types of attacks, ActiveRecord supports validation of conditions and fields (see above). It is highly recommended that validations be exercised in the testing framework to ensure their proper functioning.

February 12, 2009

RailRoad III

Testing

You can't really follow the the Test Driven Development methodology without writing tests as you develop. While the ROR documentation is fairly complete to get started on building an application, the organization of the documentation (as well as most reference material) seems to put testing at a lower priority in the context of the learning the Rails platform. It would be nice if the documentation illustrated TDD within the examples as well.

Fixtures

Rails provides a facility for quickly creating reproducible testing data through YAML fixture files. The key point of using a fixture as of 2.2.2 is that it is essentially a fully fledged ActiveRecord. When you run a test against a feature, one of the first things that happens is that Rails populates the database table with the fixture information. It is important that your fixture YAML file is syntactically correct - if the data specified in the file references an undefined column or violates a database constraint, Rails will fail to run the test and generate a whack tonne of arcane error messages. Don't do this unless you like to read stack traces.

Strange Boolean Behavior. If validates_presence_of is placed on a boolean attribute, it can only be assigned true values within the fixture. Attempting to assign false to the fixture attribute will break unit tests with the following error:

Attribute_name can't be blank.
 is not true.

In addition, when assigning boolean values within tests, you cannot use the false keyword. Doing so will create an invalid record. The numeric convention to assign true or false is to use 0 and 1 respectively.

Validation of Date versus DateTime Objects. Fixtures can use eRB to embed ruby code within the fixture itself. Unfortunately, when it comes to Date / DateTime attributes, the object returned by the fixture record is database dependent. In most cases, to validate date/time attributes requires using the strftime comparison. There is no way to get a Date object from a DateTime object. Seems intuitive, but Rails does not provide this facility. For simplicity, I've included the format parameters for posterity:

%a - The abbreviated weekday name (``Sun'')
%A - The  full  weekday  name (``Sunday'')
%b - The abbreviated month name (``Jan'')
%B - The  full  month  name (``January'')
%c - The preferred local date and time representation
%d - Day of the month (01..31)
%H - Hour of the day, 24-hour clock (00..23)
%I - Hour of the day, 12-hour clock (01..12)
%j - Day of the year (001..366)
%m - Month of the year (01..12)
%M - Minute of the hour (00..59)
%p - Meridian indicator (``AM''  or  ``PM'')
%S - Second of the minute (00..60)
%U - Week  number  of the current year,
        starting with the first Sunday as the first
        day of the first week (00..53)
%W - Week  number  of the current year,
        starting with the first Monday as the first
        day of the first week (00..53)
%w - Day of the week (Sunday is 0, 0..6)
%x - Preferred representation for the date alone, no time
%X - Preferred representation for the time alone, no date
%y - Year without a century (00..99)
%Y - Year with century
%Z - Time zone name
%% - Literal ``%'' character
t = Time.now
t.strftime("Printed on %m/%d/%Y")  
    #=> "Printed on 04/09/2003"
t.strftime("at %I:%M%p")            
    #=> "at 08:56AM"

Attempting to resolve the fixture issues highlights one of Rails glaring deficiencies - the lack of authoritative, comprehensive documentation. From IRC, to the blogs I researched to troubleshoot these issues, it was apparent that everyone had rather unsubstantiated opinions regarding built-in testing facilities on Rails which were largely incomplete. No application is perfect, but this is a rather obvious omission.

testhelper.rb

By default, the testhelper.rb file has the fixtures :all parameter enabled. If your scaffold YAML files are not valid, this setting will only throw a lot of unintelligible errors. To build up your test suite one model at a time, it might be useful to simply have a script with ruby commands to run tests you've already finished. For example, I have a file that I've chown to be executable which contains commands to run individual tests.

ruby unit/model1_test.rb
ruby unit/model2_test.rb

The testhelper.rb file is not all bad. In fact when used in it's primary capacity, it's quite useful. For example, instead of writing custom assertions for my unit tests, I placed a bunch of these in testhelper.rb. This allows you to follow the DRY (Don't Repeat Yourself) principle an simplify test suite creation. Combined with TextExpander, it's positively stunning how quickly you can create a fairly thorough test suite for a model. I've included some of my custom assertions so that others don't have quite the barrier to entry that I encounter:

def assert_not_valid(object, 
    msg="Object is valid when it should be invalid")
  assert(!object.valid?, msg)
end
alias :assert_invalid :assert_not_valid
  
def assert_presence_required(object, field)
  # Test that the initial object is valid
  assert_valid object
   
  # Test that it becomes invalid by removing the field
  temp = object.send field
  object.send "#{field}=", nil
  assert_invalid object
  assert !object.save, 
    "Cannot save record with invalid #{field}"
  assert object.errors.invalid?(field), "Invalid #{field}"
   
  # Make object valid again
  object.send("#{field}=", temp)
end
     
def assert_has_attribute(object, field)
  assert object.has_attribute?(field), 
     "#{object}.klass is missing #{field}"
end
	
def assert_doesnt_have_attribute(object, field)
  assert !object.has_attribute?(field), 
    "#{object}.klass is includes #{field}"
end 
	
def assert_has_readonly_attribute(class_type, field)
  attribute = class_type.readonly_attributes.find { |attr| attr == field }
  assert_not_nil attribute, 
     "#{field} read only attribute was not found."
end
	
def assert_required_length_less_than(object, field, length)
  duplicate = object.dup

  # Valid at length-1
  duplicate.send "#{field}=", "a"*(length-1)
  assert_valid duplicate

  # Valid at length
  duplicate.send "#{field}=", "a"*length
  assert_valid duplicate

  # Invalid at length+1
  duplicate.send "#{field}=", "a"*(length+1)
  assert_invalid duplicate
  assert duplicate.errors.invalid?(field), 
    "Invalid length of : #{field}"
end
	
def assert_inclusion (object, *list)
  assert list.include?(object), "#{object} not in #{list}"	
end
	
def assert_numerical(field)
  assert Integer(field) || Float(field), 
    "The field is not a number."
end
	
def assert_positive_number(field)
  assert_numerical field
  assert field > 0 , "The field is not a positive number."
end
	
def assert_negative_number(field)
  assert_numerical field
  assert field < 0 , "The field is not a negative number."
end
	
def assert_uniqueness_of(object, field)
  duplicate = object.clone
		
  assert_invalid duplicate, 
    "The #{field} attribute must be unique."
  assert duplicate.errors.invalid?(field), "Invalid #{field}"
end
	
def assert_inheritance(object_class, object)
  assert_kind_of object_class, object, 
     "#{object} is not a kind of #{object_class}."
end

Pluralization Conventions

One of the things that I needed to get used to was the use of pluralization of objects in Rails. From table names in migrations, to polymorphic has_many associations, being able to specify either single or multiple objects requires being aware of when rails expects plurals. As I mentioned in a previous article, pluralization is controlled through inflections.rb. This is something to reiterate again, unless you want to learn the hard way.

Counter Cache attributes. A counter cache attribute added to a model, is expected to be a pluralized (and possibly inflected) name. For example, to add a Comment object counter cache to another object requires the comments_count attribute to be present.

Limitiations of Single Table Inheritance

The implementation of object inheritance in Rails can only be described as extremely rudimentary. As per Fowler's description of this pattern, a single table is responsible for all base and subclass data. While this is great for subclasses that simply add attributes to a base class when they are subclassed, this does not work so well when derived subclasses have different attributes.

Lack of Class Attribute Encapsulation. Essentially, Rails implementation of STI does not allow subclasses to specify which attributes belong exclusively to themselves. An attribute that is available from one subclass is automatically available to all sibling subclasses. There is no mechanism to disable attribute accessors for certain classes, and enable them for others. It seems the only advantage of STI in rails is to provide convenient way to encapsulate methods and provide a mechanism for storing an object Class name in a table. Not exactly what I would consider Object Oriented .... While it has been suggested that attribute accessors can be overridden within the models, this seems like too much of hack that could have unintended consequences with regards to ActiveRecord behavior. The trade off is to probably code in logic in the classes to ensure that only certain attributes have valid values - the lesser of two evils.

Storage of Class Name as the Base Type in Associations. If polymorphic associations are used in conjunction with STI, the association_type by default must be the base Class name. If it is the actual class name, the association will fail. There are hacks that will allow the actual Class name to be stored by overriding the association_type attribute, but doing so is less than all encompassing. For example, having :dependent => :destroy conditions on the association will fail when this hack is implemented. This would then require manually destroying associated objects. Not really a great compromise in my opinion.

Miscellaneous

Sometimes things just don't work the way you expect them to. In most cases, it's probably just a case of the documentation not being updated with changes in the code. One particularly pernicious bug was the way in which ActiveRecord deals with obj.clone versus obj.dup.

Limitations actually a Good Thing?

While these limitations suggest that these areas of Rails are under developed, Martin Fowler has an interesting take on the rigidity shown by the core rails team to solving "enterprise" problems. In his article he suggests that Rails resistance to antiquated conventions which give strength to the existing system. This goes to prove just because you can do something, doesn't mean you should (such as attempting to create an Object Relational Mapper for Rails - RHibernate anyone?).

I reserve the right to withhold judgment ...

January 18, 2009

Professional Developer Tools OS X

There are just some tools that make life easier. Although I'm a self proclaimed CLI junkie, I think that adhering to fundamentalist attitudes only leads to atrophy. To that end, I'd like to suggest a couple of tools that I grudgingly have to admit are better than their command line equivalents. Its not these tools should be used without knowledge of their CLI counterparts; it's just that having graphical equivalents somehow refines their usage and reduces cognitive resistance when you're in the Flow.

Cornerstone

I can't say enough about Subversion, but trying to keep track of changes between commits and doing diff comparisons with your working set versus the last revision is nothing short of a PITA. Thankfully, there is mature, stable graphical Subversion client for OS X - Cornerstone. It does a great job of abstracting various Subversion operations and does not suffer from extreme featuritis. Give it a try if your tired of looking up man pages to get just the right svn syntax.

Araxis Merge

While diffing files is old hat, the output is just barely human readable. Too much effort is expended by the user trying to visually grep the output. They say a picture is worth a thousand words, in the in spirit of "Ut pictura poesis" I would have to agree when using a visual diff tool. Having side by side comparisons greatly improves the ability to use diffs in a more coherent manner. Thankfully, Araxis has ported their flagship Merge tool to OS X. Like Cornerstone, the features are implemented with minimal clutter. This allows it to integrate cleanly into an XCode based work flow. With its seemless integration with Cornerstone, checking working copy diffs to a source code repository can't get any easier.

O'Reilly Safari

Do your self a favor and forget the forest of books that inevitably become obsolete and sign up for a Safari subscription. Technical books have a limited shelf life. Prevent become antiquated and get the latest documentation without the hassle of having to lug around a dead tree. It's not that I don't like physical books, but the rate at which technical documentation evolves makes it unrealistic to have a well stocked reference library without having to spend a fortune. Combined with the BookBag iPhone app, you can have your cake and eat it too.


February 26, 2009

Fink, ImageMagick, and RMagic Installation for Rails

It took me a while to figure out how to get Fink to install ImageMagick and the RMagic gem for use with attachment_fu and I thought I would share my method. From the #rubyonrails channel on freenode, it seems that I am a Luddite; most users prefer MacPorts. As I've written before, I think there is value in understanding the ports system you are using in OS X and that there be a clear separation between system binaries and those you add yourself. Polluting the /usr directory with unsupported 3rd party code can only lead to heartache. It also helps to acknowledge the underlying software dependencies in case your production environment varies from development (which is my case). That being said, I've provided the link for those who just have to use MacPorts.

ImageMagick & Fink

Before the rmagic gem can be used, ImageMagick needs to be installed on the machine. Fink is great at being able to build from source and resolving dependencies, but in this case, it took a bit of coercion to get ImageMagick installed. At various points during dependency resolution (for ghostscript and dbus-dev), I was required to abandon FinkCommander and issue the following commands from a Terminal:

# fink scanpackages
# sudo apt-get
# sudo apt-get install ghostscript=8.61-5
# fink scanpackages
# sudo apt-get
# sudo apt-get install dbus-dev=1.2.6-1

I'm assuming that order is important in the dependency resolution process, so I included both sets of commands which needed to be run separately at different points in the installation process.

This eventually installed ImageMagick, but unfortunately, the default configuration included the dreaded --enable-hdri option. Fixing this required digging into Fink source code management internals. By default, Fink keeps ports metadata information in .info files which are arranged based on stable/unstable trees as well as by function. For ImageMagick, the relevant files were located in the /sw/fink/10.5/unstable/main/finkinfo/graphics directory. A grep against the ImageMagick files revealed that imagemagick-nox.info and imagemagic.info both contain the option. Simply removing it from these files and rebuilding the ImageMagic port resulted in an rmagic compatible installation.

# fink rebuild imagemagick

There are a number of supplementary packages that are required to build rmagic; I've included a list of the required ports:

# imagemagick
# imagemagick1-dev
# imagemagick1-shlibs
# imagemagick1-svg

In particular, be sure to have the imagemagick1-dev port installed, otherwise Magick-config will not be installed which is required for gem installation.

scripts/plugin fail

I usually try to follow the path of least resistance - In this case, it was to use the built-in plugin managment utility in Rails. Unfortunately, no matter how I spelled rmagic, the plugin could not be found in the sources packaged with 2.2.2. I even tried to find the plugin with rapt. C'est la vie.

RMagic Installation from Source

Although the preferred method of installing Rails components is by using gem, OSX's fonts break the rmagic tests that run when documentation examples are being generated. This leaves the method of last resort - installing from source. The trick is to change the allow-example-errors=no parameter to yes in the .config located in the source directory. Once this is done, run the following commands:

# sudo ruby ./setup.rb
# sudo ruby ./setup.rb install

Presto! At this point RMagic should be installed on your system. You can verify by running the following commands (as per the MacPorts installation doc):

# irb -rubygems -r RMagick
>> puts Magick::Long_version
This is RMagick 2.9.1 ($Date: 2009/01/12 23:08:35 $) Copyright (C) 2008 by Timothy P. Hunter
Built with ImageMagick 6.4.1 02/25/09 Q16 http://www.imagemagick.org
Built for ruby 1.8.6
Web page: http://rmagick.rubyforge.org
Email: rmagick@rubyforge.org

All in all, the process is not unlike a contortionist attempting to pick their nose with their pinky toe .... doable, but certainly uncomfortable. Comments welcome.

March 17, 2009

Testing is Insurance Against Technical Debt

I've been ghosting YCombinator's Hacker News and one of the most interesting articles I recently read was by Martin Fowler on the idea of Technical Debt. Coined by Ward Cunningham, the idea is simple - taking a quick and dirty approach to a solution burdens a project with technical debt. This debt is the future effort required to refactor existing code into something more elegant, and ultimately more useful. While the concept explains why people may choose trade-offs in the name of expediency, what struck me most about the metaphor is how the role of testing in the development process could offset this technical debt as a form of "insurance". Tests preserve the original requirements without necessarily committing a developer to a specific implementation. So long as the implementation preserves the requirements, this technical debt can be managed.

One of the most direct measurements of software productivity is the ability to deliver on schedule. By accumulating technical debt, part of your development time is spent either servicing the costs of that debt (by having to code around the original hacks) or paying down the principle (by refactoring). This is the true cost of technical debt. When this debt begins to dwarf the principle value of an application, it is all to easy to default on this debt by slipping deadlines. While tests do nothing to reduce this debt, they prevent it from accumulating additional interest. Without tests, the situation quickly becomes untenable. Instead of Insurance, what you have is a Credit Default Swap. At this point, productivity is a synthetic derivative which has no bearing in reality. All productivity is lost in Complexity.

Put another way, is it possible to pay down technical debt without tests? I'm inclined to think not.

Since we're using economic metaphors, I'll use the prophetic words from the Oracle of Omaha which illuminate the cost associated with testing:

Price is what you pay, value is what you get.

The price incurred for having to implement and maintain tests far outweighs the value they provide for your application. The only certainty in development is that requirements will change as a program evolves. Tests are insurance against these "known unknowns".

As with all my articles, comments (not spam) are welcome.

November 17, 2009

Snow Leopard Gotchas

Missing User

After upgrading to Snow Leopard (OS X 10.6), I noticed that the PostgreSQL user I created for development using dscl had suddenly disappeared. Apparently any users that are not created through System Preferences -> User Accounts are excluded during the upgrade process. Strangely, the group associated with this PostgreSQL admin user was still present after the upgrade. It was trivial to restore functionality, but a bit irritating. At least I wasn't stung by the Guest user fiasco that has been finally fixed in 10.6.2.

Now that's out of the way, why is my subversion launchd entry being ignored? Hrmmm ...

IR/EyeTV Oddities

Another thing I noticed was the complete miscommunication between the IR Remote that came standard with older Macs and EyeTV. IR controls were either mismapped (resulting in strange interactions with EyeTV) or completely non-functional. Thankfully, this was resolved easily with the installation of Candalair - an alternative driver for internal Apple IR Receivers. By enabling Leopard Compatibility Mode, things were back to normal. This is obviously a known problem given the very existence of a compatibility mode, but why won't Apple actually fix the problem?

Printing?

One of the primary reasons for me considering OS X a few years ago was the tight integration of device drivers (for things such as printers) with the OS. I was tired of trying to configure PS emulation for standard photo printers in Linux. Printer configuration was by far the biggest PITA under free *nix varieties. Being able to install a printer painlessly was, for me, a true measure of usability.

Boy, have times changed. Where as my initial experience with 10.4 was the pleasant surprise of "wow that worked the first time", Snow Leopard has changed this process into an all too familiar experience of disappointment. Broken driver support for a slew of existing printers formerly supported by Leopard (10.5) was painful, to say the least. The process of upgrading the drivers with Apple's driver fix failed to notify users that existing print queues would NOT function until they had been recreated was completely obtuse in a way reminiscent of Windows. Oh well, so much for the usability advantage.

To see just how badly this process has devolved, try setting up a Canon Pixma 420 for wireless network printing. A friend of my got one of these with his new iMac, and nothing short of a herculean effort got this printer to work with OS X. Can you say "obscure"?

Quicktime X Black Screen

A new and improved Quicktime was supposed to be a boon to Snow Leopard. Unfortunately, right out of the gate, Quicktime X support in Front Row was broken for almost all files. Attempting to play any media files in Front Row resulted in a black screen with no audio or video. 10.6.1 at least restored the ability to play .avi files, but I had to wait until the recent 10.6.2 update to finally have support restored for .mkv's. What happened to releasing a functional product? Given legacy Quicktime support is available in Snow Leopard, wouldn't it have been prudent to wait until this version of Quicktime was ready for prime time before releasing it for public use? At the very least, it shouldn't have broken existing functionality. Where are the QA regression tests?

At What Cost?

I understand the primary motivation behind any public company is profit and Apple is no exception. But what is the cost of relentless push for greater market share if they start to diverge from their core philosophy of "just works"? From a consumer standpoint, there are increasingly compelling reasons to question Apple's current strategies, specially if it comes at the cost of keeping existing customers satisfied. I purchased Apple products because I did not want to contribute to the cycle of "disposable" electronics. Little did I know that by design, this is exactly what I've ended up with.

Hackintoshes are looking better every day ...

December 9, 2009

Snow Leopard Mysteries

The upgrade to Snow Leopard left certain parts of my system non-functional. Not good considering that a number of these components are crucial to my development process. Here are the hacks/work-arounds I discovered restoring these services:

Subversion

Subversion running locally on my MacBook Pro requires that the Remote Login privilege be enabled to support svn+ssh secure tunneling mode. For some strange reason, the upgrade to OS X 10.6 disabled this privilege breaking my ability to connect to my subversion server. Luckily, my installation notes reminded me of this requirement and after a visit to System Preferences -> Sharing, I was able to restore access.

PostgreSQL

As I documented with my previous post, the custom PostgreSQL user I created to run the database was deleted by the upgrade. This oversight did not extend to the database installation itself, but recreating the user did not automatically restore database functionality. After a bit of digging around, it seems that my previous PostgreSQL user was assigned a different user id. A peek at the ownership privileges on the database files and directories revealed ownership permissions which did not correspond to a valid system user. A quick chmod -R fixed the permission problem and allowed PostgreSQL to be started correctly.

Fink Commander

I've been using Fink Commander to manage packages I've installed on my system over the last two versions of OS X and encountered no obvious upgrade problems when migrating to newer versions of OS X. This changed with Snow Leopard. After upgrading to 10.6, I noticed that despite having updated Fink via the command line, Fink Commander refused to display any package information. Despite an exhaustive search when I first upgraded to Snow Leopard, I was thwarted; I had no clue how to fix this issue. Jump forward a few months and it seems that I was not alone: a solution was finally posted. Due to the number of different perl binaries packaged with OS X, an explicit path to the older perl binaries was required. Under Fink Commander 0.5.5, this path can be set by navigating to Preferences -> Paths -> Paths to Perl. For OS X 10.6, this value should be /usr/bin/perl5.8.9. The original post can be found here.

Mysteries solved.

About Eunichs

This page contains an archive of all entries posted to Z1R0 in the Eunichs category. They are listed from oldest to newest.

Many more can be found on the main index page or by looking through the archives.

Colophon

Creative Commons License
This weblog is licensed under a Creative Commons License.