Skip to content

Commit

Permalink
Merge commit 'bdash/delta-updates'
Browse files Browse the repository at this point in the history
This is a big one, guys. Haven't tested the new features in the merged branch yet.
  • Loading branch information
andymatuschak committed Jan 11, 2010
2 parents 2e3ed79 + ab23fed commit 9bc63cc
Show file tree
Hide file tree
Showing 25 changed files with 1,732 additions and 40 deletions.
9 changes: 9 additions & 0 deletions Configurations/ConfigBinaryDelta.xcconfig
@@ -0,0 +1,9 @@
// BinaryDelta tool only

PRODUCT_NAME = BinaryDelta
GCC_PREFIX_HEADER =
SDKROOT = macosx10.5
MACOSX_DEPLOYMENT_TARGET[arch=i386] = 10.5
MACOSX_DEPLOYMENT_TARGET[arch=ppc64] = 10.5
MACOSX_DEPLOYMENT_TARGET[arch=ppc] = 10.5
MACOSX_DEPLOYMENT_TARGET[arch=x86_64] = 10.5
5 changes: 5 additions & 0 deletions Configurations/ConfigBinaryDeltaDebug.xcconfig
@@ -0,0 +1,5 @@
#include "ConfigCommon.xcconfig"
#include "ConfigCommonDebug.xcconfig"
#include "ConfigBinaryDelta.xcconfig"

OTHER_CFLAGS = -fsingle-precision-constant -DDEBUG
3 changes: 3 additions & 0 deletions Configurations/ConfigBinaryDeltaRelease.xcconfig
@@ -0,0 +1,3 @@
#include "ConfigCommon.xcconfig"
#include "ConfigCommonRelease.xcconfig"
#include "ConfigBinaryDelta.xcconfig"
1 change: 1 addition & 0 deletions Configurations/ConfigCommon.xcconfig
Expand Up @@ -47,3 +47,4 @@ GCC_WARN_UNUSED_PARAMETER = YES
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
GCC_WARN_UNDECLARED_SELECTOR = YES
WARNING_CFLAGS = -Wall -Wundef -Wendif-labels -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-noreturn -Wmissing-format-attribute -Wpacked -Wredundant-decls -Winline -Wdisabled-optimization -Wformat=2 -Wlarger-than-32768 -Winvalid-pch
LIBRARY_SEARCH_PATHS = $(inherited) $(SRCROOT)
29 changes: 28 additions & 1 deletion License.txt
Expand Up @@ -123,4 +123,31 @@ Original SSLeay License
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
*/

License for bspatch.c and bsdiff.c, from bsdiff 4.3 (<http://www.daemonology.net/bsdiff/>:
/*-
* Copyright 2003-2005 Colin Percival
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
39 changes: 31 additions & 8 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 @@ -121,12 +138,7 @@ - (void)downloadDidFinish:(NSURLDownload *)aDownload
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 @@ -137,8 +149,19 @@ - (void)downloadDidFinish:(NSURLDownload *)aDownload
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];
}
Expand Down
6 changes: 5 additions & 1 deletion SUAppcastItem.h
Expand Up @@ -24,7 +24,9 @@
NSURL *fileURL;
NSString *versionString;
NSString *displayVersionString;


NSDictionary *deltaUpdates;

NSDictionary *propertiesDictionary;
}

Expand All @@ -41,6 +43,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
89 changes: 65 additions & 24 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
{
return [self initWithDictionary:dict failureReason:nil];
Expand Down Expand Up @@ -155,30 +168,58 @@ - (void)setMinimumSystemVersion:(NSString *)systemVersionString
return nil;
}

propertiesDictionary = [[NSMutableDictionary alloc] initWithDictionary:dict];
[self setTitle:[dict objectForKey:@"title"]];
[self setDate:[dict objectForKey:@"pubDate"]];
[self setItemDescription:[dict objectForKey:@"description"]];

[self setFileURL:[NSURL URLWithString:[[enclosure objectForKey:@"url"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
[self setDSASignature:[enclosure objectForKey:@"sparkle:dsaSignature"]];

[self setVersionString:newVersion];
[self setMinimumSystemVersion:[dict objectForKey:@"sparkle:minimumSystemVersion"]];

NSString *shortVersionString = [enclosure objectForKey:@"sparkle:shortVersionString"];
if (shortVersionString)
[self setDisplayVersionString:shortVersionString];
else
[self setDisplayVersionString:[self versionString]];

// Find the appropriate release notes URL.
if ([dict objectForKey:@"sparkle:releaseNotesLink"])
[self setReleaseNotesURL:[NSURL URLWithString:[dict objectForKey:@"sparkle:releaseNotesLink"]]];
else if ([[self itemDescription] hasPrefix:@"http://"]) // if the description starts with http://, use that.
[self setReleaseNotesURL:[NSURL URLWithString:[self itemDescription]]];
else
[self setReleaseNotesURL:nil];
if (enclosure == nil || [enclosure objectForKey:@"url"] == nil || newVersion == nil)
{
[self release];
self = nil;
}
else
{
propertiesDictionary = [[NSMutableDictionary alloc] initWithDictionary:dict];
[self setTitle:[dict objectForKey:@"title"]];
[self setDate:[dict objectForKey:@"pubDate"]];
[self setItemDescription:[dict objectForKey:@"description"]];

[self setFileURL:[NSURL URLWithString:[[enclosure objectForKey:@"url"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
[self setDSASignature:[enclosure objectForKey:@"sparkle:dsaSignature"]];

[self setVersionString:newVersion];
[self setMinimumSystemVersion:[dict objectForKey:@"sparkle:minimumSystemVersion"]];

NSString *shortVersionString = [enclosure objectForKey:@"sparkle:shortVersionString"];
if (shortVersionString)
[self setDisplayVersionString:shortVersionString];
else
[self setDisplayVersionString:[self versionString]];

// Find the appropriate release notes URL.
if ([dict objectForKey:@"sparkle:releaseNotesLink"])
[self setReleaseNotesURL:[NSURL URLWithString:[dict objectForKey:@"sparkle:releaseNotesLink"]]];
else if ([[self itemDescription] hasPrefix:@"http://"]) // if the description starts with http://, use that.
[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
25 changes: 24 additions & 1 deletion SUBasicUpdateDriver.m
Expand Up @@ -91,6 +91,12 @@ - (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];
Expand Down Expand Up @@ -200,7 +206,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 @@ -212,6 +218,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 @@ -221,6 +237,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 @@ -328,6 +350,7 @@ - (void)abortUpdateWithError:(NSError *)error
- (void)dealloc
{
[updateItem release];
[nonDeltaUpdateItem release];
[download release];
[downloadPath release];
[relaunchPath release];
Expand Down
15 changes: 15 additions & 0 deletions SUBinaryDeltaApply.h
@@ -0,0 +1,15 @@
//
// SUBinaryDeltaApply.h
// Sparkle
//
// Created by Mark Rowe on 2009-06-01.
// Copyright 2009 Mark Rowe. All rights reserved.
//

#ifndef SUBINARYDELTAAPPLY_H
#define SUBINARYDELTAAPPLY_H

@class NSString;
int applyBinaryDelta(NSString *source, NSString *destination, NSString *patchFile);

#endif

0 comments on commit 9bc63cc

Please sign in to comment.