Permalink
Browse files

Touched practically every line of code in a super-monster-awesome ref…

…actoring. Please read:

- Broke out SUUpdater functionality into update drivers. There's a basic one from which everything else inherits, then a user-initiated one, an automatic one, and a scheduled one. It's super-clean-and-shiny.
- Destroyed the abomination that was SUStatusChecker. In its place is SUProbingUpdateDriver, which is like 10 lines long.
- Made automatic installation less stupid. It used to install, THEN offer to relaunch. That's dumb, beacuse if the user says no, the app is running from the trash. Now it offers to install and relaunch or to install on quit.
- Renamed like every method and symbol. I hope you didn't branch anything.
- Reorganized the project hierarchy to be much clearer and easier to navigate.
- Reworked the error system to no use NSError instead of exceptions; extra technical information is now logged to the console so that we can find problems.
- A bunch of other small bugfixes in things I noticed along the way but no longer remember.
- Probably a ton of other stuff.
Read over the code and see what I've done. Then PLEASE test this with your app internally and let me know how it goes. This revision is hereby NOT YET DECLARED SAFE FOR PUBLIC RELEASE. But because I'm still using SVN, this is how things have to be.
  • Loading branch information...
1 parent 0e99700 commit bc3be9a1f24deb5436684f2f59d7f0379e3bc915 andym committed May 8, 2008
Showing with 1,317 additions and 904 deletions.
  1. +5 −0 NSFileManager+Aliases.h
  2. +16 −19 NSFileManager+Authentication.m
  3. +5 −0 NSFileManager+ExtendedAttributes.h
  4. +18 −0 NSURL+Parameters.h
  5. +27 −0 NSURL+Parameters.m
  6. +18 −0 NSWorkspace+SystemVersion.h
  7. +36 −0 NSWorkspace+SystemVersion.m
  8. +1 −3 RSS.h
  9. +14 −24 RSS.m
  10. +4 −3 SUAppcast.h
  11. +46 −55 SUAppcast.m
  12. +5 −27 SUAppcastItem.h
  13. +64 −85 SUAppcastItem.m
  14. +15 −3 SUAutomaticUpdateAlert.h
  15. +16 −8 SUAutomaticUpdateAlert.m
  16. +23 −0 SUAutomaticUpdateDriver.h
  17. +76 −0 SUAutomaticUpdateDriver.m
  18. +56 −0 SUBasicUpdateDriver.h
  19. +208 −0 SUBasicUpdateDriver.m
  20. +17 −0 SUConstants.h
  21. +17 −4 SUConstants.m
  22. +7 −6 SUInstaller.h
  23. +2 −3 SUInstaller.m
  24. +5 −0 SUPackageInstaller.h
  25. +6 −1 SUPlainInstaller.h
  26. +14 −2 SUPlainInstaller.m
  27. +24 −0 SUProbingUpdateDriver.h
  28. +28 −0 SUProbingUpdateDriver.m
  29. +21 −0 SUScheduledUpdateDriver.h
  30. +39 −0 SUScheduledUpdateDriver.m
  31. +0 −30 SUStatusChecker.h
  32. +0 −78 SUStatusChecker.m
  33. +1 −1 SUSystemProfiler.m
  34. +27 −0 SUUpdateDriver.h
  35. +26 −0 SUUpdateDriver.m
  36. +2 −2 SUUpdatePermissionPrompt.h
  37. +1 −1 SUUpdatePermissionPrompt.m
  38. +6 −33 SUUpdater.h
  39. +51 −453 SUUpdater.m
  40. +23 −0 SUUserInitiatedUpdateDriver.h
  41. +151 −0 SUUserInitiatedUpdateDriver.m
  42. +8 −1 Sparkle.h
  43. +118 −62 Sparkle.xcodeproj/project.pbxproj
  44. +50 −0 en.lproj/SUAutomaticUpdateAlert.nib/classes.nib
  45. +20 −0 en.lproj/SUAutomaticUpdateAlert.nib/info.nib
  46. BIN en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
View
@@ -6,8 +6,13 @@
// Copyright 2008 Andy Matuschak. All rights reserved.
//
+#ifndef NSFILEMANAGER_PLUS_ALIASES_H
+#define NSFILEMANAGER_PLUS_ALIASES_H
+
#import <Cocoa/Cocoa.h>
@interface NSFileManager (Aliases)
- (BOOL)isAliasFolderAtPath:(NSString *)path;
@end
+
+#endif
@@ -88,7 +88,13 @@ - (NSString *)_temporaryCopyNameForPath:(NSString *)path
}
else
postFix = @"old";
- return [[[path stringByDeletingPathExtension] stringByAppendingFormat:@" (%@)", postFix] stringByAppendingPathExtension:[path pathExtension]];
+ NSString *prefix = [[path stringByDeletingPathExtension] stringByAppendingFormat:@" (%@)", postFix];
+ NSString *tempDir = [prefix stringByAppendingPathExtension:[path pathExtension]];
+ // Now let's make sure we get a unique path.
+ int cnt=2;
+ while ([[NSFileManager defaultManager] fileExistsAtPath:tempDir] && cnt <= 999999)
+ tempDir = [NSString stringWithFormat:@"%@ %d.%@", prefix, cnt++, [path pathExtension]];
+ return tempDir;
}
- (BOOL)_copyPathWithForcedAuthentication:(NSString *)src toPath:(NSString *)dst error:(NSError **)error
@@ -206,27 +212,18 @@ - (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst erro
return [self _copyPathWithForcedAuthentication:src toPath:dst error:error];
NSString *tmpPath = [self _temporaryCopyNameForPath:dst];
-
- // We get more error information if we're running on Leopard, so let's use that if we can.
- if ([[NSFileManager defaultManager] respondsToSelector:@selector(moveItemAtPath:toPath:error:)])
+
+ if (![[NSFileManager defaultManager] movePath:dst toPath:tmpPath handler:self])
{
- if (![[NSFileManager defaultManager] moveItemAtPath:dst toPath:tmpPath error:error]) { return NO; }
- if (![[NSFileManager defaultManager] copyItemAtPath:src toPath:dst error:error]) { return NO; }
+ if (error != NULL)
+ *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Couldn't move %@ to %@.", dst, tmpPath] forKey:NSLocalizedDescriptionKey]];
+ return NO;
}
- else // We just get generic error messages.
+ if (![[NSFileManager defaultManager] copyPath:src toPath:dst handler:self])
{
- if (![[NSFileManager defaultManager] movePath:dst toPath:tmpPath handler:self])
- {
- if (error != NULL)
- *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Couldn't move %@ to %@.", dst, tmpPath] forKey:NSLocalizedDescriptionKey]];
- return NO;
- }
- if (![[NSFileManager defaultManager] copyPath:src toPath:dst handler:self])
- {
- if (error != NULL)
- *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Couldn't copy %@ to %@.", src, dst] forKey:NSLocalizedDescriptionKey]];
- return NO;
- }
+ if (error != NULL)
+ *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Couldn't copy %@ to %@.", src, dst] forKey:NSLocalizedDescriptionKey]];
+ return NO;
}
// Trash the old copy of the app.
@@ -6,6 +6,9 @@
// Copyright 2008 Mark Mentovai. All rights reserved.
//
+#ifndef NSFILEMANAGER_PLUS_EXTENDEDATTRIBUTES
+#define NSFILEMANAGER_PLUS_EXTENDEDATTRIBUTES
+
#import <Cocoa/Cocoa.h>
@interface NSFileManager (ExtendedAttributes)
@@ -46,3 +49,5 @@
- (void)releaseFromQuarantine:(NSString*)root;
@end
+
+#endif
View
@@ -0,0 +1,18 @@
+//
+// NSURL+Parameters.h
+// Sparkle
+//
+// Created by Andy Matuschak on 5/6/08.
+// Copyright 2008 Andy Matuschak. All rights reserved.
+//
+
+#ifndef NSURL_PLUS_PARAMETERS_H
+#define NSURL_PLUS_PARAMETERS_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSURL (SUParameterAdditions)
+- (NSURL *)URLWithParameters:(NSArray *)parameters;
+@end
+
+#endif
View
@@ -0,0 +1,27 @@
+//
+// NSURL+Parameters.m
+// Sparkle
+//
+// Created by Andy Matuschak on 5/6/08.
+// Copyright 2008 Andy Matuschak. All rights reserved.
+//
+
+#import "NSURL+Parameters.h"
+
+@implementation NSURL (SUParameterAdditions)
+- (NSURL *)URLWithParameters:(NSArray *)parameters;
+{
+ if (parameters == nil || [parameters count] == 0) { return self; }
+ NSMutableArray *profileInfo = [NSMutableArray array];
+ NSEnumerator *profileInfoEnumerator = [parameters objectEnumerator];
+ NSDictionary *currentProfileInfo;
+ while ((currentProfileInfo = [profileInfoEnumerator nextObject])) {
+ [profileInfo addObject:[NSString stringWithFormat:@"%@=%@", [currentProfileInfo objectForKey:@"key"], [currentProfileInfo objectForKey:@"value"]]];
+ }
+
+ NSString *appcastStringWithProfile = [NSString stringWithFormat:@"%@?%@", [self absoluteString], [profileInfo componentsJoinedByString:@"&"]];
+
+ // Clean it up so it's a valid URL
+ return [NSURL URLWithString:[appcastStringWithProfile stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
+}
+@end
@@ -0,0 +1,18 @@
+//
+// NSWorkspace+SystemVersion.h
+// Sparkle
+//
+// Created by Andy Matuschak on 5/7/08.
+// Copyright 2008 Andy Matuschak. All rights reserved.
+//
+
+#ifndef NSWORKSPACE_PLUS_SYSTEMVERSION_H
+#define NSWORKSPACE_PLUS_SYSTEMVERSION_H
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSWorkspace (SystemVersion)
++ (NSString *)systemVersionString;
+@end
+
+#endif
@@ -0,0 +1,36 @@
+//
+// NSWorkspace+SystemVersion.m
+// Sparkle
+//
+// Created by Andy Matuschak on 5/7/08.
+// Copyright 2008 Andy Matuschak. All rights reserved.
+//
+
+#import "NSWorkspace+SystemVersion.h"
+
+
+@implementation NSWorkspace (SystemVersion)
++ (NSString *)systemVersionString
+{
+ // This returns a version string of the form X.Y.Z
+ // There may be a better way to deal with the problem that gestaltSystemVersionMajor
+ // et al. are not defined in 10.3, but this is probably good enough.
+ NSString* verStr = nil;
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
+ SInt32 major, minor, bugfix;
+ OSErr err1 = Gestalt(gestaltSystemVersionMajor, &major);
+ OSErr err2 = Gestalt(gestaltSystemVersionMinor, &minor);
+ OSErr err3 = Gestalt(gestaltSystemVersionBugFix, &bugfix);
+ if (!err1 && !err2 && !err3)
+ {
+ verStr = [NSString stringWithFormat:@"%d.%d.%d", major, minor, bugfix];
+ }
+ else
+#endif
+ {
+ NSString *versionPlistPath = @"/System/Library/CoreServices/SystemVersion.plist";
+ verStr = [[[NSDictionary dictionaryWithContentsOfFile:versionPlistPath] objectForKey:@"ProductVersion"] retain];
+ }
+ return verStr;
+}
+@end
View
4 RSS.h
@@ -61,14 +61,12 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMA
/*Public*/
+- (RSS *)initWithURL:(NSURL *) url normalize:(BOOL) fl userAgent:(NSString*)userAgent error:(NSError **)error;
- (RSS *) initWithTitle: (NSString *) title andDescription: (NSString *) description;
- (RSS *) initWithData: (NSData *) rssData normalize: (BOOL) fl;
-- (RSS *) initWithURL: (NSURL *) url normalize: (BOOL) fl;
-- (RSS *) initWithURL: (NSURL *) url normalize: (BOOL) fl userAgent:(NSString *)userAgent;
-
- (NSDictionary *) headerItems;
- (NSMutableArray *) newsItems;
View
38 RSS.m
@@ -138,41 +138,31 @@ - (RSS *) initWithData: (NSData *) rssData normalize: (BOOL) fl {
} /*initWithData*/
-- (RSS *) initWithURL: (NSURL *) url normalize: (BOOL) fl
-{
- return [self initWithURL: url normalize: fl userAgent: nil];
-}
-
-- (RSS *) initWithURL: (NSURL *) url normalize: (BOOL) fl userAgent: (NSString*)userAgent
+- (RSS *)initWithURL:(NSURL *)url normalize:(BOOL)fl userAgent:(NSString*)userAgent error:(NSError **)error
{
- NSData *rssData;
-
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url cachePolicy: NSURLRequestReloadIgnoringCacheData
timeoutInterval: 30.0];
if (userAgent)
[request setValue: userAgent forHTTPHeaderField: @"User-Agent"];
- NSURLResponse *response=0;
- NSError *error=0;
-
- rssData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
+ NSURLResponse *response = nil;
+ NSData *rssData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:error];
+ if (rssData == nil) { return nil; }
- if (rssData == nil)
+ @try
{
- NSString *failureReason;
- if ([error respondsToSelector:@selector(localizedFailureReason)])
- failureReason = [error localizedFailureReason];
- else
- failureReason = [error localizedDescription];
- NSException *exception = [NSException exceptionWithName: @"RSSDownloadFailed"
- reason: failureReason userInfo: [error userInfo] ];
- [exception raise];
+ [self initWithData:rssData normalize:fl];
}
-
- return [self initWithData: rssData normalize: fl];
-} /*initWithUrl*/
+ @catch (NSException *parseException)
+ {
+ if (error)
+ *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAppcastParseError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while parsing the update feed.", nil), NSLocalizedDescriptionKey, [parseException reason], NSLocalizedFailureReasonErrorKey, nil]];
+ return nil;
+ }
+ return self;
+}
- (NSDictionary *) headerItems {
View
@@ -12,11 +12,13 @@
@class RSS, SUAppcastItem;
@interface SUAppcast : NSObject {
NSArray *items;
+ NSString *userAgentString;
id delegate;
}
-- (void)fetchAppcastFromURL:(NSURL *)url parameters:(NSArray *)parameters;
+- (void)fetchAppcastFromURL:(NSURL *)url;
- (void)setDelegate:delegate;
+- (void)setUserAgentString:(NSString *)userAgentString;
- (SUAppcastItem *)newestItem;
- (NSArray *)items;
@@ -25,8 +27,7 @@
@interface NSObject (SUAppcastDelegate)
- (void)appcastDidFinishLoading:(SUAppcast *)appcast;
-- (void)appcastDidFailToLoad:(SUAppcast *)appcast;
-- (NSString *)userAgentForAppcast:(SUAppcast *)appcast;
+- (void)appcast:(SUAppcast *)appcast failedToLoadWithError:(NSError *)error;
@end
#endif
Oops, something went wrong.

0 comments on commit bc3be9a

Please sign in to comment.