Skip to content

Commit

Permalink
Add support for parsing an extended <sparkle:deltas> element in the a…
Browse files Browse the repository at this point in the history
…ppcast that describes

the delta updates that are available for a given version.

The appcast would look a little something like the following:

<enclosure url="http://you.com/app/Your Great App 2.0.zip" sparkle:version="2.0" length="1623481" type="application/octet-stream" sparkle:dsaSignature="BAFJW4B6B1K1JyW30nbkBwainOzrN6EQuAh" />
<sparkle:deltas>
    <enclosure url="http://you.com/app/Your Great App 1.5 to 2.0.delta" sparkle:version="2.0" sparkle:deltaFrom="1.5" length="642381" type="application/octet-stream" sparkle:dsaSignature="MCa1JyW30nbkBwaC0CFBfeinOzrN6EQuAh=" />
    <enclosure url="http://you.com/app/Your Great App 1.4 to 2.0.delta" sparkle:version="2.0" sparkle:deltaFrom="1.4" length="928231" type="application/octet-stream" sparkle:dsaSignature="B6B1K1JyW30nbkBDBfeinOAszrN6Ea1JyW3" />
</sparkle:deltas>
  • Loading branch information
bdash committed Aug 21, 2009
1 parent c3d8254 commit 6e648f1
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 13 deletions.
41 changes: 32 additions & 9 deletions SUAppcast.m
Expand Up @@ -9,6 +9,23 @@
#import "Sparkle.h"
#import "SUAppcast.h"

@interface NSXMLElement (SUAppcastExtensions)
- (NSDictionary *)attributesAsDictionary;
@end

@implementation NSXMLElement (SUAppcastExtensions)
- (NSDictionary *)attributesAsDictionary
{
NSEnumerator *attributeEnum = [[self attributes] objectEnumerator];
NSXMLNode *attribute;
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

while ((attribute = [attributeEnum nextObject]))
[dictionary setObject:[attribute stringValue] forKey:[attribute name]];
return dictionary;
}
@end

@interface SUAppcast (Private)
- (void)reportError:(NSError *)error;
- (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes;
Expand Down Expand Up @@ -116,12 +133,7 @@ - (void)downloadDidFinish:(NSURLDownload *)download
if ([name isEqualToString:@"enclosure"])
{
// enclosure is flattened as a separate dictionary for some reason
NSEnumerator *attributeEnum = [[(NSXMLElement *)node attributes] objectEnumerator];
NSXMLNode *attribute;
NSMutableDictionary *encDict = [NSMutableDictionary dictionary];

while ((attribute = [attributeEnum nextObject]))
[encDict setObject:[attribute stringValue] forKey:[attribute name]];
NSDictionary *encDict = [(NSXMLElement *)node attributesAsDictionary];
[dict setObject:encDict forKey:@"enclosure"];

}
Expand All @@ -132,13 +144,24 @@ - (void)downloadDidFinish:(NSURLDownload *)download
if (date)
[dict setObject:date forKey:name];
}
else if (name != nil)
{
else if ([name isEqualToString:@"sparkle:deltas"])
{
NSMutableArray *deltas = [NSMutableArray array];
NSEnumerator *childEnum = [[node children] objectEnumerator];
NSXMLNode *child;
while ((child = [childEnum nextObject])) {
if ([[child name] isEqualToString:@"enclosure"])
[deltas addObject:[(NSXMLElement *)child attributesAsDictionary]];
}
[dict setObject:deltas forKey:@"deltas"];
}
else if (name != nil)
{
// add all other values as strings
[dict setObject:[[node stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:name];
}
}

SUAppcastItem *anItem = [[SUAppcastItem alloc] initWithDictionary:dict];
if (anItem)
{
Expand Down
6 changes: 5 additions & 1 deletion SUAppcastItem.h
Expand Up @@ -22,7 +22,9 @@
NSURL *fileURL;
NSString *versionString;
NSString *displayVersionString;


NSDictionary *deltaUpdates;

NSDictionary *propertiesDictionary;
}

Expand All @@ -38,6 +40,8 @@
- (NSURL *)fileURL;
- (NSString *)DSASignature;
- (NSString *)minimumSystemVersion;
- (NSDictionary *)deltaUpdates;
- (BOOL)isDeltaUpdate;

// Returns the dictionary provided in initWithDictionary; this might be useful later for extensions.
- (NSDictionary *)propertiesDictionary;
Expand Down
31 changes: 31 additions & 0 deletions SUAppcastItem.m
Expand Up @@ -101,6 +101,19 @@ - (void)setMinimumSystemVersion:(NSString *)systemVersionString
minimumSystemVersion = [systemVersionString copy];
}

- (NSDictionary *)deltaUpdates { return [[deltaUpdates retain] autorelease]; }
- (void)setDeltaUpdates:(NSDictionary *)updates
{
if (deltaUpdates == updates) return;
[deltaUpdates release];
deltaUpdates = [updates copy];
}

- (BOOL)isDeltaUpdate
{
return [[propertiesDictionary objectForKey:@"enclosure"] objectForKey:@"sparkle:deltaFrom"] != nil;
}

- initWithDictionary:(NSDictionary *)dict
{
self = [super init];
Expand Down Expand Up @@ -157,6 +170,24 @@ - (void)setMinimumSystemVersion:(NSString *)systemVersionString
[self setReleaseNotesURL:[NSURL URLWithString:[self itemDescription]]];
else
[self setReleaseNotesURL:nil];

if ([dict objectForKey:@"deltas"]) {
NSMutableDictionary *deltas = [NSMutableDictionary dictionary];
NSArray *deltaDictionaries = [dict objectForKey:@"deltas"];
NSEnumerator *deltaDictionariesEnum = [deltaDictionaries objectEnumerator];
NSDictionary *deltaDictionary;
while ((deltaDictionary = [deltaDictionariesEnum nextObject])) {
NSMutableDictionary *fakeAppCastDict = [dict mutableCopy];
[fakeAppCastDict removeObjectForKey:@"deltas"];
[fakeAppCastDict setObject:deltaDictionary forKey:@"enclosure"];
SUAppcastItem *deltaItem = [[[self class] alloc] initWithDictionary:fakeAppCastDict];
[fakeAppCastDict release];

[deltas setObject:deltaItem forKey:[deltaDictionary objectForKey:@"sparkle:deltaFrom"]];
[deltaItem release];
}
[self setDeltaUpdates:deltas];
}
}
}
return self;
Expand Down
2 changes: 2 additions & 0 deletions SUBasicUpdateDriver.h
Expand Up @@ -15,6 +15,7 @@
@class SUAppcastItem, SUUnarchiver, SUAppcast, SUUnarchiver, SUHost;
@interface SUBasicUpdateDriver : SUUpdateDriver {
SUAppcastItem *updateItem;
SUAppcastItem *nonDeltaUpdateItem;

NSURLDownload *download;
NSString *downloadPath;
Expand Down Expand Up @@ -42,6 +43,7 @@
- (void)extractUpdate;
- (void)unarchiverDidFinish:(SUUnarchiver *)ua;
- (void)unarchiverDidFail:(SUUnarchiver *)ua;
- (void)failedToApplyDeltaUpdate;

- (void)installUpdate;
- (void)installerFinishedForHost:(SUHost *)host;
Expand Down
29 changes: 26 additions & 3 deletions SUBasicUpdateDriver.m
Expand Up @@ -94,9 +94,15 @@ - (void)appcastDidFinishLoading:(SUAppcast *)ac
do {
item = [updateEnumerator nextObject];
} while (item && ![self hostSupportsItem:item]);

SUAppcastItem *deltaUpdateItem = [[item deltaUpdates] objectForKey:[host version]];
if (deltaUpdateItem && [self hostSupportsItem:deltaUpdateItem]) {
nonDeltaUpdateItem = [item retain];
item = deltaUpdateItem;
}
}
updateItem = [item retain];
updateItem = [item retain];
CFRelease(ac); // Remember that we're explicitly managing the memory of the appcast.
if (updateItem == nil) { [self didNotFindUpdate]; return; }

Expand Down Expand Up @@ -189,7 +195,7 @@ - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSS

- (void)extractUpdate
{
SUUnarchiver *unarchiver = [SUUnarchiver unarchiverForPath:downloadPath];
SUUnarchiver *unarchiver = [SUUnarchiver unarchiverForPath:downloadPath updatingHost:host];
if (!unarchiver)
{
NSLog(@"Sparkle Error: No valid unarchiver for %@!", downloadPath);
Expand All @@ -201,6 +207,16 @@ - (void)extractUpdate
[unarchiver start];
}

- (void)failedToApplyDeltaUpdate
{
// When a delta update fails to apply we fall back on updating via a full install.
[updateItem release];
updateItem = nonDeltaUpdateItem;
nonDeltaUpdateItem = nil;

[self downloadUpdate];
}

- (void)unarchiverDidFinish:(SUUnarchiver *)ua
{
if (ua) { CFRelease(ua); }
Expand All @@ -210,6 +226,12 @@ - (void)unarchiverDidFinish:(SUUnarchiver *)ua
- (void)unarchiverDidFail:(SUUnarchiver *)ua
{
if (ua) { CFRelease(ua); }

if ([updateItem isDeltaUpdate]) {
[self failedToApplyDeltaUpdate];
return;
}

[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUUnarchivingError userInfo:[NSDictionary dictionaryWithObject:SULocalizedString(@"An error occurred while extracting the archive. Please try again later.", nil) forKey:NSLocalizedDescriptionKey]]];
}

Expand Down Expand Up @@ -304,6 +326,7 @@ - (void)abortUpdateWithError:(NSError *)error
- (void)dealloc
{
[updateItem release];
[nonDeltaUpdateItem release];
[download release];
[downloadPath release];
[relaunchPath release];
Expand Down

0 comments on commit 6e648f1

Please sign in to comment.