Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bde5ff2983 | ||
|
|
ae78589d3a | ||
|
|
abec74ed3f | ||
|
|
a994876d98 | ||
|
|
9d5464c693 | ||
|
|
f00ad7e91b | ||
|
|
4b0d5ffe18 | ||
|
|
d93abe66ec | ||
|
|
196abf93b8 | ||
|
|
a0079fdee0 | ||
|
|
fdb4ffa000 | ||
|
|
cc047bdc6f | ||
|
|
7231919408 |
@@ -23,6 +23,9 @@ typedef enum : NSUInteger {
|
||||
SQRLUpdaterStateAwaitingRelaunch,
|
||||
} SQRLUpdaterState;
|
||||
|
||||
// Block for providing download requests given a download url
|
||||
typedef NSURLRequest * (^SQRLRequestForDownload)(NSURL *);
|
||||
|
||||
// The domain for errors originating within SQRLUpdater.
|
||||
extern NSString * const SQRLUpdaterErrorDomain;
|
||||
|
||||
@@ -92,6 +95,15 @@ extern NSString * const SQRLUpdaterJSONObjectErrorKey;
|
||||
// This property must never be set to nil.
|
||||
@property (atomic, copy) NSURLRequest *updateRequest;
|
||||
|
||||
// The block used for fetching a given download request
|
||||
//
|
||||
// The default value is the argument that was originally passed to
|
||||
// -initWithUpdateRequest:requestForDownload:.
|
||||
//
|
||||
// If initialized with -initWithUpdateRequest: this block will
|
||||
// return a generic NSURLRequest with the provided url.
|
||||
@property (nonatomic, copy) SQRLRequestForDownload requestForDownload;
|
||||
|
||||
// The `SQRLUpdate` subclass to instantiate with the server's response.
|
||||
//
|
||||
// By default, this is `SQRLUpdate` itself, but it can be set to a custom
|
||||
@@ -111,6 +123,18 @@ extern NSString * const SQRLUpdaterJSONObjectErrorKey;
|
||||
// Returns the initialized `SQRLUpdater`.
|
||||
- (id)initWithUpdateRequest:(NSURLRequest *)updateRequest;
|
||||
|
||||
// Initializes an updater that will send the given request to check for updates
|
||||
// and passes a block to provide requests for the update downloads.
|
||||
//
|
||||
// updateRequest - Same as with initWithUpdateRequest
|
||||
// requestForDownload - Once the update url is found for the update download, allow
|
||||
// providing custom requests that can be costomized as desired.
|
||||
// Useful for including `Authorization` headers just like the
|
||||
// updateRequest param.
|
||||
//
|
||||
// Returns the initialized `SQRLUpdater`.
|
||||
- (id)initWithUpdateRequest:(NSURLRequest *)updateRequest requestForDownload:(SQRLRequestForDownload)requestForDownload;
|
||||
|
||||
// Executes `checkForUpdatesCommand` (if enabled) every `interval` seconds.
|
||||
//
|
||||
// The first check will not occur until `interval` seconds have passed.
|
||||
|
||||
+37
-1
@@ -20,6 +20,7 @@
|
||||
#import "SQRLShipItRequest.h"
|
||||
#import <ReactiveCocoa/EXTScope.h>
|
||||
#import <ReactiveCocoa/ReactiveCocoa.h>
|
||||
#import <sys/mount.h>
|
||||
|
||||
NSString * const SQRLUpdaterErrorDomain = @"SQRLUpdaterErrorDomain";
|
||||
NSString * const SQRLUpdaterServerDataErrorKey = @"SQRLUpdaterServerDataErrorKey";
|
||||
@@ -32,6 +33,9 @@ const NSInteger SQRLUpdaterErrorInvalidServerResponse = 5;
|
||||
const NSInteger SQRLUpdaterErrorInvalidJSON = 6;
|
||||
const NSInteger SQRLUpdaterErrorInvalidServerBody = 7;
|
||||
|
||||
/// The application's being run on a read-only volume.
|
||||
const NSInteger SQRLUpdaterErrorReadOnlyVolume = 8;
|
||||
|
||||
// The prefix used when creating temporary directories for updates. This will be
|
||||
// followed by a random string of characters.
|
||||
static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
|
||||
@@ -140,11 +144,19 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
|
||||
}
|
||||
|
||||
- (id)initWithUpdateRequest:(NSURLRequest *)updateRequest {
|
||||
return [self initWithUpdateRequest:updateRequest requestForDownload:^(NSURL *downloadURL) {
|
||||
return [NSURLRequest requestWithURL:downloadURL];
|
||||
}];
|
||||
}
|
||||
|
||||
- (id)initWithUpdateRequest:(NSURLRequest *)updateRequest requestForDownload:(SQRLRequestForDownload)requestForDownload {
|
||||
NSParameterAssert(updateRequest != nil);
|
||||
NSParameterAssert(requestForDownload != nil);
|
||||
|
||||
self = [super init];
|
||||
if (self == nil) return nil;
|
||||
|
||||
_requestForDownload = [requestForDownload copy];
|
||||
_updateRequest = [updateRequest copy];
|
||||
_updateClass = SQRLUpdate.class;
|
||||
|
||||
@@ -194,6 +206,16 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
|
||||
if (httpResponse.statusCode == 204 /* No Content */) {
|
||||
return [RACSignal empty];
|
||||
}
|
||||
|
||||
BOOL readOnlyVolume = [self isRunningOnReadOnlyVolume];
|
||||
if (readOnlyVolume) {
|
||||
NSDictionary *errorInfo = @{
|
||||
NSLocalizedDescriptionKey: NSLocalizedString(@"Cannot update while running on a read-only volume", nil),
|
||||
NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"The application is on a read-only volume. Please move the application and try again. If you're on macOS Sierra or later, you'll need to move the application out of the Downloads directory. See https://github.com/Squirrel/Squirrel.Mac/issues/182 for more information.", nil),
|
||||
};
|
||||
NSError *error = [NSError errorWithDomain:SQRLUpdaterErrorDomain code:SQRLUpdaterErrorReadOnlyVolume userInfo:errorInfo];
|
||||
return [RACSignal error:error];
|
||||
}
|
||||
}
|
||||
|
||||
return [RACSignal return:bodyData];
|
||||
@@ -369,7 +391,8 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
|
||||
return [[RACSignal
|
||||
defer:^{
|
||||
NSURL *zipDownloadURL = update.updateURL;
|
||||
NSMutableURLRequest *zipDownloadRequest = [NSMutableURLRequest requestWithURL:zipDownloadURL];
|
||||
NSMutableURLRequest *zipDownloadRequest = [self.requestForDownload(zipDownloadURL) mutableCopy];
|
||||
|
||||
[zipDownloadRequest setValue:@"application/zip" forHTTPHeaderField:@"Accept"];
|
||||
if (self.etag != nil) {
|
||||
[zipDownloadRequest setValue:self.etag forHTTPHeaderField:@"If-None-Match"];
|
||||
@@ -492,6 +515,19 @@ static NSString * const SQRLUpdaterUniqueTemporaryDirectoryPrefix = @"update.";
|
||||
setNameWithFormat:@"%@ -shipItStateURL", self];
|
||||
}
|
||||
|
||||
/// Is the host app running on a read-only volume?
|
||||
- (BOOL)isRunningOnReadOnlyVolume {
|
||||
struct statfs statfsInfo;
|
||||
NSURL *bundleURL = NSRunningApplication.currentApplication.bundleURL;
|
||||
int result = statfs(bundleURL.fileSystemRepresentation, &statfsInfo);
|
||||
if (result == 0) {
|
||||
return (statfsInfo.f_flags & MNT_RDONLY) != 0;
|
||||
} else {
|
||||
// If we can't even check if the volume is read-only, assume it is.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
- (RACSignal *)performHousekeeping {
|
||||
return [[RACSignal
|
||||
merge:@[ [self pruneUpdateDirectories], [self truncateLogs] ]]
|
||||
|
||||
Reference in New Issue
Block a user