Monthly Archives: May 2009

Installer sympathy for Linux

Nice to see [the installation process on Linux][rpm] can be [as misguided as it is on Mac OS X][installer].

> The irritating thing about these system manglings is that by and large they’re unnecessary, especially things like the JDK ugliness. These companies are not running into novel problems in building RPM packages, and other software manages to do the right thing. The companies were just lazy. (And because of the license terms of their software, outsiders can’t fix the problem, build proper packages, and distribute the results.)

[Chris Siebenmann’s blog, Wandering Thoughts][chris].

[rpm]: http://utcc.utoronto.ca/~cks/space/blog/linux/BadRPMPackaging
[installer]: http://reliablybroken.com/b/tag/installer/
[chris]: http://utcc.utoronto.ca/~cks/space/blog/

Adobe AIR installer, a hateful tradition

[Tweetdeck][tweetdeck] seems to be the path of least resistance for a desktop
[Twitter][twitter] client on Mac OS X 10.4 (there are other free Mac desktop
clients, [Nambu][nambu] and [Tweetie][tweetie] but unfortunately they both
require 10.5).

But Tweetdeck requires the [Adobe AIR runtime][air]. And the Adobe AIR 1.5
installer takes Adobe’s favourite approach of ignoring Mac OS X’s package
installer format in favour of a custom installer application.

When you open the installer, it takes a few seconds and then gives you a
license agreement. Here’s an excerpt:

> 2.3 Distribution. This license does not grant you the right to sublicense
> or distribute the Software. For information about obtaining the right to
> distribute the Software on tangible media or through an internal network or
> with your product or service please refer to…

I read that as explicitly banning any efforts to create a package
to ease the pain of deploying AIR across a bunch of Macs. Damn it.

Clicking Accept moves you to the installation proper, and Adobe loses a few
more points by immediately throwing up an authentication dialog box. Why does
this dialog appear? What am I about to install? If only this was a package
installer I could have looked at the installation manifest to get an idea of
what was going to happen *before* granting the installer free rein to my
computer.

Turns out that everything you care about is installed in `/Library/Frameworks/Adobe AIR.framework` and `/Applications/Utilities/Adobe AIR Application Installer.app` and `/Applications/Utilities/Adobe AIR Uninstaller.app`. For some reason the installer also touches a couple of files in `/Users/Shared/Library/Application Support/Adobe/AIR/Updater` and slips a couple utility apps in your `Library` somewhere. You can ignore those.

It feels particularly wrong when non-system applications put things in the `Utilities` folder – it is effectively a special system directory, and its contents are tools for tinkering with the system configuration or for diagnostics. Adobe Creative Suite 3 likes to create a folder `Adobe Installers` in there *and* `Adobe Utilities`, just in case you haven’t worked out how much you need their software on your computer.

Heaven is almost certainly running System 6.0.8. Nothing is installed without [Font DA Mover][fontdamover].

[air]: http://www.adobe.com/products/air/
[tweetdeck]: http://www.tweetdeck.com/
[nambu]: http://nambu.com/
[tweetie]: http://www.atebits.com/tweetie-mac/
[twitter]: http://twitter.com/
[fontdamover]: http://download.info.apple.com/Apple_Support_Area/Apple_Software_Updates/English-North_American/Macintosh/System/Older_System/System_6.0.x/TrueType/

Using plists for site-specific Django settings

I have a [Django][django] project that I am going to deploy at several sites, but I need
to tweak the project settings slightly for each site. Specifically I need
different a [EMAIL_HOST address and related settings][emailhost] for sending mail at each
site.

The simplest route is to customize the project settings.py as part of the
site deployment, but that will drive you insane when you deploy the wrong
custom-settings to a site.

Another approach is similar to that used by many for switching between settings
when moving between testing / staging / live environments: your `settings.py`
has a few lines something like

try:
from sitesettings import *
except ImportError:
pass

so you can over-ride any setting by putting them in a `sitesettings.py` file,
and then make sure your deployment never overwrites that site-specific file.

In my case I want to make it easy for the site administrator to customize
the settings, but I am worried that it is too easy for someone who does not
know Python syntax to inadvertently break things by writing a `sitesettings.py`
that throws [a `SyntaxError` exception][syntaxerror]. Given the significance of
white-space in Python I feel this would be easy to get wrong.

So I’ve gone for storing the custom settings in Mac OS X’s [property list
format][manplist]. Bless Python for it has [the plistlib module][plistlib] that reads
and writes the simple XML format of property lists.

Here’s my module that imports all properties from a plist straight into the
module’s namespace. This then makes it easy to over-ride Django’s settings
by doing

from plistsettings import *

A couple bits made my lips move during the writing. The contents of `__all__`
are updated dynamically because I wanted to use this with
`from plistingsettings import *` without worrying that my module’s imports
would get clobbered by imports used in the `plistsettings` module. And working
out how to bind keys and values to the module itself is not obvious to me –
it *feels* like one ought to be able to use `self` within the scope of the
module to refer to the module itself. Except you can’t. No biggie.

# plistsettings.py
import os.path
import plistlib
import sys
from xml.parsers.expat import ExpatError

__all__ = []

PLIST_PATH = ‘/Library/Preferences/com.example.plist’

def read_prefs(plist_path):
“””Import settings from preference file into this module’s global namespace.

Returns a dictionary as returned by plistlib.readPlist().
“””
try:
if os.path.exists(plist_path):
prefs = plistlib.readPlist(plist_path)
else:
return
except ExpatError:
return

mod = sys.modules[__name__]
global __all__

for key, value in prefs.items():
setattr(mod, key, value)
__all__.append(key)
return prefs

read_prefs(PLIST_PATH)

Now if you are the kind of Mac guy who enjoys using `defaults` you can write
out your site-specific settings from the command-line.

defaults write /Library/Preferences/com.example EMAIL_HOST smtp.example.com
plutil -convert xml1 /Library/Preferences/com.example.plist

N.B. Mac OS X 10.5 `defaults` uses the binary format by default, so you need
`plutil` to convert it back to XML because `plistlib` does not handle
the binary format.

[django]: http://www.djangoproject.com/
[emailhost]: http://docs.djangoproject.com/en/dev/ref/settings/#email-host
[syntaxerror]: http://docs.python.org/library/exceptions.html#exceptions.SyntaxError
[plistlib]: http://docs.python.org/library/plistlib.html
[manplist]: http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html

10.5.7 fixes AppleShare speeds

The recently-released [Mac OS X 10.5.7 update][1057] fixes the atrocious AppleShare transfer speed bug that was introduced by 10.5.6. The problem was that copying files larger than a few hundred kilobytes to certain AppleShare servers (including Mac OS X Server 10.4.11) would go *extremely* slow, and usually fail after a minute.

But copying files from the server to your Mac was hunky dory! Fun.

I like to think the programmers at Apple refuse to consider allowing software to be released until they have written comprehensive tests for regression testing. I like to think I do the same (I don’t, but I respond faster when you want my attention).

[1057]: http://support.apple.com/kb/HT3397