From e51eb32403081ecebfd4cf8493964ecd5adc05ae Mon Sep 17 00:00:00 2001 From: Zorg <zorgiepoo@gmail.com> Date: Sat, 24 Apr 2021 21:42:33 -0700 Subject: [PATCH 1/4] Fix bestValidUpdateInAppcast: not handling delta updates correctly All the top level appcast items are non-delta items. The client needs to give us back a non-delta update item. We then fetch the appropriate delta item ourselves. --- Sparkle/SPUBasicUpdateDriver.h | 2 +- Sparkle/SPUBasicUpdateDriver.m | 4 +- Sparkle/SPUCoreBasedUpdateDriver.m | 8 +-- Sparkle/SUAppcast.h | 3 +- Sparkle/SUAppcast.m | 8 +-- Sparkle/SUAppcastDriver.h | 2 +- Sparkle/SUAppcastDriver.m | 85 +++++++++++++++++++----------- 7 files changed, 64 insertions(+), 48 deletions(-) diff --git a/Sparkle/SPUBasicUpdateDriver.h b/Sparkle/SPUBasicUpdateDriver.h index 8598024fc8..107dd0200f 100644 --- a/Sparkle/SPUBasicUpdateDriver.h +++ b/Sparkle/SPUBasicUpdateDriver.h @@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpdateDriverCompletion)completionBlock; -@property (nullable, nonatomic, readonly) SUAppcastItem *nonDeltaUpdateItem; +@property (nullable, nonatomic, readonly) SUAppcastItem *secondaryUpdateItem; - (void)abortUpdateAndShowNextUpdateImmediately:(BOOL)shouldSignalShowingUpdate resumableUpdate:(id<SPUResumableUpdate> _Nullable)resumableUpdate error:(nullable NSError *)error; diff --git a/Sparkle/SPUBasicUpdateDriver.m b/Sparkle/SPUBasicUpdateDriver.m index 49929c1af5..2a3be1d4a4 100644 --- a/Sparkle/SPUBasicUpdateDriver.m +++ b/Sparkle/SPUBasicUpdateDriver.m @@ -112,9 +112,9 @@ - (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpda [self notifyResumableUpdateItem:resumableUpdate.updateItem systemDomain:nil]; } -- (SUAppcastItem *)nonDeltaUpdateItem +- (SUAppcastItem *)secondaryUpdateItem { - return self.appcastDriver.nonDeltaUpdateItem; + return self.appcastDriver.secondaryUpdateItem; } - (void)didFailToFetchAppcastWithError:(NSError *)error diff --git a/Sparkle/SPUCoreBasedUpdateDriver.m b/Sparkle/SPUCoreBasedUpdateDriver.m index a769fe08fe..4b5c435f9a 100644 --- a/Sparkle/SPUCoreBasedUpdateDriver.m +++ b/Sparkle/SPUCoreBasedUpdateDriver.m @@ -381,16 +381,16 @@ - (void)basicDriverIsRequestingAbortUpdateWithError:(nullable NSError *)error - (void)installerDidFailToApplyDeltaUpdate { - SUAppcastItem *nonDeltaUpdateItem = self.basicDriver.nonDeltaUpdateItem; - assert(nonDeltaUpdateItem != nil); + SUAppcastItem *secondaryUpdateItem = self.basicDriver.secondaryUpdateItem; + assert(secondaryUpdateItem != nil); BOOL backgroundDownload = self.downloadDriver.inBackground; [self clearDownloadedUpdate]; // Fall back to the non-delta update. Note that we don't want to trigger another update was found event. - self.updateItem = nonDeltaUpdateItem; - [self downloadUpdateFromAppcastItem:nonDeltaUpdateItem inBackground:backgroundDownload]; + self.updateItem = secondaryUpdateItem; + [self downloadUpdateFromAppcastItem:secondaryUpdateItem inBackground:backgroundDownload]; } - (void)abortUpdateAndShowNextUpdateImmediately:(BOOL)shouldShowUpdateImmediately error:(nullable NSError *)error diff --git a/Sparkle/SUAppcast.h b/Sparkle/SUAppcast.h index 5ae0f0fabc..7030dff314 100644 --- a/Sparkle/SUAppcast.h +++ b/Sparkle/SUAppcast.h @@ -28,10 +28,9 @@ SU_EXPORT @interface SUAppcast : NSObject<NSURLDownloadDelegate> @property (copy, nullable) NSDictionary<NSString *, NSString *> *httpHeaders; - (void)fetchAppcastFromURL:(NSURL *)url inBackground:(BOOL)bg completionBlock:(void (^)(NSError *_Nullable))err; -- (SUAppcast *)copyWithoutDeltaUpdates; - (SUAppcast *)copyByFilteringItems:(BOOL (^)(SUAppcastItem *))filterBlock; -@property (readonly, copy, nullable) NSArray *items; +@property (readonly, copy, nullable) NSArray<SUAppcastItem *> *items; @end NS_ASSUME_NONNULL_END diff --git a/Sparkle/SUAppcast.m b/Sparkle/SUAppcast.m index 640960e833..467854a73f 100644 --- a/Sparkle/SUAppcast.m +++ b/Sparkle/SUAppcast.m @@ -47,7 +47,7 @@ - (NSDictionary *)attributesAsDictionary @interface SUAppcast () <NSURLDownloadDelegate> @property (strong) void (^completionBlock)(NSError *); -@property (copy) NSArray *items; +@property (copy) NSArray<SUAppcastItem *> *items; - (void)reportError:(NSError *)error; - (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes; @end @@ -306,12 +306,6 @@ - (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes return [nodes objectAtIndex:i]; } -- (SUAppcast *)copyWithoutDeltaUpdates { - return [self copyByFilteringItems:^(SUAppcastItem *item) { - return (BOOL)![item isDeltaUpdate]; - }]; -} - - (SUAppcast *)copyByFilteringItems:(BOOL (^)(SUAppcastItem *))filterBlock { SUAppcast *other = [SUAppcast new]; diff --git a/Sparkle/SUAppcastDriver.h b/Sparkle/SUAppcastDriver.h index b5b2dbf280..d9a6a3cfa6 100644 --- a/Sparkle/SUAppcastDriver.h +++ b/Sparkle/SUAppcastDriver.h @@ -28,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)loadAppcastFromURL:(NSURL *)appcastURL userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background includesSkippedUpdates:(BOOL)includesSkippedUpdates; -@property (nullable, nonatomic, readonly) SUAppcastItem *nonDeltaUpdateItem; +@property (nullable, nonatomic, readonly) SUAppcastItem *secondaryUpdateItem; @end diff --git a/Sparkle/SUAppcastDriver.m b/Sparkle/SUAppcastDriver.m index 24a0e69296..9dfb4a01e3 100644 --- a/Sparkle/SUAppcastDriver.m +++ b/Sparkle/SUAppcastDriver.m @@ -16,6 +16,7 @@ #import "SUHost.h" #import "SUConstants.h" #import "SUPhasedUpdateGroupInfo.h" +#import "SULog.h" #include "AppKitPrevention.h" @@ -26,7 +27,7 @@ @interface SUAppcastDriver () @property (nonatomic, copy) NSString *userAgent; @property (nullable, nonatomic, readonly, weak) id updater; @property (nullable, nonatomic, readonly, weak) id <SPUUpdaterDelegate> updaterDelegate; -@property (nullable, nonatomic) SUAppcastItem *nonDeltaUpdateItem; +@property (nullable, nonatomic) SUAppcastItem *secondaryUpdateItem; @property (nullable, nonatomic, readonly, weak) id <SUAppcastDriverDelegate> delegate; @end @@ -37,7 +38,7 @@ @implementation SUAppcastDriver @synthesize userAgent = _userAgent; @synthesize updater = _updater; @synthesize updaterDelegate = _updaterDelegate; -@synthesize nonDeltaUpdateItem = _nonDeltaUpdateItem; +@synthesize secondaryUpdateItem = _secondaryUpdateItem; @synthesize delegate = _delegate; - (instancetype)initWithHost:(SUHost *)host updater:(id)updater updaterDelegate:(id <SPUUpdaterDelegate>)updaterDelegate delegate:(id <SUAppcastDriverDelegate>)delegate @@ -68,6 +69,24 @@ - (void)loadAppcastFromURL:(NSURL *)appcastURL userAgent:(NSString *)userAgent h }]; } +- (SUAppcastItem * _Nullable)preferredUpdateForRegularAppcastItem:(SUAppcastItem * _Nullable)regularItem secondaryUpdate:(SUAppcastItem * __autoreleasing _Nullable *)secondaryUpdate +{ + if (regularItem == nil) { + return nil; + } + + SUAppcastItem *deltaItem = [[self class] deltaUpdateFromAppcastItem:regularItem hostVersion:self.host.version]; + + if (deltaItem != nil) { + if (secondaryUpdate != NULL) { + *secondaryUpdate = regularItem; + } + return deltaItem; + } else { + return regularItem; + } +} + - (void)appcastDidFinishLoading:(SUAppcast *)loadedAppcast inBackground:(BOOL)background includesSkippedUpdates:(BOOL)includesSkippedUpdates { [self.delegate didFinishLoadingAppcast:loadedAppcast]; @@ -79,35 +98,33 @@ - (void)appcastDidFinishLoading:(SUAppcast *)loadedAppcast inBackground:(BOOL)ba SUAppcast *supportedAppcast = [[self class] filterSupportedAppcast:loadedAppcast phasedUpdateGroup:phasedUpdateGroup]; SUAppcastItem *item = nil; - SUAppcastItem *nonDeltaUpdateItem = nil; + SUAppcastItem *secondaryItem = nil; - // Now we have to find the best valid update in the appcast. + // Find the best valid update in the appcast by asking the delegate if ([self.updaterDelegate respondsToSelector:@selector((bestValidUpdateInAppcast:forUpdater:))]) { - item = [self.updaterDelegate bestValidUpdateInAppcast:supportedAppcast forUpdater:(id _Nonnull)self.updater]; - } - - if (item != nil) - { - // Does the delegate want to handle it? - if ([item isDeltaUpdate]) { - nonDeltaUpdateItem = [self.updaterDelegate bestValidUpdateInAppcast:[supportedAppcast copyWithoutDeltaUpdates] forUpdater:(id _Nonnull)self.updater]; + SUAppcastItem *regularItem = [self.updaterDelegate bestValidUpdateInAppcast:supportedAppcast forUpdater:(id _Nonnull)self.updater]; + + assert(!regularItem.deltaUpdate); + if (regularItem.deltaUpdate) { + // Client would have to go out of their way to examine the .deltaUpdates to return one + // This is very unlikely, and we need them to give us a regular update item back + SULog(SULogLevelError, @"Error: -bestValidUpdateInAppcast:forUpdater: cannot return a delta update item"); + } else { + item = [self preferredUpdateForRegularAppcastItem:regularItem secondaryUpdate:&secondaryItem]; } } - else // If not, we'll take care of it ourselves. + + // Take care of finding best appcast item ourselves if delegate does not + if (item == nil) { - // Find the best supported update - SUAppcastItem *deltaUpdateItem = nil; - item = [[self class] bestItemFromAppcastItems:supportedAppcast.items getDeltaItem:&deltaUpdateItem withHostVersion:self.host.version comparator:[self versionComparator]]; + SUAppcastItem *regularItem = [[self class] bestItemFromAppcastItems:supportedAppcast.items comparator:[self versionComparator]]; - if (item && deltaUpdateItem) { - nonDeltaUpdateItem = item; - item = deltaUpdateItem; - } + item = [self preferredUpdateForRegularAppcastItem:regularItem secondaryUpdate:&secondaryItem]; } if ([self itemContainsValidUpdate:item inBackground:background includesSkippedUpdates:includesSkippedUpdates]) { - self.nonDeltaUpdateItem = nonDeltaUpdateItem; + self.secondaryUpdateItem = secondaryItem; [self.delegate didFindValidUpdateWithAppcastItem:item preventsAutoupdate:[self itemPreventsAutoupdate:item]]; } else { NSComparisonResult hostToLatestAppcastItemComparisonResult = (item != nil) ? [[self versionComparator] compareVersion:[self.host version] toVersion:[item versionString]] : 0; @@ -125,9 +142,12 @@ + (SUAppcast *)filterSupportedAppcast:(SUAppcast *)appcast phasedUpdateGroup:(NS }]; } -// This method is used by unit tests -// This method should not do *any* filtering, only version comparing -+ (SUAppcastItem *)bestItemFromAppcastItems:(NSArray *)appcastItems getDeltaItem:(SUAppcastItem * __autoreleasing *)deltaItem withHostVersion:(NSString *)hostVersion comparator:(id<SUVersionComparison>)comparator ++ (SUAppcastItem * _Nullable)deltaUpdateFromAppcastItem:(SUAppcastItem *)appcastItem hostVersion:(NSString *)hostVersion +{ + return appcastItem.deltaUpdates[hostVersion]; +} + ++ (SUAppcastItem * _Nullable)bestItemFromAppcastItems:(NSArray *)appcastItems comparator:(id<SUVersionComparison>)comparator { SUAppcastItem *item = nil; for(SUAppcastItem *candidate in appcastItems) { @@ -135,14 +155,17 @@ + (SUAppcastItem *)bestItemFromAppcastItems:(NSArray *)appcastItems getDeltaItem item = candidate; } } - - if (item && deltaItem) { - SUAppcastItem *deltaUpdateItem = [item deltaUpdates][hostVersion]; - if (deltaUpdateItem) { - *deltaItem = deltaUpdateItem; - } + return item; +} + +// This method is used by unit tests +// This method should not do *any* filtering, only version comparing ++ (SUAppcastItem *)bestItemFromAppcastItems:(NSArray *)appcastItems getDeltaItem:(SUAppcastItem * __autoreleasing *)deltaItem withHostVersion:(NSString *)hostVersion comparator:(id<SUVersionComparison>)comparator +{ + SUAppcastItem *item = [self bestItemFromAppcastItems:appcastItems comparator:comparator]; + if (item != nil && deltaItem != NULL) { + *deltaItem = [self deltaUpdateFromAppcastItem:item hostVersion:hostVersion]; } - return item; } From 71557fac858668a016197491899449bf30fcd76f Mon Sep 17 00:00:00 2001 From: Zorg <zorgiepoo@gmail.com> Date: Sun, 25 Apr 2021 12:15:44 -0700 Subject: [PATCH 2/4] Include secondary non-delta update to resumable updates --- Sparkle/SPUAutomaticUpdateDriver.m | 6 +++--- Sparkle/SPUBasicUpdateDriver.h | 4 +--- Sparkle/SPUBasicUpdateDriver.m | 21 ++++++++------------- Sparkle/SPUCoreBasedUpdateDriver.h | 6 +++--- Sparkle/SPUCoreBasedUpdateDriver.m | 25 +++++++++++++++---------- Sparkle/SPUDownloadDriver.h | 2 +- Sparkle/SPUDownloadDriver.m | 7 +++++-- Sparkle/SPUDownloadedUpdate.h | 2 +- Sparkle/SPUDownloadedUpdate.m | 4 +++- Sparkle/SPUInformationalUpdate.h | 2 +- Sparkle/SPUInformationalUpdate.m | 4 +++- Sparkle/SPUProbingUpdateDriver.m | 2 +- Sparkle/SPUResumableUpdate.h | 1 + Sparkle/SPUUIBasedUpdateDriver.m | 6 +++--- Sparkle/SUAppcastDriver.h | 4 +--- Sparkle/SUAppcastDriver.m | 5 +---- 16 files changed, 51 insertions(+), 50 deletions(-) diff --git a/Sparkle/SPUAutomaticUpdateDriver.m b/Sparkle/SPUAutomaticUpdateDriver.m index c6626fa344..8d2ce908fc 100644 --- a/Sparkle/SPUAutomaticUpdateDriver.m +++ b/Sparkle/SPUAutomaticUpdateDriver.m @@ -77,15 +77,15 @@ - (void)resumeUpdate:(id<SPUResumableUpdate>)__unused resumableUpdate completion SULog(SULogLevelError, @"Error: resumeDownloadedUpdate:completion: called on SPUAutomaticUpdateDriver"); } -- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate +- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate { self.updateItem = updateItem; if (updateItem.isInformationOnlyUpdate || preventsAutoupdate) { - [self.coreDriver deferInformationalUpdate:updateItem preventsAutoupdate:preventsAutoupdate]; + [self.coreDriver deferInformationalUpdate:updateItem secondaryUpdate:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate]; [self abortUpdate]; } else { - [self.coreDriver downloadUpdateFromAppcastItem:updateItem inBackground:YES]; + [self.coreDriver downloadUpdateFromAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem inBackground:YES]; } } diff --git a/Sparkle/SPUBasicUpdateDriver.h b/Sparkle/SPUBasicUpdateDriver.h index 107dd0200f..dcde2abfef 100644 --- a/Sparkle/SPUBasicUpdateDriver.h +++ b/Sparkle/SPUBasicUpdateDriver.h @@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol SPUBasicUpdateDriverDelegate <NSObject> -- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)appcastItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain; +- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)appcastItem secondaryAppcastItem:(SUAppcastItem *)secondaryAppcastItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain; - (void)basicDriverIsRequestingAbortUpdateWithError:(nullable NSError *)error; @@ -38,8 +38,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpdateDriverCompletion)completionBlock; -@property (nullable, nonatomic, readonly) SUAppcastItem *secondaryUpdateItem; - - (void)abortUpdateAndShowNextUpdateImmediately:(BOOL)shouldSignalShowingUpdate resumableUpdate:(id<SPUResumableUpdate> _Nullable)resumableUpdate error:(nullable NSError *)error; @end diff --git a/Sparkle/SPUBasicUpdateDriver.m b/Sparkle/SPUBasicUpdateDriver.m index 2a3be1d4a4..c6427f1ca8 100644 --- a/Sparkle/SPUBasicUpdateDriver.m +++ b/Sparkle/SPUBasicUpdateDriver.m @@ -79,7 +79,7 @@ - (void)checkForUpdatesAtAppcastURL:(NSURL *)appcastURL withUserAgent:(NSString } } -- (void)notifyResumableUpdateItem:(SUAppcastItem *)updateItem systemDomain:(NSNumber * _Nullable)systemDomain +- (void)notifyResumableUpdateItem:(SUAppcastItem *)updateItem secondaryUpdateItem:(SUAppcastItem *)secondaryUpdateItem systemDomain:(NSNumber * _Nullable)systemDomain { if (updateItem == nil) { [self.delegate basicDriverIsRequestingAbortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUResumeAppcastError userInfo:@{ NSLocalizedDescriptionKey: SULocalizedString(@"Failed to resume installing update.", nil) }]]; @@ -88,7 +88,7 @@ - (void)notifyResumableUpdateItem:(SUAppcastItem *)updateItem systemDomain:(NSNu [self notifyFinishLoadingAppcast]; SUAppcastItem *nonNullUpdateItem = updateItem; - [self notifyFoundValidUpdateWithAppcastItem:nonNullUpdateItem preventsAutoupdate:NO systemDomain:systemDomain]; + [self notifyFoundValidUpdateWithAppcastItem:nonNullUpdateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:NO systemDomain:systemDomain]; } } @@ -100,7 +100,7 @@ - (void)resumeInstallingUpdateWithCompletion:(SPUUpdateDriverCompletion)completi assert(hostBundleIdentifier != nil); [SPUProbeInstallStatus probeInstallerUpdateItemForHostBundleIdentifier:hostBundleIdentifier completion:^(SPUInstallationInfo * _Nullable installationInfo) { dispatch_async(dispatch_get_main_queue(), ^{ - [self notifyResumableUpdateItem:installationInfo.appcastItem systemDomain:@(installationInfo.systemDomain)]; + [self notifyResumableUpdateItem:installationInfo.appcastItem secondaryUpdateItem:nil systemDomain:@(installationInfo.systemDomain)]; }); }]; } @@ -109,12 +109,7 @@ - (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpda { self.completionBlock = completionBlock; - [self notifyResumableUpdateItem:resumableUpdate.updateItem systemDomain:nil]; -} - -- (SUAppcastItem *)secondaryUpdateItem -{ - return self.appcastDriver.secondaryUpdateItem; + [self notifyResumableUpdateItem:resumableUpdate.updateItem secondaryUpdateItem:resumableUpdate.secondaryUpdateItem systemDomain:nil]; } - (void)didFailToFetchAppcastWithError:(NSError *)error @@ -142,7 +137,7 @@ - (void)didFinishLoadingAppcast:(SUAppcast *)appcast } } -- (void)notifyFoundValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain +- (void)notifyFoundValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain { if (!self.aborted) { [[NSNotificationCenter defaultCenter] postNotificationName:SUUpdaterDidFindValidUpdateNotification @@ -153,13 +148,13 @@ - (void)notifyFoundValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem preven [self.updaterDelegate updater:self.updater didFindValidUpdate:updateItem]; } - [self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate systemDomain:systemDomain]; + [self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate systemDomain:systemDomain]; } } -- (void)didFindValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate +- (void)didFindValidUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryAppcastItem preventsAutoupdate:(BOOL)preventsAutoupdate { - [self notifyFoundValidUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate systemDomain:nil]; + [self notifyFoundValidUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryAppcastItem preventsAutoupdate:preventsAutoupdate systemDomain:nil]; } - (void)didNotFindUpdateWithLatestAppcastItem:(nullable SUAppcastItem *)latestAppcastItem hostToLatestAppcastItemComparisonResult:(NSComparisonResult)hostToLatestAppcastItemComparisonResult diff --git a/Sparkle/SPUCoreBasedUpdateDriver.h b/Sparkle/SPUCoreBasedUpdateDriver.h index 57806ee8e4..f936e9b00c 100644 --- a/Sparkle/SPUCoreBasedUpdateDriver.h +++ b/Sparkle/SPUCoreBasedUpdateDriver.h @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol SPUCoreBasedUpdateDriverDelegate <NSObject> -- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate; +- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryAppcastItem preventsAutoupdate:(BOOL)preventsAutoupdate; - (void)installerDidFinishPreparationAndWillInstallImmediately:(BOOL)willInstallImmediately silently:(BOOL)willInstallSilently; @@ -61,9 +61,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpdateDriverCompletion)completionBlock; -- (void)downloadUpdateFromAppcastItem:(SUAppcastItem *)updateItem inBackground:(BOOL)background; +- (void)downloadUpdateFromAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem * _Nullable)secondaryUpdateItem inBackground:(BOOL)background; -- (void)deferInformationalUpdate:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate; +- (void)deferInformationalUpdate:(SUAppcastItem *)updateItem secondaryUpdate:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate; - (void)extractDownloadedUpdate; diff --git a/Sparkle/SPUCoreBasedUpdateDriver.m b/Sparkle/SPUCoreBasedUpdateDriver.m index 4b5c435f9a..b095524ffe 100644 --- a/Sparkle/SPUCoreBasedUpdateDriver.m +++ b/Sparkle/SPUCoreBasedUpdateDriver.m @@ -32,6 +32,7 @@ @interface SPUCoreBasedUpdateDriver () <SPUBasicUpdateDriverDelegate, SPUDownloa @property (nonatomic, readonly) SPUInstallerDriver *installerDriver; @property (nonatomic, weak, readonly) id<SPUCoreBasedUpdateDriverDelegate> delegate; @property (nonatomic) SUAppcastItem *updateItem; +@property (nonatomic) SUAppcastItem *secondaryUpdateItem; @property (nonatomic) id<SPUResumableUpdate> resumableUpdate; @property (nonatomic) SPUDownloadedUpdate *downloadedUpdateForRemoval; @@ -53,6 +54,7 @@ @implementation SPUCoreBasedUpdateDriver @synthesize installerDriver = _installerDriver; @synthesize delegate = _delegate; @synthesize updateItem = _updateItem; +@synthesize secondaryUpdateItem = _secondaryUpdateItem; @synthesize host = _host; @synthesize resumingInstallingUpdate = _resumingInstallingUpdate; @synthesize silentInstall = _silentInstall; @@ -147,33 +149,34 @@ - (void)basicDriverDidFinishLoadingAppcast } } -- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain +- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate systemDomain:(NSNumber * _Nullable)systemDomain { self.updateItem = updateItem; + self.secondaryUpdateItem = secondaryUpdateItem; if (self.resumingInstallingUpdate) { assert(systemDomain != nil); [self.installerDriver resumeInstallingUpdateWithUpdateItem:updateItem systemDomain:systemDomain.boolValue]; - [self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate]; + [self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate]; } else { if (!self.preventsInstallerInteraction) { // Simple case - delegate allows interaction, so we should continue along - [self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate]; + [self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate]; } else { // Package type installations will always require installer interaction as long as we don't support running as root // If it's not a package type installation, we should be okay since we did an auth check before checking for updates above if (![updateItem.installationType isEqualToString:SPUInstallationTypeApplication]) { [self.delegate coreDriverIsRequestingAbortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUNotAllowedInteractionError userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"A new update is available but cannot be installed because interaction has been prevented."] }]]; } else { - [self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate]; + [self.delegate basicDriverDidFindUpdateWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate]; } } } } -- (void)downloadUpdateFromAppcastItem:(SUAppcastItem *)updateItem inBackground:(BOOL)background +- (void)downloadUpdateFromAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem * _Nullable)secondaryUpdateItem inBackground:(BOOL)background { - self.downloadDriver = [[SPUDownloadDriver alloc] initWithUpdateItem:updateItem host:self.host userAgent:self.userAgent httpHeaders:self.httpHeaders inBackground:background delegate:self]; + self.downloadDriver = [[SPUDownloadDriver alloc] initWithUpdateItem:updateItem secondaryUpdateItem:secondaryUpdateItem host:self.host userAgent:self.userAgent httpHeaders:self.httpHeaders inBackground:background delegate:self]; if ([self.updaterDelegate respondsToSelector:@selector((updater:willDownloadUpdate:withRequest:))]) { [self.updaterDelegate updater:self.updater @@ -222,9 +225,9 @@ - (void)downloadDriverDidDownloadUpdate:(SPUDownloadedUpdate *)downloadedUpdate [self extractUpdate:downloadedUpdate]; } -- (void)deferInformationalUpdate:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate +- (void)deferInformationalUpdate:(SUAppcastItem *)updateItem secondaryUpdate:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate { - self.resumableUpdate = [[SPUInformationalUpdate alloc] initWithAppcastItem:updateItem preventsAutoupdate:preventsAutoupdate]; + self.resumableUpdate = [[SPUInformationalUpdate alloc] initWithAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem preventsAutoupdate:preventsAutoupdate]; } - (void)extractDownloadedUpdate @@ -381,7 +384,7 @@ - (void)basicDriverIsRequestingAbortUpdateWithError:(nullable NSError *)error - (void)installerDidFailToApplyDeltaUpdate { - SUAppcastItem *secondaryUpdateItem = self.basicDriver.secondaryUpdateItem; + SUAppcastItem *secondaryUpdateItem = self.secondaryUpdateItem; assert(secondaryUpdateItem != nil); BOOL backgroundDownload = self.downloadDriver.inBackground; @@ -390,7 +393,9 @@ - (void)installerDidFailToApplyDeltaUpdate // Fall back to the non-delta update. Note that we don't want to trigger another update was found event. self.updateItem = secondaryUpdateItem; - [self downloadUpdateFromAppcastItem:secondaryUpdateItem inBackground:backgroundDownload]; + self.secondaryUpdateItem = nil; + + [self downloadUpdateFromAppcastItem:secondaryUpdateItem secondaryAppcastItem:nil inBackground:backgroundDownload]; } - (void)abortUpdateAndShowNextUpdateImmediately:(BOOL)shouldShowUpdateImmediately error:(nullable NSError *)error diff --git a/Sparkle/SPUDownloadDriver.h b/Sparkle/SPUDownloadDriver.h index 43fd6667af..14934806b5 100644 --- a/Sparkle/SPUDownloadDriver.h +++ b/Sparkle/SPUDownloadDriver.h @@ -28,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @interface SPUDownloadDriver : NSObject -- (instancetype)initWithUpdateItem:(SUAppcastItem *)updateItem host:(SUHost *)host userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background delegate:(id<SPUDownloadDriverDelegate>)delegate; +- (instancetype)initWithUpdateItem:(SUAppcastItem *)updateItem secondaryUpdateItem:(SUAppcastItem * _Nullable)secondaryUpdateItem host:(SUHost *)host userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background delegate:(id<SPUDownloadDriverDelegate>)delegate; - (instancetype)initWithHost:(SUHost *)host; diff --git a/Sparkle/SPUDownloadDriver.m b/Sparkle/SPUDownloadDriver.m index 7624510aad..7b7c3c039f 100644 --- a/Sparkle/SPUDownloadDriver.m +++ b/Sparkle/SPUDownloadDriver.m @@ -28,6 +28,7 @@ @interface SPUDownloadDriver () <SPUDownloaderDelegate> @property (nonatomic) id<SPUDownloaderProtocol> downloader; @property (nonatomic) NSXPCConnection *connection; @property (nonatomic, readonly) SUAppcastItem *updateItem; +@property (nonatomic, readonly) SUAppcastItem *secondaryUpdateItem; @property (nonatomic, readonly) SUHost *host; @property (nonatomic, copy) NSString *temporaryDirectory; @property (nonatomic, copy) NSString *downloadName; @@ -43,6 +44,7 @@ @implementation SPUDownloadDriver @synthesize downloader = _downloader; @synthesize connection = _connection; @synthesize updateItem = _updateItem; +@synthesize secondaryUpdateItem = _secondaryUpdateItem; @synthesize request = _request; @synthesize inBackground = _inBackground; @synthesize host = _host; @@ -106,11 +108,12 @@ - (instancetype)initWithHost:(SUHost *)host return self; } -- (instancetype)initWithUpdateItem:(SUAppcastItem *)updateItem host:(SUHost *)host userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background delegate:(id<SPUDownloadDriverDelegate>)delegate +- (instancetype)initWithUpdateItem:(SUAppcastItem *)updateItem secondaryUpdateItem:(SUAppcastItem * _Nullable)secondaryUpdateItem host:(SUHost *)host userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background delegate:(id<SPUDownloadDriverDelegate>)delegate { self = [self initWithHost:host]; if (self != nil) { _updateItem = updateItem; + _secondaryUpdateItem = secondaryUpdateItem; _delegate = delegate; _inBackground = background; @@ -188,7 +191,7 @@ - (void)downloaderDidFinishWithTemporaryDownloadData:(SPUDownloadData * _Nullabl SULog(SULogLevelError, @"Warning: Downloader's expected content length (%llu) != Appcast item's length (%llu)", self.expectedContentLength, self.updateItem.contentLength); } - SPUDownloadedUpdate *downloadedUpdate = [[SPUDownloadedUpdate alloc] initWithAppcastItem:self.updateItem downloadName:self.downloadName temporaryDirectory:self.temporaryDirectory]; + SPUDownloadedUpdate *downloadedUpdate = [[SPUDownloadedUpdate alloc] initWithAppcastItem:self.updateItem secondaryAppcastItem:self.secondaryUpdateItem downloadName:self.downloadName temporaryDirectory:self.temporaryDirectory]; [self.delegate downloadDriverDidDownloadUpdate:downloadedUpdate]; }); diff --git a/Sparkle/SPUDownloadedUpdate.h b/Sparkle/SPUDownloadedUpdate.h index 349d03a48a..2dc0a842c4 100644 --- a/Sparkle/SPUDownloadedUpdate.h +++ b/Sparkle/SPUDownloadedUpdate.h @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @interface SPUDownloadedUpdate : NSObject <SPUResumableUpdate> -- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem downloadName:(NSString *)downloadName temporaryDirectory:(NSString *)temporaryDirectory; +- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem * _Nullable)secondaryItem downloadName:(NSString *)downloadName temporaryDirectory:(NSString *)temporaryDirectory; @property (nonatomic, copy, readonly) NSString *downloadName; @property (nonatomic, copy, readonly) NSString *temporaryDirectory; diff --git a/Sparkle/SPUDownloadedUpdate.m b/Sparkle/SPUDownloadedUpdate.m index 07b8cdb804..f3d7b520c1 100644 --- a/Sparkle/SPUDownloadedUpdate.m +++ b/Sparkle/SPUDownloadedUpdate.m @@ -16,15 +16,17 @@ @implementation SPUDownloadedUpdate // If we ever enable auto-synthesize in the future, we'll still need this synthesize // because the property is declared in a protocol @synthesize updateItem = _updateItem; +@synthesize secondaryUpdateItem = _secondaryUpdateItem; @synthesize downloadName = _downloadName; @synthesize temporaryDirectory = _temporaryDirectory; -- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem downloadName:(NSString *)downloadName temporaryDirectory:(NSString *)temporaryDirectory +- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem * _Nullable)secondaryUpdateItem downloadName:(NSString *)downloadName temporaryDirectory:(NSString *)temporaryDirectory { self = [super init]; if (self != nil) { _updateItem = updateItem; + _secondaryUpdateItem = secondaryUpdateItem; _downloadName = [downloadName copy]; _temporaryDirectory = [temporaryDirectory copy]; } diff --git a/Sparkle/SPUInformationalUpdate.h b/Sparkle/SPUInformationalUpdate.h index c26b03f48f..0d54f99d09 100644 --- a/Sparkle/SPUInformationalUpdate.h +++ b/Sparkle/SPUInformationalUpdate.h @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @interface SPUInformationalUpdate : NSObject <SPUResumableUpdate> -- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate; +- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate; @end diff --git a/Sparkle/SPUInformationalUpdate.m b/Sparkle/SPUInformationalUpdate.m index 6dd3b15c51..e9eec62f3d 100644 --- a/Sparkle/SPUInformationalUpdate.m +++ b/Sparkle/SPUInformationalUpdate.m @@ -16,13 +16,15 @@ @implementation SPUInformationalUpdate // If we ever enable auto-synthesize in the future, we'll still need this synthesize // because the property is declared in a protocol @synthesize updateItem = _updateItem; +@synthesize secondaryUpdateItem = _secondaryUpdateItem; @synthesize preventsAutoupdate = _preventsAutoupdate; -- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate +- (instancetype)initWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate { self = [super init]; if (self != nil) { _updateItem = updateItem; + _secondaryUpdateItem = secondaryUpdateItem; _preventsAutoupdate = preventsAutoupdate; } return self; diff --git a/Sparkle/SPUProbingUpdateDriver.m b/Sparkle/SPUProbingUpdateDriver.m index 6cd8fc3b30..bb377ef7da 100644 --- a/Sparkle/SPUProbingUpdateDriver.m +++ b/Sparkle/SPUProbingUpdateDriver.m @@ -54,7 +54,7 @@ - (void)resumeUpdate:(id<SPUResumableUpdate>)resumableUpdate completion:(SPUUpda [self.basicDriver resumeUpdate:resumableUpdate completion:completionBlock]; } -- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)__unused appcastItem preventsAutoupdate:(BOOL)__unused preventsAutoupdate systemDomain:(NSNumber * _Nullable)__unused systemDomain +- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)__unused appcastItem secondaryAppcastItem:(SUAppcastItem *)__unused secondaryAppcastItem preventsAutoupdate:(BOOL)__unused preventsAutoupdate systemDomain:(NSNumber * _Nullable)__unused systemDomain { // Stop as soon as we have an answer [self abortUpdate]; diff --git a/Sparkle/SPUResumableUpdate.h b/Sparkle/SPUResumableUpdate.h index 65ad7db66d..895a80c888 100644 --- a/Sparkle/SPUResumableUpdate.h +++ b/Sparkle/SPUResumableUpdate.h @@ -15,6 +15,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol SPUResumableUpdate <NSObject> @property (nonatomic, readonly) SUAppcastItem *updateItem; +@property (nonatomic, readonly, nullable) SUAppcastItem *secondaryUpdateItem; @property (nonatomic, readonly) BOOL preventsAutoupdate; @end diff --git a/Sparkle/SPUUIBasedUpdateDriver.m b/Sparkle/SPUUIBasedUpdateDriver.m index ea29f6d0f6..54ae8de44b 100644 --- a/Sparkle/SPUUIBasedUpdateDriver.m +++ b/Sparkle/SPUUIBasedUpdateDriver.m @@ -105,7 +105,7 @@ - (void)basicDriverDidFinishLoadingAppcast } } -- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem preventsAutoupdate:(BOOL)preventsAutoupdate +- (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem secondaryAppcastItem:(SUAppcastItem *)secondaryUpdateItem preventsAutoupdate:(BOOL)preventsAutoupdate { id <SPUUpdaterDelegate> updaterDelegate = self.updaterDelegate; if ([self.userDriver respondsToSelector:@selector(showUpdateFoundWithAppcastItem:userInitiated:state:reply:)]) { @@ -143,7 +143,7 @@ - (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem prev [self.coreDriver finishInstallationWithResponse:validatedChoice displayingUserInterface:!self.preventsInstallerInteraction]; break; case SPUUserUpdateStateNotDownloaded: - [self.coreDriver downloadUpdateFromAppcastItem:updateItem inBackground:NO]; + [self.coreDriver downloadUpdateFromAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem inBackground:NO]; break; case SPUUserUpdateStateInformational: assert(false); @@ -235,7 +235,7 @@ - (void)basicDriverDidFindUpdateWithAppcastItem:(SUAppcastItem *)updateItem prev [self.host setObject:nil forUserDefaultsKey:SUSkippedVersionKey]; switch (choice) { case SPUInstallUpdateChoice: - [self.coreDriver downloadUpdateFromAppcastItem:updateItem inBackground:NO]; + [self.coreDriver downloadUpdateFromAppcastItem:updateItem secondaryAppcastItem:secondaryUpdateItem inBackground:NO]; break; case SPUSkipThisVersionChoice: [self.host setObject:[updateItem versionString] forUserDefaultsKey:SUSkippedVersionKey]; diff --git a/Sparkle/SUAppcastDriver.h b/Sparkle/SUAppcastDriver.h index d9a6a3cfa6..e96686783d 100644 --- a/Sparkle/SUAppcastDriver.h +++ b/Sparkle/SUAppcastDriver.h @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)didFailToFetchAppcastWithError:(NSError *)error; - (void)didFinishLoadingAppcast:(SUAppcast *)appcast; -- (void)didFindValidUpdateWithAppcastItem:(SUAppcastItem *)appcastItem preventsAutoupdate:(BOOL)preventsAutoupdate; +- (void)didFindValidUpdateWithAppcastItem:(SUAppcastItem *)appcastItem secondaryAppcastItem:(SUAppcastItem *)secondaryAppcastItem preventsAutoupdate:(BOOL)preventsAutoupdate; - (void)didNotFindUpdateWithLatestAppcastItem:(nullable SUAppcastItem *)latestAppcastItem hostToLatestAppcastItemComparisonResult:(NSComparisonResult)hostToLatestAppcastItemComparisonResult; @end @@ -28,8 +28,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)loadAppcastFromURL:(NSURL *)appcastURL userAgent:(NSString *)userAgent httpHeaders:(NSDictionary * _Nullable)httpHeaders inBackground:(BOOL)background includesSkippedUpdates:(BOOL)includesSkippedUpdates; -@property (nullable, nonatomic, readonly) SUAppcastItem *secondaryUpdateItem; - @end NS_ASSUME_NONNULL_END diff --git a/Sparkle/SUAppcastDriver.m b/Sparkle/SUAppcastDriver.m index 9dfb4a01e3..69728e454b 100644 --- a/Sparkle/SUAppcastDriver.m +++ b/Sparkle/SUAppcastDriver.m @@ -27,7 +27,6 @@ @interface SUAppcastDriver () @property (nonatomic, copy) NSString *userAgent; @property (nullable, nonatomic, readonly, weak) id updater; @property (nullable, nonatomic, readonly, weak) id <SPUUpdaterDelegate> updaterDelegate; -@property (nullable, nonatomic) SUAppcastItem *secondaryUpdateItem; @property (nullable, nonatomic, readonly, weak) id <SUAppcastDriverDelegate> delegate; @end @@ -38,7 +37,6 @@ @implementation SUAppcastDriver @synthesize userAgent = _userAgent; @synthesize updater = _updater; @synthesize updaterDelegate = _updaterDelegate; -@synthesize secondaryUpdateItem = _secondaryUpdateItem; @synthesize delegate = _delegate; - (instancetype)initWithHost:(SUHost *)host updater:(id)updater updaterDelegate:(id <SPUUpdaterDelegate>)updaterDelegate delegate:(id <SUAppcastDriverDelegate>)delegate @@ -124,8 +122,7 @@ - (void)appcastDidFinishLoading:(SUAppcast *)loadedAppcast inBackground:(BOOL)ba } if ([self itemContainsValidUpdate:item inBackground:background includesSkippedUpdates:includesSkippedUpdates]) { - self.secondaryUpdateItem = secondaryItem; - [self.delegate didFindValidUpdateWithAppcastItem:item preventsAutoupdate:[self itemPreventsAutoupdate:item]]; + [self.delegate didFindValidUpdateWithAppcastItem:item secondaryAppcastItem:secondaryItem preventsAutoupdate:[self itemPreventsAutoupdate:item]]; } else { NSComparisonResult hostToLatestAppcastItemComparisonResult = (item != nil) ? [[self versionComparator] compareVersion:[self.host version] toVersion:[item versionString]] : 0; [self.delegate didNotFindUpdateWithLatestAppcastItem:item hostToLatestAppcastItemComparisonResult:hostToLatestAppcastItemComparisonResult]; From 564f0c316ac672d44693c9b6d80c56a2c383cbe0 Mon Sep 17 00:00:00 2001 From: Zorg <zorgiepoo@gmail.com> Date: Sun, 25 Apr 2021 13:57:09 -0700 Subject: [PATCH 3/4] Refactor retrieving regular & delta update items --- Sparkle/SUAppcastDriver.m | 45 +++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/Sparkle/SUAppcastDriver.m b/Sparkle/SUAppcastDriver.m index 69728e454b..44101dadfa 100644 --- a/Sparkle/SUAppcastDriver.m +++ b/Sparkle/SUAppcastDriver.m @@ -70,6 +70,9 @@ - (void)loadAppcastFromURL:(NSURL *)appcastURL userAgent:(NSString *)userAgent h - (SUAppcastItem * _Nullable)preferredUpdateForRegularAppcastItem:(SUAppcastItem * _Nullable)regularItem secondaryUpdate:(SUAppcastItem * __autoreleasing _Nullable *)secondaryUpdate { if (regularItem == nil) { + if (secondaryUpdate != NULL) { + *secondaryUpdate = nil; + } return nil; } @@ -95,37 +98,43 @@ - (void)appcastDidFinishLoading:(SUAppcast *)loadedAppcast inBackground:(BOOL)ba NSNumber *phasedUpdateGroup = background ? @([SUPhasedUpdateGroupInfo updateGroupForHost:self.host]) : nil; SUAppcast *supportedAppcast = [[self class] filterSupportedAppcast:loadedAppcast phasedUpdateGroup:phasedUpdateGroup]; - SUAppcastItem *item = nil; - SUAppcastItem *secondaryItem = nil; - // Find the best valid update in the appcast by asking the delegate - if ([self.updaterDelegate respondsToSelector:@selector((bestValidUpdateInAppcast:forUpdater:))]) - { - SUAppcastItem *regularItem = [self.updaterDelegate bestValidUpdateInAppcast:supportedAppcast forUpdater:(id _Nonnull)self.updater]; + SUAppcastItem *regularItemFromDelegate; + if ([self.updaterDelegate respondsToSelector:@selector((bestValidUpdateInAppcast:forUpdater:))]) { + SUAppcastItem *candidateItem = [self.updaterDelegate bestValidUpdateInAppcast:supportedAppcast forUpdater:(id _Nonnull)self.updater]; - assert(!regularItem.deltaUpdate); - if (regularItem.deltaUpdate) { + assert(!candidateItem.deltaUpdate); + if (candidateItem.deltaUpdate) { // Client would have to go out of their way to examine the .deltaUpdates to return one // This is very unlikely, and we need them to give us a regular update item back SULog(SULogLevelError, @"Error: -bestValidUpdateInAppcast:forUpdater: cannot return a delta update item"); + regularItemFromDelegate = nil; } else { - item = [self preferredUpdateForRegularAppcastItem:regularItem secondaryUpdate:&secondaryItem]; + regularItemFromDelegate = candidateItem; } + } else { + regularItemFromDelegate = nil; } // Take care of finding best appcast item ourselves if delegate does not - if (item == nil) - { - SUAppcastItem *regularItem = [[self class] bestItemFromAppcastItems:supportedAppcast.items comparator:[self versionComparator]]; - - item = [self preferredUpdateForRegularAppcastItem:regularItem secondaryUpdate:&secondaryItem]; + SUAppcastItem *regularItem; + if (regularItemFromDelegate == nil) { + regularItem = [[self class] bestItemFromAppcastItems:supportedAppcast.items comparator:[self versionComparator]]; + } else { + regularItem = regularItemFromDelegate; } - if ([self itemContainsValidUpdate:item inBackground:background includesSkippedUpdates:includesSkippedUpdates]) { - [self.delegate didFindValidUpdateWithAppcastItem:item secondaryAppcastItem:secondaryItem preventsAutoupdate:[self itemPreventsAutoupdate:item]]; + // Retrieve the preferred primary and secondary update items + // In the case of a delta update, the preferred primary item will be the delta update, + // and the secondary item will be the regular update. + SUAppcastItem *secondaryItem = nil; + SUAppcastItem *primaryItem = [self preferredUpdateForRegularAppcastItem:regularItem secondaryUpdate:&secondaryItem]; + + if ([self itemContainsValidUpdate:primaryItem inBackground:background includesSkippedUpdates:includesSkippedUpdates]) { + [self.delegate didFindValidUpdateWithAppcastItem:primaryItem secondaryAppcastItem:secondaryItem preventsAutoupdate:[self itemPreventsAutoupdate:primaryItem]]; } else { - NSComparisonResult hostToLatestAppcastItemComparisonResult = (item != nil) ? [[self versionComparator] compareVersion:[self.host version] toVersion:[item versionString]] : 0; - [self.delegate didNotFindUpdateWithLatestAppcastItem:item hostToLatestAppcastItemComparisonResult:hostToLatestAppcastItemComparisonResult]; + NSComparisonResult hostToLatestAppcastItemComparisonResult = (primaryItem != nil) ? [[self versionComparator] compareVersion:[self.host version] toVersion:[primaryItem versionString]] : 0; + [self.delegate didNotFindUpdateWithLatestAppcastItem:primaryItem hostToLatestAppcastItemComparisonResult:hostToLatestAppcastItemComparisonResult]; } } From 063974c5537aba2c03aec74336b620ada0b3a131 Mon Sep 17 00:00:00 2001 From: Zorg <zorgiepoo@gmail.com> Date: Sun, 25 Apr 2021 14:28:33 -0700 Subject: [PATCH 4/4] Simplify logic in -preferredUpdateForRegularAppcastItem method --- Sparkle/SUAppcastDriver.m | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Sparkle/SUAppcastDriver.m b/Sparkle/SUAppcastDriver.m index 44101dadfa..64366002e4 100644 --- a/Sparkle/SUAppcastDriver.m +++ b/Sparkle/SUAppcastDriver.m @@ -69,14 +69,7 @@ - (void)loadAppcastFromURL:(NSURL *)appcastURL userAgent:(NSString *)userAgent h - (SUAppcastItem * _Nullable)preferredUpdateForRegularAppcastItem:(SUAppcastItem * _Nullable)regularItem secondaryUpdate:(SUAppcastItem * __autoreleasing _Nullable *)secondaryUpdate { - if (regularItem == nil) { - if (secondaryUpdate != NULL) { - *secondaryUpdate = nil; - } - return nil; - } - - SUAppcastItem *deltaItem = [[self class] deltaUpdateFromAppcastItem:regularItem hostVersion:self.host.version]; + SUAppcastItem *deltaItem = (regularItem != nil) ? [[self class] deltaUpdateFromAppcastItem:regularItem hostVersion:self.host.version] : nil; if (deltaItem != nil) { if (secondaryUpdate != NULL) { @@ -84,6 +77,9 @@ - (SUAppcastItem * _Nullable)preferredUpdateForRegularAppcastItem:(SUAppcastItem } return deltaItem; } else { + if (secondaryUpdate != NULL) { + *secondaryUpdate = nil; + } return regularItem; } }