The Future of Appcasting

A lot of people feel strongly about this. The Appfresh guys have their thoughts, Thomas Keller has some more radical ideas, Denis Defreyne likes hAtom-based feeds, and Olivier Gutknecht tried an Atom-based approach.

I'd like to open this up to discussion here; let's coalesce all the discussion on blogs and mailing lists into one canonical place and get something ironed out. My feelings are not strong, other than that things like the version shouldn't be an attribute of the enclosure as they are now, and DSA signatures are going to be required.

Alright! Atom it is. Here we go, guys. If you find the versioning confusing, check out Poset Versioning.

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:sparkle="http://sparkle.andymatuschak.org/2.0">

	<title>Pixen Release Notes</title>
	<link href="http://opensword.org/pixen" title="Pixen Homepage" />
	<link rel="alternate" href="http://opensword.org/pixen/releasenotes.php" />
	<link rel="self" href="http://opensword.org/pixen/appcast.xml" />
	<updated>2007-09-12T15:30:02Z</updated>
	<author>
		<name>Open Sword Group</name>
		<uri>http://opensword.org</uri>
	</author>
	<id>http://opensword.org/pixen</id>

	<entry>
		<title>Pixen 1.5.1</title>
		<link href="http://opensword.org/pixen/blog.php?post=34" />
		<id>urn:uuid:1231c695-cfb8-4ebb-aaaa-80da344efa6a</id>
		<updated>2007-09-14T15:30:02Z</updated>
		<summary>Ohgod, we made a terrible mistake! This is an update for 1.x customers..</summary>
		<content src="http://opensword.org/pixen/rnotes151.html" type="html" />
		
		<sparkle:version>
			<sparkle:bundleVersion>900</sparkle:bundleVersion>
			<sparkle:displayVersion>1.5.1</sparkle:displayVersion>
			<sparkle:supersedes>300</sparkle:supersedes>
		</sparkle:version>
				
		<sparkle:download src="http://opensword.org/pixen/pixen151.zip">
			<sparkle:dsaSignature>FTPCFBfeCa1XnW30nbkBwainOzrN6EQuAh=</sparkle:dsaSignature>
		</sparkle:download>
	</entry>

	<entry>
		<title>Pixen 2.0 Is Released!</title>
		<link href="http://opensword.org/pixen/blog.php?post=42" />
		<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
		<updated>2007-09-12T15:30:02Z</updated>
		<summary>Including all kinds of new knickknackery.</summary>
		<content src="http://opensword.org/pixen/rnotes2.html" type="html" />
		
		<sparkle:version>
			<sparkle:bundleVersion>456</sparkle:bundleVersion>
			<sparkle:displayVersion>2.0: Imagine</sparkle:displayVersion>
			<sparkle:displayVersion xml:lang="it">2.0: Imaginare</sparkle:displayVersion>
			<sparkle:supersedes>300</sparkle:supersedes>
			<sparkle:supersedes>449</sparkle:supersedes>
		</sparkle:version>
		
		<sparkle:branch paid="true">
			<sparkle:relevantTag>stable</sparkle:relevantTag>
			<sparkle:relevantTag>beta</sparkle:relevantTag>
		</sparkle:branch>
		
		<sparkle:requires systemVersion="10.4.9" />
		
		<sparkle:diff src="http://opensword.org/pixen/diffs/300_456.zip">
			<sparkle:fromVersion>300</sparkle:fromVersion>
			<sparkle:dsaSignature>MC0CFBfeCa1JyW30nbkBwainOzrN6EQuAh=</sparkle:dsaSignature>
		</sparkle:diff>
		
		<sparkle:download src="http://opensword.org/pixen/pixen2.zip">
			<sparkle:dsaSignature>FTPCFBfeCa1XnW30nbkBwainOzrN6EQuAh=</sparkle:dsaSignature>
		</sparkle:download>
	</entry>
	
	<entry>
		<title>Pixen 2.0 Beta</title>
		<link href="http://opensword.org/pixen/blog.php?post=40" />
		<id>urn:uuid:1228c695-cfb8-4ebb-aaaa-80da344efa6a</id>
		<updated>2007-09-10T15:30:02Z</updated>
		<summary>This is only a beta.</summary>
		<content src="http://opensword.org/pixen/rnotes2b.html" type="html" />
		
		<sparkle:version>
			<sparkle:bundleVersion>449</sparkle:bundleVersion>
			<sparkle:displayVersion>2.0 Beta</sparkle:displayVersion>
			<sparkle:supersedes>300</sparkle:supersedes>
		</sparkle:version>
		
		<sparkle:branch>
			<sparkle:relevantTag>beta</sparkle:relevantTag>
		</sparkle:branch>
		
		<sparkle:requires systemVersion="10.4.9" />
		
		<sparkle:diff src="http://opensword.org/pixen/diffs/300_449.zip">
			<sparkle:fromVersion>300</sparkle:fromVersion>
			<sparkle:dsaSignature>MC0CFBfeCa1JyW30nbkBwainOzrN6EQuAh=</sparkle:dsaSignature>
		</sparkle:diff>
		
		<sparkle:download src="http://opensword.org/pixen/pixen2b.zip">
			<sparkle:dsaSignature>FTPCFBfeCa1XnW30nbkBwainOzrN6EQuAh=</sparkle:dsaSignature>
		</sparkle:download>
	</entry>
	
	<entry>
		<title>Pixen 1.5</title>
		<link href="http://opensword.org/pixen/blog.php?post=35" />
		<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
		<updated>2007-07-10T15:30:02Z</updated>
		<summary>This is old-style Pixen.</summary>
		<content src="http://opensword.org/pixen/rnotes15.html" type="html" />
		
		<sparkle:version>
			<sparkle:bundleVersion>300</sparkle:bundleVersion>
			<sparkle:displayVersion>1.5</sparkle:displayVersion>
		</sparkle:version>
		
		<sparkle:download src="http://opensword.org/pixen/pixen15.zip">
			<sparkle:dsaSignature>FTPCFBfeCa1XnW30nbkBwainOzrN6EQuAh=</sparkle:dsaSignature>
		</sparkle:download>
	</entry>

	<sparkle:branchTags>
		<sparkle:branchTag default="true">
			<sparkle:name>stable</sparkle:name>
			<sparkle:title>Stable</sparkle:title>
			<sparkle:title xml:lang="it">Stabile</sparkle:title>
		</sparkle:branchTag>
		<sparkle:branchTag>
			<sparkle:name>beta</sparkle:name>
			<sparkle:title>Beta</sparkle:title>
		</sparkle:branchTag>
	</sparkle:branchTags>

</feed>

Let's go through these one section at a time.

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:sparkle="http://sparkle.andymatuschak.org/2.0">

	<title>Pixen Release Notes</title>
	<link href="http://opensword.org/pixen" title="Pixen Homepage" />
	<link rel="alternate" href="http://opensword.org/pixen/releasenotes.php" />
	<link rel="self" href="http://opensword.org/pixen/appcast.xml" />
	<updated>2007-09-12T15:30:02Z</updated>
	<author>
		<name>Open Sword Group</name>
		<uri>http://opensword.org</uri>
	</author>
	<id>http://opensword.org/pixen</id>

This is normal Atom stuff. Boring.

	<entry>
		<title>Pixen 1.5.1</title>
		<link href="http://opensword.org/pixen/blog.php?post=34" />
		<id>urn:uuid:1231c695-cfb8-4ebb-aaaa-80da344efa6a</id>
		<updated>2007-09-14T15:30:02Z</updated>
		<summary>Ohgod, we made a terrible mistake! This is an update for 1.x customers..</summary>
		<content src="http://opensword.org/pixen/rnotes151.html" type="html" />
		
		<sparkle:version>
			<sparkle:bundleVersion>900</sparkle:bundleVersion>
			<sparkle:displayVersion>1.5.1</sparkle:displayVersion>
			<sparkle:supersedes>300</sparkle:supersedes>
		</sparkle:version>
				
		<sparkle:download src="http://opensword.org/pixen/pixen151.zip">
			<sparkle:dsaSignature>FTPCFBfeCa1XnW30nbkBwainOzrN6EQuAh=</sparkle:dsaSignature>
		</sparkle:download>
	</entry>

This is the first entry in the feed. Not everything here is necessarily clear. Note in the <sparkle:version> section, we're explicitly designating which version this version supersedes: it's version 300, which if you look down in the feed, you'll find was called 1.5 as far as the user knew. sparkle:bundleVersion == CFBundleVersion and sparkle:displayVersion == CFBundleShortVersionString. The latter is optional. DSA signatures are now required.

Now, from the next version:

<sparkle:version>
	<sparkle:bundleVersion>456</sparkle:bundleVersion>
	<sparkle:displayVersion>2.0: Imagine</sparkle:displayVersion>
	<sparkle:displayVersion xml:lang="it">2.0: Imaginare</sparkle:displayVersion>
	<sparkle:supersedes>300</sparkle:supersedes>
	<sparkle:supersedes>449</sparkle:supersedes>
</sparkle:version>

Stuff can be localized easily because this is XML. Note that this version supersedes two versions: 300, and 449 (2.0 beta). Now, normally two entries would not be allowed to supercede the same version, but this is a branch:

<sparkle:branch paid="true">
	<sparkle:relevantTag>stable</sparkle:relevantTag>
	<sparkle:relevantTag>beta</sparkle:relevantTag>
</sparkle:branch>

Sparkle supports branching now, and it makes sense for this to branch, since it's a paid upgrade. Sparkle uses tags to determine which branches to present to a user; later in the file they're defined, but for now, consider that in the prefpane, the user can pick between stable and beta updates, and this is a branch that should be displayed for both options.

Because this upgrade is paid, it'll be distinguished visually and have an explanatory bar below the release notes stating that it's a paid upgrade with one button linking to the site and one button to hide the upgrade. The check box next to this update will be disabled by default.

Now, when multiple branching updates are available to the user (like 1.5.1 vs. 2.0 for a user updating from 1.5), both are displayed, with the one in the current branch selected by default. If the current branch ended there, it will select the most recently updated branch by default. Explanatory text will help the user along.

<sparkle:requires systemVersion="10.4.9" />

Self-explanatory but useful. I considered a sparkleVersion attribute on that, too, but decided that Sparkle must always be the latest version to update.

<sparkle:diff src="http://opensword.org/pixen/diffs/300_456.zip">
	<sparkle:fromVersion>300</sparkle:fromVersion>
	<sparkle:dsaSignature>MC0CFBfeCa1JyW30nbkBwainOzrN6EQuAh=</sparkle:dsaSignature>
</sparkle:diff>

Diffs will really help bandwidth usage and download times. See Incremental Updates for more information. If a diff is not available or the checksum fails on a file being patched, Sparkle will just fall back on the normal download link.

<sparkle:branch>
	<sparkle:relevantTag>beta</sparkle:relevantTag>
</sparkle:branch>

As we continue down the sample, note that the Sparkle 2.0 beta entry is also a branch, but this upgrade will only appear to users who say they want to see beta branches. This version is immediately superceded by 2.0, but there could be other updates in this branch while the main branch was updated.

<sparkle:branchTags>
	<sparkle:branchTag default="true">
		<sparkle:name>stable</sparkle:name>
		<sparkle:title>Stable</sparkle:title>
		<sparkle:title xml:lang="it">Stabile</sparkle:title>
	</sparkle:branchTag>
	<sparkle:branchTag>
		<sparkle:name>beta</sparkle:name>
		<sparkle:title>Beta</sparkle:title>
	</sparkle:branchTag>
</sparkle:branchTags>

This section defines the branch tags used earlier. This is self-explanatory. Note that branch tag titles can be easily localized.

Comments?