Archive for 2007

An invalid property list

Monday, October 1st, 2007

If you work on an [added: a document-based] app that uses a plist-based format, you should test your plist-reading code to see how it handles an invalid (e.g., eaten by the user’s dog) plist. Here’s one:

<plist>
<qux></qux>
</plist>

The binary plist parser won’t even touch it because it doesn’t have the bplist header, the XML parser will choke on it because it contains an element that it doesn’t recognize, and the OpenStep parser will choke on it because the first line doesn’t end with a semicolon or backslash.

When you feed this to your app, your app should present an error message. Anything else is a bug. (UPDATE 2007-10-02: OK, maybe not. There’s at least one circumstance where you can ignore it, as pointed out in the comments. I still think I’m right in most circumstances, just clearly not all.)

Apple Easter eggs are not dead

Sunday, September 30th, 2007

From QA1420:

A screenshot of an open menu, with the items “Mini”, “Nano”, and “Piqueño”.

(In case you don’t get it, here’s the reference.)

I am now an Amazon customer

Saturday, September 29th, 2007

They finally started selling something that I want to buy.

Almost since the iTunes Music Store first opened, I’ve been a customer of the iTunes Store. 99¢ a song is fine by me, and I love paying by the song. There are few albums so consistently good that I’ll buy the whole thing.

Then iTunes Plus started, and I immediately switched over. Sure, it’s 30¢ extra, but I pay that 30¢ as a statement against DRM.

Then came the Amazon MP3 Store.

Amazon sells plain old MP3s, at roughly 256 kbps VBR (in order that nobody can complain about the encoding quality). Since they’re plain old MP3s, there’s no DRM.

Even better, Amazon beats iTunes’ prices: 89–99¢ per song. iTunes charges $1.29 (remember, no DRM, so the proper comparison is to iTunes Plus rather than to non-Plus).

So, in short:

  • The encoding is almost as good as or better than iTunes.
  • The price is the same as or less than iTunes.
  • Amazon’s MP3s are never DRMed, whereas iTunes’ MPEG-4s are usually DRMed.

Like Simone, I shall buy from Amazon first from now on. (I haven’t switched away from iTunes; they’ll continue to get my business for songs that Amazon doesn’t carry. But, unfortunately for Apple, I expect that set to diminish.) Take notice of this, Apple—get the record labels to let you lower your prices, or you will lose serious market share to Amazon.


Just in case you’re wondering…

The Amazon MP3 Store works by downloading a file in a special format: .amz. This is a document for the Amazon MP3 Downloader application. (In case you’re wondering, the contents are some binary data, which may just be ciphertext of some sort, encoded in base64.)

The reason they do this is so that it can download the MP3s into a subfolder of your Music folder, rather than your usual Downloads folder (normally your Desktop). That’s good, but it has two downsides:

  1. You need a Windows or Mac OS X PC to download MP3s from Amazon, even though the MP3s themselves will play anywhere.
  2. If your browser is set not to auto-open files, or doesn’t trust the Amazon MP3 Downloader, then you may be sitting there for a moment wondering why the Downloader is not doing anything.

My suggestion to Amazon would be to switch to a custom URL scheme, rather than a custom file format. I don’t know about Windows, but this would certainly make it much easier on the Mac, since the custom URL scheme will always work. (It won’t help the non-Mac non-Windows users, though, since you still need the Amazon MP3 Downloader to handle the custom URL.)

New utility: Make RAM Disk

Saturday, September 29th, 2007

Make RAM Disk is a simple app to create and mount a RAM disk on Mac OS X 10.4 or later. It encapsulates my previously-stated series of terminal commands into a tiny little app—just launch it and go.

I use my RAM disk for three things:

  • Download holding area. I have Mail, Safari, OmniWeb, and Adium all set to download files to the RAM disk. If I decide I don’t want to keep the download, I just leave it there until shutdown (only works on my desktop Mac).
  • iShowU storage. I create a 1-GiB RAM Disk named “iShowU temp” which iShowU is set to use as its scratch disk. Using a RAM disk for this helps your recording frame rate.
  • Xcode build folder. On my laptop, I symlink the project’s build folder over to the RAM disk (e.g., mkdir /Volumes/RAM\ Disk/Adium-build && ln -s /Volumes/RAM\ Disk/Adium-build build). This cuts out a lot of the disk grinding that happens during a build, which I believe helps my battery life.

Enjoy!

Ghostwriter has invaded my menubar!

Thursday, September 27th, 2007

All the lowercase e's in my menubar are missing from all of OmniWeb's menus (except for Help, strangely enough). A blank space shows instead.

WTF?

And no, it’s not just in OmniWeb (or, for that matter, my menubar):

Same goes for capital F and lowercase L in Mail's Activity Viewer window.

Appcasts on Google

Thursday, September 27th, 2007

If you publish an appcast, you should also publish a robots.txt file that tells search engines such as Google not index the appcast file. I came to this realization after searching for “appcast editor”: the first four hits, and several of the others, are all just appcasts.

There is no point to having these indexed by Google, so save the bandwidth and help people’s search results—tell the search engines not to index them.

And I never did find an appcast editor. I guess I get to write it by hand in vim. (There’s one in MacCode, but it’s not working yet.)

UPDATE: I knew there was an appcast editor out there! It’s Feeder, by Reinvented Software. Thanks to Andy Kim for pointing it out in the comments.

I do believe we have a record

Monday, September 24th, 2007
pngout \        %~/Projects/@otherpeoplesprojects/growl/trunk/Core/Resources(0)
> NotifyOSX.growlStyle/Contents/Resources/sidetitle.png 
 In:                             NotifyOSX.growlStyle/Contents/Resources/sidetitle.png
 In:   29644 bytes
Out:                             NotifyOSX.growlStyle/Contents/Resources/sidetitle.png
Out:     527 bytes               
Chg:  -29117 bytes (  1% of original)

My Simpsons avatar

Sunday, September 23rd, 2007

What I look like as a Simpsons character.

Part of the website for The Simpsons Movie; found on Chad Weider’s blog.

Vacation numbers

Sunday, September 23rd, 2007
  • Days gone: 3
  • New mail messages: 75
  • New messages in RSS feed: 86
  • Miles driven (total): 133

Commercial Success

Tuesday, September 18th, 2007

Now on iTunes: An endcap with various songs from commercials. They’ve done this before, but this time, the first four tracks are from recent Apple commercials, including the one from the iPhone commercials.

zsh completion rocks

Monday, September 17th, 2007

Specifically, enable and configure zshcompsys. Here’s what this will get you (6 seconds; 144 K; requires any version of QuickTime):

UPDATE 2007-09-18 11:54 PDT: More info in the comments.

Report-an-Apple-Bug Friday! 70

Friday, September 14th, 2007

This bug is Borken implementation of -setNilValueForKey: in Model Object Impl Guide. It was filed on 2007-09-14 at 12:24 PDT.

(more…)

Quickie: Bindings and KVV

Tuesday, September 11th, 2007

If you want Bindings to call your Key-Value Validation methods, you need to check the Validates Immediately checkbox in the binding editor in IB.

In my case, this was with an NSTableColumn’s value binding in an NSTableView.

A note about your WordPress blog’s tagline

Tuesday, September 11th, 2007

On the general options pane, there is a field labeled “Tagline”:

Tagline: cd prh && dd if=brain of=blog

The value shown in that field is WRONG WRONG WRONG!

You see, that’s actually supposed to be HTML—or at least, such is the implication of the Atom template’s use of bloginfo_rss to get the description. The difference between {get_,}bloginfo_rss and {get_,}bloginfo is that the _rss versions call strip_tags to take out any HTML and escape any non-HTML characters, such as &.

That wouldn’t be so bad if strip_tags worked properly, but it doesn’t—not on this host, at least. It leaves the second & in the above example unescaped. (“OK, I escaped that one. It must be the only one. I’m off to Subway!”)

As if that wasn’t bad enough, WordPress doesn’t escape the tagline field’s value when putting it back into the field the next time you load up the Options pane. (It does if it’s plain text, but not if it’s HTML. Go figure.) So if you click “Update Options” again, your HTML goes bye-bye. You need to remember to re-escape it every time you save the General Options.

(Given that, maybe it’s not supposed to be HTML after all, and the use of bloginfo_rss in the Atom 0.3 template is a bug.)

Want to know how I found this out? Because the RSS reader in Safari 2 (I don’t use 3) was critically failing on the Atom feed. It was slurring posts together once it saw that an ampersand was not escaped.

Relevant versions:

  • WordPress 2.1.3
  • PHP 5.1.4 or so (I have no idea what version is actually running the blogs)
  • Safari 2.0.4/419.3

Blog spam count: 2007-08

Monday, September 3rd, 2007

Sorry I’m late with this. Here we go.

Spam comments blocked by Negative Turing Test in August 2007 (and September 1–3):

17,837

Looks like last month’s lull was temporary. They’re ramping back up.

Apple Bug Friday! 69

Friday, August 31st, 2007

This bug is Member variable is not an Objective-C term. It was filed on 2007-08-10 at 12:13 PDT.

(more…)

My first unit tests

Friday, August 24th, 2007

Last night, I added unit tests to Adium. Despite the fact that I have espoused adding tests for some time (usually when stuff broke that would have been caught by an automated test), I actually had never created tests before.

I love it.

Here’s why I added tests, and my quick overview of how to do it.

Why

I started out looking at fixing #7713. The problem was that our display of intervals was including units of which there were zero: the example from the ticket is “1 Week 4 Days 0 Hours 43 Minutes”. (We don’t really capitalize those letters, in case you’re wondering.)

Upon investigating, I found that the method that creates these strings was complex and thinly commented, and it didn’t work in the obvious way (building an array and then joining its elements). The upshot of that was that I could guess that that the method was probably deeply broken, but in such ways that made it not obvious exactly how it was broken. This left me uncertain of how to proceed, since I had the sneaking feeling that any change had a chance of breaking something else, even if it fixed #7713.

What I needed was a complete set of diagnostics that would attempt to extract every combination of time units and make sure that all of the results were in line with my expectations.

In other words—a test suite!

The major mental block that had kept me from getting into unit testing had always been how tautological it seemed: having just written some code that does X, you then write code that makes sure X got done. This seemed redundant, mostly because I had been envisioning assigning to a variable, then checking the value in the variable to make sure it really got assigned. (Obviously, that’s wrong. I never seriously thought that people were really doing that, but couldn’t think of what else you would test.)

Now, I had a case that clearly and finally proved that real unit testing isn’t anywhere near tautological: I had code that’s broken, that I could break in some other way by attempting to fix it. Thorough testing would help me find all the ways in which it’s broken, so that I could fix it without breaking something else.

This is exactly what unit testing is for.

How

Here’s a brief summary of what you need to do to set up your project the unit tests (assuming that you’re using Xcode, version 2.1 or later):

  1. Create one or more subclasses of SenTestCase.

    Here’s what one of our tests looks like:

    - (void)testDateFormatterStringRepWithInterval_minutes {
    	//Note that we want a date in the past, because we want to describe the time interval since that date.
    	NSDate *date = [[NSCalendarDate calendarDate]
    		dateByAddingYears:-0
    		           months:-0
    		             days:-0
    		            hours:-0
    		          minutes:-10
    		          seconds:-0];
    	STAssertEqualObjects([NSDateFormatter stringForTimeIntervalSinceDate:date], @"10 minutes", @"Unexpected string for time interval");
    }

    Every individual test should be in its own method in your class, and that method’s selector must begin with “test”. Go wild—you don’t need to list them anywhere, because the test runner detects them all automatically (hence the selector-begins-with-“test” requirement). So don’t worry about having lots and lots of methods, as long as they’re appropriately categorized in different SenTestCase subclasses (for the sake of small, easily-navigable files).

    And yes, you do need to subclass SenTestCase, as it provides methods that the STAssert… macros need.

  2. Add a Cocoa/Unit Test Bundle target to your Xcode project.

  3. Add your SenTestCase subclasses to the bundle target.

    You probably should not put the test case class in your main application or framework targets. I know I can’t think of a reason why you would.

  4. Configure the Info.plist of the bundle in the usual way (Get Info on the target, then set the bundle ID and signature on the Properties tab).

Henceforth, whenever you want to run your tests, build the bundle target. You don’t need to run it, because the last phase of the target is a shell script that runs the tests. This is so that you can make the test bundle target a dependency of your main application/framework target, in order to have it run whenever you try to build the app/framework.


(Also, this is the 500th post in my blog’s WP database. Woo-hoo!)

Quicksilver + SVN = yum

Friday, August 17th, 2007

Go directly to the plug-ins pane of your Quicksilver Preferences and install the Subversion module. Do not pass Go. Do not check out $200.

Best when combined with the comma trick.

So far, I’ve tried both add and ci, and they work in the obvious way. They even provide a notification (which goes through the Growl notifier for me—that’s another plug-in) with the command’s output.

Fixing an Adium bug: A timeline

Tuesday, August 14th, 2007

I’m fixing a hole, where the rain gets in/and stops my mind from wondering/where it will go-ooo…

All times are PDT.

  • 2007-08-12 14:04:38: Evan releases 1.1 in the appcast. 1.1 is our first version that requires Tiger.

  • 2007-08-12 14:08:09: Evan puts back 1.0.5 alongside 1.1, with a sparkle:minimumSystemVersion attribute on the enclosure element noting that 1.0.5 requires 10.3.0 or later.

  • 2007-08-12 14:25:12: Evan changes 10.3.0 to 10.3.9; David had pointed out that 1.0.5 won’t run on OS versions before 10.3.9.

  • 2007-08-12 17:32:02: First user report on the feedback address from a 10.3.9 user that she had updated to 1.1 and it didn’t run on her system.

  • 2007-08-13, about 06:00: I wake up, and find six such user reports sent to the feedback list, including the first one. I answer them all saying that 1.1 requires Tiger and you can get 1.0.5 from the front page. By the sixth one, I’m suspicious that we may have a Sparkle bug.

  • 06:31:48: I join the #adium IRC channel. I have a feeling that I’m going to need to field user reports there, too. I join the Adium development channel at the same time (my IRC client is set to join both automatically).

  • From the #adium IRC channel:

    06:32:46:              Mac-arena notes that the Adium 1.1 story is #1 in Apple, #4 in Technology, and #8 in News.
  • From the #adium IRC channel:

    06:51:55:   <proton> damn sparkle updating 10.3 users
    06:53:59: <Mac-arena> Evan said he fixed it, which makes it weird.
  • 07:57:58: I fix the appcast for Panther users. Sparkle actually looks for the minimum OS version in an element named sparkle:minimumSystemVersion, not in an attribute of the enclosure element.

  • 08:13:58: I’m sending emails to Panther users who got the update notification before I fixed the appcast, then emailed our feedback address complaining that it didn’t work. Here’s an excerpt from eight such emails:

    Adium 1.0.5 is available from the front page of http://adiumx.com/, at the bottom of the page. Unless some bug arises that we need to address quickly with a 1.0.6, this is the last version that will run on 10.3.9.

  • From the #adium IRC channel:

    08:34:56:    :Server: eventualbuddha (n=eventual@[deleted].sbcglobal.net) joined #adium
    08:35:16: <eventualbuddha> congrats on 1.1 guys! in trying to update Adium it crashes though
    ⋮
    08:41:57: <Mac-arena> eventualbuddha: What version of Adium were you running at the time?
    08:42:07: <eventualbuddha> 1.0.5
    ⋮
    08:55:39: <eventualbuddha> Mac-arena, The_Tick: i should mention that the svn build i had was doing the same thing, but i just updated to 1.1 and it doesn't have that problem

    So, this user has the problem with 1.0.5 and not 1.1.

  • From the #adium IRC channel:

    08:53:58:    :Server: gammah (n=gammah@[censored].swbell.net) joined #adium
    08:54:28:   <gammah> hey I was getting crashes in the previous version of adium, on what appeared to be the 'check for updates' function
    08:54:46:   <gammah> so I manually got adium, and it seems to suffer the same fate - crashing right at startup

    This user has the problem with both 1.0.5 and 1.1.

  • 09:01:35: First ticket filed about the crash on update.

  • 09:22:11: Second ticket filed. The other tickets that will be filed about this are #7544, #7546, #7547, #7549, #7550, #7552, #7555, #7557, #7559, #7564, #7565, #7566, #7568. (Ever wonder why we don’t do more actual programming work on Adium? That’s why. However, to be fair, #7543 was filed on request from me, because we initially thought it to be a second bug.)

  • From the #adium IRC channel:

    09:23:45: <Mac-arena> dang503: Interesting.
    09:23:59: <Mac-arena> dang503: There are a lot of people getting this same crash on update in 1.0.5.
    09:24:05: <Mac-arena> dang503: And you have it in 1.1.
  • From the #adium IRC channel:

    09:47:17:   <nphase> http://pastebin.com/m28849e83
    09:48:51: <Mac-arena> Hey, let's see if we can get this crash posted to every pastebin on the internet. :D
  • By 10:00 it becomes clear on #adium that this is mostly happening to 1.1 people.

  • 10:19:02: Received first email to the feedback address reporting the crash on update.

  • 10:42: Posted to the blog acknowledging the crash and inviting users with debugger-fu to help us track it down.

  • From the Adium development IRC channel:

    10:46:12: <The_Tick> zac: go into com.adiumX.adiumX.plist
    10:46:21: <The_Tick> and change the last update time
    10:46:23: <The_Tick> to today
    10:46:29: <The_Tick> you'll be able to launch then

    The other way to do this would have been defaults write com.adiumx.adiumx SULastCheckTime '2007-08-13 10:47:00 -0700'. The effect of this would have been to forestall the crash; it would not have actually fixed it. Zac says he did not perform the edit.

  • 11:50:39: First volunteer joins IRC to help with debugging.

  • 11:57:35: First debug build goes live.

  • 12:02:05: I create a page on our wiki to keep the debug build link and provide instructions on how to step through and get a stack trace.

  • As evidence of how inaccurate the page was initially, this excerpt from #adium:

    12:12:45:      <prb> I have the build and XCode, but it's not obvious to me how to attach the debugger.  What is the necessary dance to get the attach enabled?
    12:12:59: <Mac-arena> prb: Build & Debug, cmd-y
    12:13:45:      <prb> Mac-arena: Is there a project lurking around somewhere, or do I need to download a source snapshot?
    12:14:06: <Mac-arena> prb: Erm. Right. :D Probably easiest just to use gdb
  • From the #adium IRC channel:

    12:16:34:      <prb> I'm in -- anyone got a gdb cribsheet (catch foo, etc.)
    12:16:40: <Mac-arena> prb: Writing the instructions now
  • Our webmaster, Zac, who is able to reproduce the crash (although at the time, it seems like a slightly different crash and is tentatively considered unrelated), posts his Console output, containing some NSLogs that I’d accidentally left in while diagnosing the earlier problem with the appcast (wherein the minimumSystemVersion was in the wrong place in the XML). I don’t realize it at the time, but the NSLogs actually give a hint to the problem, as they show the two minimumSystemVersion objects each used once, and then the crash.

  • From the #adium IRC channel:

    12:25:32: <Mac-arena> Note for future reference
    12:25:39: <Mac-arena> When you use cd Release && make
    12:25:42: <Mac-arena> It uses Deployment [build configuration].
    12:25:48: <Mac-arena> OK, I get to do *THAT* over.
  • 13:24:46: I post the link to the new debug build (this time actually compiled with Development build config)…

  • 13:25:51: … and update the wiki page with it.

  • From the #adium IRC channel:

    13:31:50:     <efge> Mac-arena: Thread 0 Crashed:
    13:31:50:     <efge> 0   libobjc.A.dylib                	0x90a594c0 objc_msgSend + 16
    13:31:51:     <efge> 1   org.ironcoder.SparklePlus      	0x003eb552 -[SUUpdater newVersionAvailable] + 49 (SUUpdater.m:479)
    13:31:51:     <efge> 2   org.ironcoder.SparklePlus      	0x003eb96b -[SUUpdater appcastDidFinishLoading:] + 786 (SUUpdater.m:507)

    Line numbers! Woo-hoo!

    So here’s line 478 (gdb being generally off by one with its line numbers):

    	BOOL available = SUStandardVersionComparison([updateItem minimumSystemVersion], SUCurrentSystemVersionString()) == NSOrderedDescending;

    There’s only one message there, so that has to be what’s crashing.

    Current suspicion: The SUAppcastItem is a zombie.

  • About 13:36: I finally get the idea to try to reproduce the bug on my laptop.

  • From the #adium IRC channel:

    13:38:25: <Mac-arena> Hey, everybody!
    13:38:27: <Mac-arena> Good news
    13:38:31: <Mac-arena> I can reproduce this on my laptop!
    13:39:17:  <durin42> yay Mac-arena can has crash
  • From the #adium IRC channel:

    13:39:12: <Mac-arena> The appcast calls -appcastDidFailToLoad:, and we send it autorelease, and that breaks.
    13:40:52: <Mac-arena> Wait, that's wrong. The backtrace says -appcastDidFinishLoading: and -newVersionAvailable [accessor], so it's not in -DidFailToLoad:.
    13:40:59: <Mac-arena> I hate it when gdb lies to me.
  • From the #adium IRC channel:

    13:55:00:  <Mac-arena> (gdb) po minimumSystemVersion
    13:55:00:  <Mac-arena> 1, 0
    13:55:23:  <Mac-arena> That's on the third of two calls to that method.
  • 13:59:36: Found the problem! The minimumSystemVersion property in SUAppcastItem was not being retained (or copied, to be precise about the correct behavior) by -setMinimumSystemVersion:. So it wasn’t the SUAppcastItem that was zombied; it was the item’s minimumSystemVersion string.

    This also means that zac’s backtrace in #7543 is the same bug; the one in #7542 is missing a frame (for some reason).

    Note how this was 21 minutes after I reproduced the crash on my laptop. This is why you must provide steps that can consistently reproduce your problem, if this is at all possible. Finding this bug would have taken at least an hour, probably more, if I hadn’t been able to reproduce it myself.

  • 14:09: Posted second blog post, announcing that I found the bug and will release 1.1.1 “soon—if all goes well, within the hour”.

    So much for that.

  • From the #adium IRC channel:

    14:20:57: <Newtylicious> Did you really switch to geico?
    14:21:08: <Newtylicious> and did it really take 15 minutes or less?
    14:21:03: <Mac-arena> No.
    14:21:16: <Mac-arena> Never let factual accuracy stand in the way of a good commercial reference.
  • From the #adium IRC channel:

    14:21:53: <Mac-arena> I love flash memory
    14:21:58: <Mac-arena> aka SneakerNet 3.0
  • From the #adium IRC channel:

    14:23:42:     <efge> Mac-arena: was it the same bug in 1.0.5 ? will people have to update manually from that version ?
    14:24:02: <Mac-arena> efge: Well, that's a good question
    14:24:12: <Mac-arena> I haven't confirmed yet whether the Sparkle in 1.0.5 has the same bug.
    14:24:22: <Mac-arena> You raise a good point, and I thank you for it. We may be doing a 1.0.6 as well.
    14:24:26: <Catfish_Man> it is likely
    14:24:34: <Catfish_Man> iirc I wrote that code for a 1.0 beta
    14:24:38: <Catfish_Man> possibly even a 1.0 alpha
  • 14:42:02: Third and final debug build goes live. This one contains the fix for the crash, which was to make -setMinimumSystemVersion: copy its argument, then assign the copy to the instance variable.

  • From the #adium IRC channel:

    14:54:23:   <vIkSiT> ah. so is the problem with sparkle itself, or the adium-sparkle integration?
    14:54:31: <Mac-arena> Neither.
    14:54:45: <Mac-arena> The official Sparkle doesn't have the problem. Only Sparkle ChatKit Edition and Sparkle Plus.
    14:55:04: <Mac-arena> It was already fixed in the official Sparkle.
    14:55:16: <Mac-arena> But that fix did not get carried over to S+, for some reason.
    14:58:40:   <jchang> is there a reason we didn't catch this bug during the betas?
    14:58:49: <Catfish_Man> yes
    14:59:00: <Catfish_Man> minimumSystemVersion was not enabled in the appcast correctly
    15:01:02: <Mac-arena> Now it is, and we find out that it was broken in Sparkle+ :)
    15:02:17: <Mac-arena> http://sparkle.andymatuschak.org/changeset/13
    15:02:46: <Mac-arena> So, it was fixed 5 months ago and it never made its way to us :\
    15:02:54: <Mac-arena> (nor S+, which is how it would have gotten to us)
    
  • From the #adium IRC channel:

    15:06:52:      <zac> can we temporarily fix the appcast now? :P
    15:07:29:   <jchang> zac: what do you mean?
    15:07:51:      <zac> removing the minimum requirement from the .xml will fix the bug
    15:07:59:      <zac> temporarily at least

    I should have done this then.

  • 15:20:24: Sent email to our development mailing-list explaining the situation and proposing a plan:

    1. Take the minimumSystemVersion elements out of the appcast. Since this would lead to Panther users downloading 1.1 again, also take out 1.1, leaving only 1.0.5 (with no minimumSystemVersion element) in the appcast.
    2. Push 1.0.6 with the fixed Sparkle+, for the benefit of Panther users.
    3. 24 hours later, release 1.1.1, put it in the appcast, and restore the minimumSystemVersion elements.
  • 15:37:46: “Michael” replies on the list suggesting that we only hold the 1.1.1 announcement from the appcast; 1.1.1 would be released everywhere else.

  • 15:49:50: I reply to Michael agreeing with his plan, though honestly, I thought that that was what I’d originally said, and worded it accordingly. If you’re reading this, Michael, sorry about the mix-up. (The above list is taken directly from my original email to the development list. As you can see, I clearly wrote that we would hold the entire 1.1.1 release, not just the appcast. No, that doesn’t make sense to me either—Michael was patently right.)

  • From the #adium IRC channel:

    16:45:25:  <Maurits> hi, is the 1.1.1 version available from svn already?
  • 17:15:25: No dissents on the development list, so I IM Chris (who’s just gotten back online) and ask him about the plan.

  • 17:17:15: He asks basically the same question Michael did, and I (slightly puzzled at the time, but brushing it off) give basically the same answer I gave Michael. (To you, too, Chris, sorry about the mix-up.) He OKs the amended plan. I begin prepping two new releases.

  • 17:21:03: I finally uncrashify the appcast as zac suggested (and as mentioned in my email), deleting 1.1 and the minimumSystemVersion elements.

  • From the Adium development IRC channel:

    19:02:29:   <proton> you know peter what oyu really should do is make Adium 1.0.6 and Adium 1.1.1 point to a new sparkle feed that has minimum system requirements in it
    19:02:38:   <proton> and leave the current feed permanently pointing to 1.0.6
    19:02:53:   <proton> because there'll be people for quite a while with older versions that'll be going boom :)
    19:04:31: <Mac-arena> Eh. I think most people will update within 24 hours.
    19:04:56:   <proton> i think that's deluded
    19:05:19:      <zac> 12.7% of our users currently use 1.0.4 still
    19:05:24: <Mac-arena> Heh.
    19:06:32: <Mac-arena> OK, will do
    19:06:36:              Mac-arena goes to amend the blog post
    19:08:51: <Mac-arena> zac: Yo
    19:08:54:      <zac> yo
    19:09:13: <Mac-arena> We need a new pair of feed URLs so we can abandon the old pair.
  • From the Adium development IRC channel:

    19:19:34: <Mac-arena> What if we plan for future versions?
    19:19:56:      <zac> Mac-arena: hm?
    19:19:59: <Mac-arena> update-enhanced.php?generation=2
    19:20:07: <Mac-arena> This being the second generation of appcast feeds.
    19:20:16: <Mac-arena> If anything like this happens again, we go to generation=3.
    19:20:35: <Newtylicious> go forth and multiply, little appcasts
    19:20:42: <Mac-arena> Each generation can represent a directory full of feeds. The current generation is what's updated by [the appcast-refresh script].
    19:21:07:      <zac> Mac-arena: okay, do you want to add the argument "appCastGen=2" to the new builds? that's less hackish and cleaner
    19:21:34:      <zac> or just generation=2, whichever
    19:21:51: <Mac-arena> Hmmm, yeah. We can even keep the same [appcast] URL that way.
  • About 19:14: Posted the third blog post, wherein I explained the day’s circumstances so far, the nature of the bug, and what we’d be doing about it.

  • From the Adium development IRC channel:

    19:26:43: <Mac-arena> Gargh, this code is a mess
    19:27:15: <Mac-arena> Our CodingStyle prohibits multiple returns, too.
    19:27:37:   <proton> sometimes ignoring the CodingStyle will make nicer code (and most of the time not)
    19:28:06:   <proton> hell, I've actually written code with a goto that didn't suck :)
    19:28:13: <Mac-arena> proton: Same here.
    19:27:44: <Mac-arena> This is one of the latter cases.
    19:27:52: <Mac-arena> We're passed a mutable array
    19:27:57: <Mac-arena> Expected to modify it
    19:27:59: <Mac-arena> And guess what?
    19:28:03: <Mac-arena> Two out of three times, *we don't*.
    19:28:10: <Mac-arena> We return a new array instead.
    19:29:03:      <zac> Mac-arena: I'd say, let's just do the new appcast URL part now, and decide on new generational stuff later :)
    19:29:13:      <zac> It looks like it's more effort to do the latter now.
    19:29:14: <Mac-arena> zac: No; I don't wanna go through this again
    19:29:28:      <zac> I don't want to break sparkle in 1.1.1 :)
    19:29:31: <Mac-arena> It's hard to do *anything* to this code. This is no harder than anything else.
    19:30:18: <Mac-arena> zac: This will use generation=2
    19:30:46:      <zac> k
    19:34:59:      <zac> k, my end works
  • From the Adium development IRC channel:

    19:43:32:      <zac> I can tell yo ureally quick if your generation stuff works
    19:43:37:      <zac> I just realized generation=2 isn't processed yet :)
  • From the Adium development IRC channel:

    20:28:44: <Mac-arena> zac: Mind putting a bogus version in the gen=2 appcast? Like 1.42 or something?
    20:29:01:              Mac-arena is about to test his shiny new 1.0.6 and 1.1.1
    20:28:59:      <zac> sure
    20:29:41:      <zac> adium 1.9.7 is now out!
    20:29:54: <Mac-arena> Woohoo!
  • About 20:38: I begin uploading 1.1.1 to my iDisk so that Augie can upload it to our CacheFly hosting.

  • 20:52:59: 1.1.1 arrives on my iDisk. Immediately afterward, thanks to Transmit‘s Queue feature, 1.0.6 starts on the path to join it there.

  • 21:46:37: 1.0.6 arrives on my iDisk.

  • 22:12:08: Changelogs go up.

  • 22:18:16: Replaced 1.0.5, added 1.1.1, and restored minimumSystemVersion elements in the appcasts in r20586.

  • About 22:21: Appcasts updated on the website.

  • From the Adium development IRC channel:

    22:24:12:      <zac> Mac-arena: hmm, 1.1 isn't gonna see 1.1.1 under this plan
    22:24:20:      <zac> nor 1.1.2, 1.2, etc.
    22:24:28: <Mac-arena> Hm.
    22:24:51: <Mac-arena> It was a great plan, too.
    22:24:52:      <zac> 10.3.9 users are vastly the minority
    22:24:57:      <zac> should we inconvenience them [in favor of Tiger users, who are the majority]?
    22:25:06: <Mac-arena> I'm OK with that. So what do we do?
    22:25:08:      <zac> put a "10.3.9 users: get 1.0.6 <here>" at the top of the 1.1.1 update
    22:25:13: <Mac-arena> Sounds good.
    22:25:18: <Mac-arena> In the changelog, you mean?
    22:25:20:              zac does so
    22:26:24:      <zac> 10.3.9 users: Get <a href="http://www.adiumx.com">1.0.6</a> to fix update checking.
    22:26:26:      <zac> ^ sound good?
    22:26:35: <Mac-arena> Hm, no
    22:26:47: <Mac-arena> 10.3.9 users: 1.1.1 will not run on your system. You need to get 1.0.6 instead.
    22:26:49: <Mac-arena> And put it in h2.
    22:27:54:      <zac><p style="color: maroon; font-size: large;">10.3.9 users: Adium 1.1.1 will not run on your system. You need to get <a href="http://www.adiumx.com">Adium 1.0.6</a> instead.</p>
    22:28:11: <Mac-arena> OK. How big is large? :)
    22:28:25:      <zac> about the same size as h2
    22:28:35: <Mac-arena> Should work, then.
    22:30:57: <Mac-arena> Let's change "10.3.9 users:" to "<b>10.3.9 users!</b>"
    22:31:02: <Mac-arena> (note the exclamation mark, too)
  • About 22:26: Posted the release announcement for 1.0.6 and 1.1.1 to the blog.

  • From the Adium development IRC channel:

    22:38:09:  <Wengero> zac: (small little nitpick) #7542 in the changelog is linking to adiumx instead of trac.adiumx
    22:38:27:  <Wengero> so its getting a 404
    22:38:37: <Mac-arena> Ah, relative links
    22:38:41: <Mac-arena> That affects both changelogs, BTW.
    22:38:46: <Mac-arena> And only the #7542 link.
    22:39:13: <Mac-arena> <ul><li>Fixed <a class="closed ticket" href="/ticket/7542" title="&#34;Check For Updates...&#34; systematically crashes adium (closed)">#7542</a>, the Sparkle Plus bug that caused it to crash when passed a minimum OS version in an appcast (update feed).</li></ul>
    22:39:35: <Mac-arena> Should be s#"/ticket#"http://trac.adiumx.com/ticket#

Finally, we were done. The bug was fixed and the fix was released.

So now you know the full details of how, in one day, we fixed two problems:

  1. Panther users being notified of a Tiger-only version of Adium
  2. All users crashing on update once we fixed #1

What a day. Apologies to everybody who had to put up with the crashing while we got that sorted out.

And no, it does not usually have that much drama. ;)

UPDATE 2007-08-15 08:30: Chris pointed out that he had suggested to Zac that Zac change his Adium defaults (prefs) to fake out Sparkle until the crash was fixed. I’ve added this to the appropriate point in the timeline.

Report-an-Apple-Bug Friday! 68

Friday, August 10th, 2007

This bug is Either you can use a sdef directly, or you cannot. It was filed on 2007-08-10 at 11:51 PDT.

(more…)