mac: remove standalone installer app
This change removes //chrome/installer/mac/app. This directory contained a cancelled project from 2016 to build a standalone installer and has never been shipped. Since its tests are broken on 10.14, we can just delete it rather than fixing those. Bug: 892172 Change-Id: Ib3d9e9c072a12e66cb7863a3e40eed8a13e948d6 Reviewed-on: https://chromium-review.googlesource.com/c/1315954 Reviewed-by: John Budorick <jbudorick@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Sidney San Martín <sdy@chromium.org> Commit-Queue: Elly Fong-Jones <ellyjones@chromium.org> Cr-Commit-Position: refs/heads/master@{#606514}
This commit is contained in:

committed by
Commit Bot

parent
2429b3291a
commit
351c48cef0
chrome/installer/mac
BUILD.gn
app
AppDelegate.hAppDelegate.mmAuthorizedInstall.hAuthorizedInstall.mBUILD.gnDownloader.hDownloader.mInfo.plistInstallerWindowController.hInstallerWindowController.mMainMenu.xibNSAlert+ChromeInstallerAdditions.hNSAlert+ChromeInstallerAdditions.mNSError+ChromeInstallerAdditions.hNSError+ChromeInstallerAdditions.mOWNERSOmahaCommunication.hOmahaCommunication.mOmahaXMLParser.hOmahaXMLParser.mOmahaXMLRequest.hOmahaXMLRequest.mREADME.mdSystemInfo.hSystemInfo.mUnpacker.hUnpacker.mcopy_to_disk.shmain.m
testing
testing/buildbot
@ -11,7 +11,6 @@ group("mac") {
|
||||
public_deps = [
|
||||
":copies",
|
||||
":make_signers",
|
||||
"app:mac_installer_app",
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_APPDELEGATE_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_APPDELEGATE_H_
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@interface AppDelegate : NSObject<NSApplicationDelegate>
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_APPDELEGATE_H_
|
@ -1,245 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#include <Security/Security.h>
|
||||
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
|
||||
#import "Downloader.h"
|
||||
#import "InstallerWindowController.h"
|
||||
#import "NSError+ChromeInstallerAdditions.h"
|
||||
#import "NSAlert+ChromeInstallerAdditions.h"
|
||||
#import "AuthorizedInstall.h"
|
||||
#import "OmahaCommunication.h"
|
||||
#import "Unpacker.h"
|
||||
|
||||
@interface NSAlert ()
|
||||
- (void)beginSheetModalForWindow:(NSWindow*)sheetWindow
|
||||
completionHandler:
|
||||
(void (^__nullable)(NSModalResponse returnCode))handler;
|
||||
@end
|
||||
|
||||
@interface AppDelegate ()<NSWindowDelegate,
|
||||
OmahaCommunicationDelegate,
|
||||
DownloaderDelegate,
|
||||
UnpackDelegate> {
|
||||
InstallerWindowController* installerWindowController_;
|
||||
AuthorizedInstall* authorizedInstall_;
|
||||
BOOL preventTermination_;
|
||||
}
|
||||
@property(strong) NSWindow* window;
|
||||
- (void)exit;
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
@synthesize window = window_;
|
||||
|
||||
// Sets up the main window and begins the downloading process.
|
||||
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
|
||||
// TODO: Despite what the code implies -- when the installer is run, the main
|
||||
// window of the application is not visible until the user has taken action on
|
||||
// the Authorization modal.
|
||||
window_.delegate = self;
|
||||
installerWindowController_ =
|
||||
[[InstallerWindowController alloc] initWithWindow:window_];
|
||||
authorizedInstall_ = [[AuthorizedInstall alloc] init];
|
||||
if ([authorizedInstall_ loadInstallationTool]) {
|
||||
[self startDownload];
|
||||
} else {
|
||||
[self onLoadInstallationToolFailure];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification*)aNotification {
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:
|
||||
(NSApplication*)sender {
|
||||
return preventTermination_ ? NSTerminateCancel : NSTerminateNow;
|
||||
}
|
||||
|
||||
// This function effectively takes the place of
|
||||
// applicationShouldTerminateAfterLastWindowClosed: to make sure that the
|
||||
// application does correctly terminate after closing the installer, but does
|
||||
// not terminate when we call orderOut: to hide the installer during its
|
||||
// tear-down steps. If the user quits the application, the below delegate
|
||||
// method gets called. However, when orderOut is called, the below delegate
|
||||
// method does not get called.
|
||||
- (BOOL)windowShouldClose:(id)sender {
|
||||
[self exit];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)exit {
|
||||
preventTermination_ = NO;
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
|
||||
- (void)startDownload {
|
||||
[installerWindowController_ updateStatusDescription:@"Initializing..."];
|
||||
|
||||
OmahaCommunication* omahaMessenger = [[OmahaCommunication alloc] init];
|
||||
omahaMessenger.delegate = self;
|
||||
[omahaMessenger fetchDownloadURLs];
|
||||
}
|
||||
|
||||
- (void)onLoadInstallationToolFailure {
|
||||
NSError* loadToolError = [NSError
|
||||
errorForAlerts:@"Internal Error"
|
||||
withDescription:
|
||||
@"Your Chrome Installer may be corrupted. Download and try again."
|
||||
isRecoverable:NO];
|
||||
[self displayError:loadToolError];
|
||||
}
|
||||
|
||||
- (void)omahaCommunication:(OmahaCommunication*)messenger
|
||||
onSuccess:(NSArray*)URLs {
|
||||
[installerWindowController_ updateStatusDescription:@"Downloading..."];
|
||||
|
||||
Downloader* download = [[Downloader alloc] init];
|
||||
download.delegate = self;
|
||||
[download downloadChromeImageFrom:[URLs firstObject]];
|
||||
}
|
||||
|
||||
- (void)omahaCommunication:(OmahaCommunication*)messenger
|
||||
onFailure:(NSError*)error {
|
||||
NSError* networkError =
|
||||
[NSError errorForAlerts:@"Network Error"
|
||||
withDescription:@"Could not connect to Chrome server."
|
||||
isRecoverable:YES];
|
||||
[self displayError:networkError];
|
||||
}
|
||||
|
||||
// Bridge method from Downloader to InstallerWindowController. Allows Downloader
|
||||
// to update the progressbar without having direct access to any UI obejcts.
|
||||
- (void)downloader:(Downloader*)download percentProgress:(double)percentage {
|
||||
[installerWindowController_ updateDownloadProgress:(double)percentage];
|
||||
}
|
||||
|
||||
- (void)downloader:(Downloader*)download onSuccess:(NSURL*)diskImageURL {
|
||||
[installerWindowController_ updateStatusDescription:@"Installing..."];
|
||||
[installerWindowController_ enableLaunchButton];
|
||||
|
||||
Unpacker* unpacker = [[Unpacker alloc] init];
|
||||
unpacker.delegate = self;
|
||||
[unpacker mountDMGFromURL:diskImageURL];
|
||||
}
|
||||
|
||||
- (void)downloader:(Downloader*)download onFailure:(NSError*)error {
|
||||
NSError* downloadError =
|
||||
[NSError errorForAlerts:@"Download Failure"
|
||||
withDescription:@"Unable to download Google Chrome."
|
||||
isRecoverable:NO];
|
||||
[self displayError:downloadError];
|
||||
}
|
||||
|
||||
- (void)unpacker:(Unpacker*)unpacker onMountSuccess:(NSString*)tempAppPath {
|
||||
SecStaticCodeRef diskStaticCode;
|
||||
SecRequirementRef diskRequirement;
|
||||
// TODO: Include some better error handling below than NSLog
|
||||
OSStatus oserror;
|
||||
oserror = SecStaticCodeCreateWithPath(
|
||||
(__bridge CFURLRef)[NSURL fileURLWithPath:tempAppPath isDirectory:NO],
|
||||
kSecCSDefaultFlags, &diskStaticCode);
|
||||
if (oserror != errSecSuccess)
|
||||
NSLog(@"code %d", oserror);
|
||||
// TODO: The below requirement is too general as most signed entities have the
|
||||
// below requirement; replace it with something adequately specific.
|
||||
oserror =
|
||||
SecRequirementCreateWithString((CFStringRef) @"anchor apple generic",
|
||||
kSecCSDefaultFlags, &diskRequirement);
|
||||
if (oserror != errSecSuccess)
|
||||
NSLog(@"requirement %d", oserror);
|
||||
oserror = SecStaticCodeCheckValidity(diskStaticCode, kSecCSDefaultFlags,
|
||||
diskRequirement);
|
||||
if (oserror != errSecSuccess)
|
||||
NSLog(@"static code %d", oserror);
|
||||
|
||||
// Calling this function will change the progress bar into an indeterminate
|
||||
// one. We won't need to update the progress bar any more after this point.
|
||||
[installerWindowController_ updateDownloadProgress:-1.0];
|
||||
// By disabling closing the window or quitting, we can tell the user that
|
||||
// closing the application at this point is not a good idea.
|
||||
window_.styleMask &= ~NSClosableWindowMask;
|
||||
preventTermination_ = YES;
|
||||
|
||||
NSString* chromeInApplicationsFolder =
|
||||
[authorizedInstall_ startInstall:tempAppPath];
|
||||
|
||||
NSMutableArray* installerSettings = [[NSMutableArray alloc] init];
|
||||
if ([installerWindowController_ isUserMetricsChecked])
|
||||
[installerSettings
|
||||
addObject:[NSString stringWithUTF8String:switches::kEnableUserMetrics]];
|
||||
if ([installerWindowController_ isDefaultBrowserChecked])
|
||||
[installerSettings
|
||||
addObject:[NSString
|
||||
// NOTE: the |kMakeDefaultBrowser| constant used as a
|
||||
// command-line switch here only will apply at a user
|
||||
// level, since the application itself is not running with
|
||||
// privileges. grt@ suggested this constant should be
|
||||
// renamed |kMakeDefaultBrowserforUser|.
|
||||
stringWithUTF8String:switches::kMakeDefaultBrowser]];
|
||||
|
||||
NSError* error = nil;
|
||||
[[NSWorkspace sharedWorkspace]
|
||||
launchApplicationAtURL:[NSURL fileURLWithPath:chromeInApplicationsFolder
|
||||
isDirectory:NO]
|
||||
options:NSWorkspaceLaunchDefault
|
||||
configuration:@{
|
||||
NSWorkspaceLaunchConfigurationArguments : installerSettings
|
||||
}
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Chrome failed to launch: %@", error);
|
||||
}
|
||||
|
||||
// Begin teardown step!
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[window_ orderOut:nil];
|
||||
});
|
||||
|
||||
[unpacker unmountDMG];
|
||||
}
|
||||
|
||||
- (void)unpacker:(Unpacker*)unpacker onMountFailure:(NSError*)error {
|
||||
NSError* extractError =
|
||||
[NSError errorForAlerts:@"Install Error"
|
||||
withDescription:@"Unable to add Google Chrome to Applications."
|
||||
isRecoverable:NO];
|
||||
[self displayError:extractError];
|
||||
}
|
||||
|
||||
- (void)unpacker:(Unpacker*)unpacker onUnmountSuccess:(NSString*)mountpath {
|
||||
NSLog(@"we're done here!");
|
||||
[self exit];
|
||||
}
|
||||
|
||||
- (void)unpacker:(Unpacker*)unpacker onUnmountFailure:(NSError*)error {
|
||||
NSLog(@"error unmounting");
|
||||
// NOTE: Since we are not deleting the temporary folder if the unmount fails,
|
||||
// we'll just leave it up to the computer to delete the temporary folder on
|
||||
// its own time and to unmount the disk during a restart at some point. There
|
||||
// is no other work to be done in the mean time.
|
||||
[self exit];
|
||||
}
|
||||
|
||||
// Displays an alert on the main window using the contents of the passed in
|
||||
// error.
|
||||
- (void)displayError:(NSError*)error {
|
||||
NSAlert* alertForUser = [NSAlert alertWithError:error];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[alertForUser beginSheetModalForWindow:window_
|
||||
completionHandler:^(NSModalResponse returnCode) {
|
||||
if (returnCode != [alertForUser quitResponse]) {
|
||||
[self startDownload];
|
||||
} else {
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
@ -1,23 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_AUTHORIZEDINSTALL_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_AUTHORIZEDINSTALL_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Security/Security.h>
|
||||
|
||||
@interface AuthorizedInstall : NSObject
|
||||
|
||||
// Attempts to gain elevated permissions, then starts the subprocess with the
|
||||
// appropriate level of privilege.
|
||||
- (BOOL)loadInstallationTool;
|
||||
|
||||
// Signals the tool to begin the installation. Returns the path to the
|
||||
// installed app.
|
||||
- (NSString*)startInstall:(NSString*)appBundlePath;
|
||||
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_AUTHORIZEDINSTALL_H_
|
@ -1,131 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "AuthorizedInstall.h"
|
||||
|
||||
@interface AuthorizedInstall () {
|
||||
NSFileHandle* communicationFile_;
|
||||
NSString* destinationAppBundlePath_;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation AuthorizedInstall
|
||||
// Does the setup needed to authorize a subprocess to run as root.
|
||||
- (OSStatus)setUpAuthorization:(AuthorizationRef*)authRef {
|
||||
OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
|
||||
kAuthorizationFlagDefaults, authRef);
|
||||
|
||||
AuthorizationItem items = {kAuthorizationRightExecute, 0, NULL, 0};
|
||||
AuthorizationRights rights = {1, &items};
|
||||
AuthorizationFlags flags =
|
||||
kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed |
|
||||
kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
|
||||
|
||||
status = AuthorizationCopyRights(*authRef, &rights, NULL, flags, NULL);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Starts up the proccess with privileged permissions.
|
||||
- (void)startPrivilegedTool:(const char*)toolPath
|
||||
withArguments:(const char**)args
|
||||
authorization:(AuthorizationRef)authRef
|
||||
status:(OSStatus)status {
|
||||
if (status != errAuthorizationSuccess)
|
||||
return;
|
||||
|
||||
FILE* file;
|
||||
// AuthorizationExecuteWithPrivileges is deprecated in macOS 10.7, but no good
|
||||
// replacement exists. https://crbug.com/593133.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
status = AuthorizationExecuteWithPrivileges(
|
||||
authRef, toolPath, kAuthorizationFlagDefaults, (char* const*)args, &file);
|
||||
#pragma clang diagnostic pop
|
||||
communicationFile_ = [[NSFileHandle alloc] initWithFileDescriptor:fileno(file)
|
||||
closeOnDealloc:YES];
|
||||
}
|
||||
|
||||
// Starts up same proccess as above without privileged permissions.
|
||||
- (void)startUnprivilegedTool:(NSString*)toolPath withArguments:(NSArray*)args {
|
||||
NSPipe* pipe = [NSPipe pipe];
|
||||
NSTask* task = [[NSTask alloc] init];
|
||||
[task setArguments:args];
|
||||
[task setLaunchPath:toolPath];
|
||||
[task setStandardInput:pipe];
|
||||
[task launch];
|
||||
communicationFile_ = [pipe fileHandleForWriting];
|
||||
}
|
||||
|
||||
// Determines which "Applications" folder to use based on authorization.
|
||||
// There are three possible scenarios and two possible return values.
|
||||
// 1) /Applications is returned if:
|
||||
// a) The user authenticates the app.
|
||||
// b) The user doesn't authenticate but is an admin.
|
||||
// 2) $HOME/Applications is returned if:
|
||||
// c) The user doesn't authenticate and is not an admin.
|
||||
- (NSString*)getApplicationsFolder:(BOOL)isAuthorized {
|
||||
NSFileManager* manager = [NSFileManager defaultManager];
|
||||
NSArray* applicationDirectories = NSSearchPathForDirectoriesInDomains(
|
||||
NSApplicationDirectory, NSLocalDomainMask, YES);
|
||||
if (isAuthorized ||
|
||||
[manager isWritableFileAtPath:applicationDirectories.firstObject]) {
|
||||
return applicationDirectories.firstObject;
|
||||
} else {
|
||||
NSString* usersApplicationsDirectory =
|
||||
[NSString pathWithComponents:@[ NSHomeDirectory(), @"Applications" ]];
|
||||
if (![manager fileExistsAtPath:usersApplicationsDirectory]) {
|
||||
[manager createDirectoryAtPath:usersApplicationsDirectory
|
||||
withIntermediateDirectories:NO
|
||||
attributes:nil
|
||||
error:nil];
|
||||
}
|
||||
return usersApplicationsDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)loadInstallationTool {
|
||||
AuthorizationRef authRef = NULL;
|
||||
OSStatus status = [self setUpAuthorization:&authRef];
|
||||
BOOL isAuthorized = (status == errAuthorizationSuccess);
|
||||
|
||||
NSString* toolPath =
|
||||
[[NSBundle mainBundle] pathForResource:@"copy_to_disk" ofType:@"sh"];
|
||||
NSFileManager* manager = [NSFileManager defaultManager];
|
||||
if (![manager fileExistsAtPath:toolPath]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NSString* applicationsDirectory = [self getApplicationsFolder:isAuthorized];
|
||||
destinationAppBundlePath_ = [NSString pathWithComponents: @[
|
||||
applicationsDirectory, @"Google Chrome.app"]];
|
||||
|
||||
if (isAuthorized) {
|
||||
const char* args[] = {[applicationsDirectory UTF8String], NULL};
|
||||
[self startPrivilegedTool:[toolPath UTF8String]
|
||||
withArguments:args
|
||||
authorization:authRef
|
||||
status:status];
|
||||
} else {
|
||||
NSArray* args = @[ applicationsDirectory ];
|
||||
[self startUnprivilegedTool:toolPath withArguments:args];
|
||||
}
|
||||
|
||||
AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sends a message to the tool's stdin. The tool is using 'read' to wait for
|
||||
// input. 'read' adds to its buffer until it receives a newline to continue so
|
||||
// append '\n' to the message to end the read.
|
||||
- (void)sendMessageToTool:(NSString*)message {
|
||||
[communicationFile_ writeData:[[message stringByAppendingString:@"\n"]
|
||||
dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
|
||||
- (NSString*)startInstall:(NSString*)appBundlePath {
|
||||
[self sendMessageToTool:appBundlePath];
|
||||
return destinationAppBundlePath_;
|
||||
}
|
||||
|
||||
@end
|
@ -1,102 +0,0 @@
|
||||
# Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/mac/rules.gni")
|
||||
import("//build/util/branding.gni")
|
||||
import("//testing/test.gni")
|
||||
|
||||
source_set("mac_installer_base") {
|
||||
visibility = [ ":*" ]
|
||||
sources = [
|
||||
"Downloader.h",
|
||||
"Downloader.m",
|
||||
"NSAlert+ChromeInstallerAdditions.h",
|
||||
"NSAlert+ChromeInstallerAdditions.m",
|
||||
"NSError+ChromeInstallerAdditions.h",
|
||||
"NSError+ChromeInstallerAdditions.m",
|
||||
"OmahaCommunication.h",
|
||||
"OmahaCommunication.m",
|
||||
"OmahaXMLParser.h",
|
||||
"OmahaXMLParser.m",
|
||||
"OmahaXMLRequest.h",
|
||||
"OmahaXMLRequest.m",
|
||||
"SystemInfo.h",
|
||||
"SystemInfo.m",
|
||||
"Unpacker.h",
|
||||
"Unpacker.m",
|
||||
]
|
||||
public_configs = [ "//build/config/compiler:enable_arc" ]
|
||||
}
|
||||
|
||||
mac_app_bundle("mac_installer_app") {
|
||||
output_name = "$chrome_product_installer_full_name"
|
||||
info_plist = "Info.plist"
|
||||
extra_substitutions = [
|
||||
"PRODUCT_INSTALLER_FULLNAME=$chrome_product_installer_full_name",
|
||||
"CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
|
||||
]
|
||||
sources = [
|
||||
"AppDelegate.h",
|
||||
"AppDelegate.mm",
|
||||
"AuthorizedInstall.h",
|
||||
"AuthorizedInstall.m",
|
||||
"InstallerWindowController.h",
|
||||
"InstallerWindowController.m",
|
||||
"main.m",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":mac_installer_base",
|
||||
":mac_installer_resources",
|
||||
":mac_installer_xibs",
|
||||
"//chrome/common:constants",
|
||||
]
|
||||
|
||||
libs = [
|
||||
"Cocoa.framework",
|
||||
"DiskArbitration.framework",
|
||||
"Security.framework",
|
||||
]
|
||||
}
|
||||
|
||||
mac_xib_bundle_data("mac_installer_xibs") {
|
||||
sources = [
|
||||
"MainMenu.xib",
|
||||
]
|
||||
}
|
||||
|
||||
bundle_data("mac_installer_resources") {
|
||||
sources = [
|
||||
"copy_to_disk.sh",
|
||||
]
|
||||
outputs = [
|
||||
"{{bundle_resources_dir}}/copy_to_disk.sh",
|
||||
]
|
||||
}
|
||||
|
||||
test("mac_installer_unittests") {
|
||||
sources = [
|
||||
"testing/OmahaXMLRequest_test.mm",
|
||||
"testing/SystemInfo_test.mm",
|
||||
"testing/Unpacker_test.mm",
|
||||
]
|
||||
deps = [
|
||||
":mac_installer_base",
|
||||
"//base:base",
|
||||
"//base/test:run_all_unittests",
|
||||
"//chrome/common:constants",
|
||||
"//testing/gtest:gtest",
|
||||
]
|
||||
libs = [
|
||||
"Cocoa.framework",
|
||||
"DiskArbitration.framework",
|
||||
"Security.framework",
|
||||
]
|
||||
data = [
|
||||
"//chrome/test/data/mac_installer/requestCheck.dtd",
|
||||
"//chrome/test/data/mac_installer/requestSample.xml",
|
||||
"//chrome/test/data/mac_installer/responseExample.xml",
|
||||
"//chrome/test/data/mac_installer/test-dmg.dmg",
|
||||
]
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_DOWNLOADER_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_DOWNLOADER_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Downloader;
|
||||
@protocol DownloaderDelegate
|
||||
- (void)downloader:(Downloader*)download percentProgress:(double)percentage;
|
||||
- (void)downloader:(Downloader*)download onSuccess:(NSURL*)diskImageURL;
|
||||
- (void)downloader:(Downloader*)download onFailure:(NSError*)error;
|
||||
@end
|
||||
|
||||
@interface Downloader : NSObject<NSURLSessionDownloadDelegate>
|
||||
|
||||
@property(nonatomic, assign) id<DownloaderDelegate> delegate;
|
||||
|
||||
// Downloads Chrome from |chromeImageURL| to the local hard drive.
|
||||
- (void)downloadChromeImageFrom:(NSURL*)chromeImageURL;
|
||||
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_DOWNLOADER_H_
|
@ -1,51 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "Downloader.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@implementation Downloader
|
||||
|
||||
@synthesize delegate = delegate_;
|
||||
|
||||
// Downloads contents of chromeURL to downloads folders and delegates the work
|
||||
// to the DownloadDelegate class.
|
||||
- (void)downloadChromeImageFrom:(NSURL*)chromeImageURL {
|
||||
NSURLSession* session =
|
||||
[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration
|
||||
defaultSessionConfiguration]
|
||||
delegate:self
|
||||
delegateQueue:nil];
|
||||
[[session downloadTaskWithURL:chromeImageURL] resume];
|
||||
[session finishTasksAndInvalidate];
|
||||
}
|
||||
|
||||
// Provides updates to download progress.
|
||||
- (void)URLSession:(NSURLSession*)session
|
||||
downloadTask:(NSURLSessionDownloadTask*)downloadTask
|
||||
didWriteData:(int64_t)bytesWritten
|
||||
totalBytesWritten:(int64_t)totalBytesWritten
|
||||
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
|
||||
double downloadProgressPercentage =
|
||||
(double)totalBytesWritten / totalBytesExpectedToWrite * 100.0;
|
||||
[delegate_ downloader:self percentProgress:downloadProgressPercentage];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession*)session
|
||||
downloadTask:(NSURLSessionDownloadTask*)downloadTask
|
||||
didFinishDownloadingToURL:(NSURL*)location {
|
||||
assert([location isFileURL]);
|
||||
[delegate_ downloader:self onSuccess:location];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession*)session
|
||||
task:(NSURLSessionTask*)task
|
||||
didCompleteWithError:(NSError*)error {
|
||||
if (error) {
|
||||
[delegate_ downloader:self onFailure:error];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${CHROMIUM_BUNDLE_ID}.installer</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_INSTALLER_FULLNAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${CHROMIUM_MIN_SYSTEM_VERSION}</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016 Google. All rights reserved.</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>google.com</key>
|
||||
<dict>
|
||||
<key>NSIncludesSubdomains</key>
|
||||
<true/>
|
||||
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>gvt1.com</key>
|
||||
<dict>
|
||||
<key>NSIncludesSubdomains</key>
|
||||
<true/>
|
||||
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -1,21 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_INSTALLERWINDOWCONTROLLER_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_INSTALLERWINDOWCONTROLLER_H_
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@interface InstallerWindowController : NSWindowController
|
||||
|
||||
- (id)initWithWindow:(NSWindow*)window;
|
||||
- (void)updateStatusDescription:(NSString*)text;
|
||||
- (void)updateDownloadProgress:(double)progressPercent;
|
||||
- (void)enableLaunchButton;
|
||||
|
||||
- (BOOL)isUserMetricsChecked;
|
||||
- (BOOL)isDefaultBrowserChecked;
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_INSTALLERWINDOWCONTROLLER_H_
|
@ -1,150 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "InstallerWindowController.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@interface InstallerWindowController () {
|
||||
NSButton* importButton_;
|
||||
NSButton* defaultBrowserButton_;
|
||||
NSButton* optInButton_;
|
||||
NSButton* launchButton_;
|
||||
NSTextField* statusDescription_;
|
||||
NSTextField* downloadProgressDescription_;
|
||||
NSProgressIndicator* progressBar_;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation InstallerWindowController
|
||||
|
||||
// Simplify styling and naming buttons.
|
||||
- (void)stylizeButton:(NSButton*)button withTitle:(NSString*)title {
|
||||
button.buttonType = NSSwitchButton;
|
||||
button.bezelStyle = NSRoundedBezelStyle;
|
||||
button.title = title;
|
||||
}
|
||||
|
||||
// Positions and stylizes buttons.
|
||||
- (void)setUpButtons {
|
||||
importButton_ = [[NSButton alloc] initWithFrame:NSMakeRect(30, 20, 300, 25)];
|
||||
[self stylizeButton:importButton_
|
||||
withTitle:@"Import from... Wait import what?"];
|
||||
|
||||
defaultBrowserButton_.state = NSOnState;
|
||||
defaultBrowserButton_ =
|
||||
[[NSButton alloc] initWithFrame:NSMakeRect(30, 45, 300, 25)];
|
||||
[self stylizeButton:defaultBrowserButton_
|
||||
withTitle:@"Make Chrome the default browser."];
|
||||
|
||||
optInButton_ = [[NSButton alloc] initWithFrame:NSMakeRect(30, 70, 300, 25)];
|
||||
[self stylizeButton:optInButton_ withTitle:@"Say yes to UMA."];
|
||||
|
||||
launchButton_ = [[NSButton alloc] initWithFrame:NSMakeRect(310, 6, 100, 50)];
|
||||
launchButton_.buttonType = NSPushOnPushOffButton;
|
||||
launchButton_.bezelStyle = NSRoundedBezelStyle;
|
||||
launchButton_.title = @"Launch";
|
||||
[launchButton_ setEnabled:NO];
|
||||
[launchButton_ setAction:@selector(launchButtonClicked)];
|
||||
}
|
||||
|
||||
// Simplfy styling NSTextField objects.
|
||||
- (void)stylizeTextField:(NSTextField*)textField
|
||||
withDescription:(NSString*)description {
|
||||
textField.backgroundColor = NSColor.clearColor;
|
||||
textField.textColor = NSColor.blackColor;
|
||||
textField.stringValue = description;
|
||||
textField.bezeled = NO;
|
||||
textField.editable = NO;
|
||||
}
|
||||
|
||||
// Positions and stylizes textfields.
|
||||
- (void)setUpTextfields {
|
||||
statusDescription_ =
|
||||
[[NSTextField alloc] initWithFrame:NSMakeRect(20, 95, 300, 20)];
|
||||
[self stylizeTextField:statusDescription_
|
||||
withDescription:@"Working on it! While you're waiting..."];
|
||||
|
||||
downloadProgressDescription_ =
|
||||
[[NSTextField alloc] initWithFrame:NSMakeRect(20, 160, 300, 20)];
|
||||
[self stylizeTextField:downloadProgressDescription_
|
||||
withDescription:@"Downloading... "];
|
||||
}
|
||||
|
||||
// Positions and stylizes the progressbar for download and install.
|
||||
- (void)setUpProgressBar {
|
||||
progressBar_ =
|
||||
[[NSProgressIndicator alloc] initWithFrame:NSMakeRect(15, 125, 400, 50)];
|
||||
progressBar_.indeterminate = NO;
|
||||
progressBar_.style = NSProgressIndicatorBarStyle;
|
||||
progressBar_.maxValue = 100.0;
|
||||
progressBar_.minValue = 0.0;
|
||||
progressBar_.doubleValue = 0.0;
|
||||
}
|
||||
|
||||
// Positions the main window and adds the rest of the UI elements to it.
|
||||
// Prevents resizing the window so that the absolute position will look the same
|
||||
// on all computers. Window is hidden until all positioning is finished.
|
||||
- (id)initWithWindow:(NSWindow*)window {
|
||||
if (self = [super initWithWindow:window]) {
|
||||
[window setFrame:NSMakeRect(0, 0, 430, 220) display:YES];
|
||||
[window center];
|
||||
[window setStyleMask:[window styleMask] & ~NSResizableWindowMask];
|
||||
|
||||
[self setUpButtons];
|
||||
[self setUpProgressBar];
|
||||
[self setUpTextfields];
|
||||
|
||||
[window.contentView addSubview:importButton_];
|
||||
[window.contentView addSubview:defaultBrowserButton_];
|
||||
[window.contentView addSubview:optInButton_];
|
||||
[window.contentView addSubview:launchButton_];
|
||||
[window.contentView addSubview:progressBar_];
|
||||
[window.contentView addSubview:statusDescription_];
|
||||
[window.contentView addSubview:downloadProgressDescription_];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
[window makeKeyAndOrderFront:self];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateStatusDescription:(NSString*)text {
|
||||
// TODO: This method somehow causes ghosting of the previous string's contents
|
||||
// after a redraw. The below line of code is a temporary hack to clear the
|
||||
// ghosting behavior, but it should be replaced with a legitimate bug fix.
|
||||
downloadProgressDescription_.stringValue = @"";
|
||||
downloadProgressDescription_.stringValue = text;
|
||||
}
|
||||
|
||||
- (void)updateDownloadProgress:(double)progressPercent {
|
||||
if (progressPercent > 0.0) {
|
||||
progressBar_.doubleValue = progressPercent;
|
||||
} else {
|
||||
// After the progress bar is made indeterminate, it will not need to track
|
||||
// determinate progress any more. Therefore, there is nothing implemented to
|
||||
// set indeterminate to NO.
|
||||
progressBar_.doubleValue = 0.0;
|
||||
progressBar_.indeterminate = YES;
|
||||
[progressBar_ startAnimation:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)enableLaunchButton {
|
||||
[launchButton_ setEnabled:YES];
|
||||
}
|
||||
|
||||
- (void)launchButtonClicked {
|
||||
// TODO: Launch the app and start ejecting disk.
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
|
||||
- (BOOL)isUserMetricsChecked {
|
||||
return optInButton_.state == NSOnState;
|
||||
}
|
||||
|
||||
- (BOOL)isDefaultBrowserChecked {
|
||||
return defaultBrowserButton_.state == NSOnState;
|
||||
}
|
||||
|
||||
@end
|
@ -1,294 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate">
|
||||
<connections>
|
||||
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||
<items>
|
||||
<menuItem title="Google Chrome Installer" id="1Xt-HY-uBw">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Google Chrome Installer" systemMenu="apple" id="uQy-DD-JDr">
|
||||
<items>
|
||||
<menuItem title="Services" id="NMo-om-nkz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||
<menuItem title="Hide Google Chrome Installer" keyEquivalent="h" id="Olw-nP-bQN">
|
||||
<connections>
|
||||
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||
<menuItem title="Quit Google Chrome Installer" keyEquivalent="q" id="4sb-4s-VLi">
|
||||
<connections>
|
||||
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="File" id="dMs-cI-mzQ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="File" id="bib-Uj-vzu">
|
||||
<items>
|
||||
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
|
||||
<connections>
|
||||
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
||||
<items>
|
||||
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
|
||||
<connections>
|
||||
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
|
||||
<connections>
|
||||
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
|
||||
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
|
||||
<connections>
|
||||
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
|
||||
<connections>
|
||||
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
|
||||
<connections>
|
||||
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Delete" id="pa3-QI-u2k">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
||||
<connections>
|
||||
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
|
||||
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
|
||||
<items>
|
||||
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
|
||||
<connections>
|
||||
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
|
||||
<connections>
|
||||
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
|
||||
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Substitutions" id="9ic-FL-obx">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
|
||||
<items>
|
||||
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
|
||||
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Links" id="cwL-P1-jid">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Data Detectors" id="tRr-pd-1PS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Transformations" id="2oI-Rn-ZJC">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
|
||||
<items>
|
||||
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Speech" id="xrE-MZ-jX0">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
|
||||
<items>
|
||||
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="aUF-d1-5bR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||
<items>
|
||||
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
|
||||
<connections>
|
||||
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Zoom" id="R4o-n2-Eq4">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="wpr-3q-Mcd">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
|
||||
<items>
|
||||
<menuItem title="Google Chrome Installer Help" keyEquivalent="?" id="FKE-Sm-Kum">
|
||||
<connections>
|
||||
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<window title="Google Chrome Installer" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="480" height="360"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/>
|
||||
<view key="contentView" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="430" height="220"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_NSALERT_CHROMEINSTALLERADDITIONS_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_NSALERT_CHROMEINSTALLERADDITIONS_H_
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
typedef NSInteger NSModalResponse;
|
||||
@interface NSAlert (ChromeInstallerAdditions)
|
||||
// Allows the caller to determine whether to determine the app's quit button was
|
||||
// pressed or not.
|
||||
- (NSModalResponse)quitResponse;
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_NSALERT_CHROMEINSTALLERADDITIONS_H_
|
@ -1,15 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "NSAlert+ChromeInstallerAdditions.h"
|
||||
|
||||
@implementation NSAlert (ChromeInstallerAdditions)
|
||||
// In the one-button scenario, the button would be just "Quit." In the
|
||||
// two-button scenario, the first button would allow the user to "Retry" and
|
||||
// the second button would provide the "Quit" option.
|
||||
- (NSModalResponse)quitResponse {
|
||||
return ([[self buttons] count] == 1) ? NSAlertFirstButtonReturn
|
||||
: NSAlertSecondButtonReturn;
|
||||
}
|
||||
@end
|
@ -1,18 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_NSERROR_CHROMEINSTALLERADDITIONS_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_NSERROR_CHROMEINSTALLERADDITIONS_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSError (ChromeInstallerAdditions)
|
||||
// Creates a custom error object to be used to create an alert to be shown to
|
||||
// the user.
|
||||
+ (NSError*)errorForAlerts:(NSString*)message
|
||||
withDescription:(NSString*)description
|
||||
isRecoverable:(BOOL)recoverable;
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_NSERROR_CHROMEINSTALLERADDITIONS_H_
|
@ -1,27 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "NSError+ChromeInstallerAdditions.h"
|
||||
|
||||
@implementation NSError (ChromeInstallerAdditions)
|
||||
+ (NSError*)errorForAlerts:(NSString*)message
|
||||
withDescription:(NSString*)description
|
||||
isRecoverable:(BOOL)recoverable {
|
||||
NSArray* options = @[];
|
||||
if (recoverable) {
|
||||
options = @[ @"Try Again", @"Quit" ];
|
||||
} else {
|
||||
options = @[ @"Quit" ];
|
||||
}
|
||||
|
||||
NSDictionary* errorContents = @{
|
||||
NSLocalizedDescriptionKey : NSLocalizedString(message, nil),
|
||||
NSLocalizedRecoveryOptionsErrorKey : options,
|
||||
NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString(description, nil)
|
||||
};
|
||||
return [NSError errorWithDomain:@"ChromeErrorDomain"
|
||||
code:-1
|
||||
userInfo:errorContents];
|
||||
}
|
||||
@end
|
@ -1,6 +0,0 @@
|
||||
ellyjones@chromium.org
|
||||
ivanhernandez@google.com
|
||||
mark@chromium.org
|
||||
zengster@google.com
|
||||
|
||||
# COMPONENT: Internals>Installer
|
@ -1,31 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_OMAHACOMMUNICATION_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_OMAHACOMMUNICATION_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class OmahaCommunication;
|
||||
@protocol OmahaCommunicationDelegate
|
||||
- (void)omahaCommunication:(OmahaCommunication*)messenger
|
||||
onSuccess:(NSArray*)URLs;
|
||||
- (void)omahaCommunication:(OmahaCommunication*)messenger
|
||||
onFailure:(NSError*)error;
|
||||
@end
|
||||
|
||||
@interface OmahaCommunication : NSObject<NSURLSessionDataDelegate>
|
||||
|
||||
@property(nonatomic, copy) NSXMLDocument* requestXMLBody;
|
||||
@property(nonatomic, assign) id<OmahaCommunicationDelegate> delegate;
|
||||
|
||||
- (id)init;
|
||||
- (id)initWithBody:(NSXMLDocument*)xmlBody;
|
||||
|
||||
// Asks the Omaha servers for the most updated version of Chrome.
|
||||
- (void)fetchDownloadURLs;
|
||||
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_OMAHACOMMUNICATION_H_
|
@ -1,68 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "OmahaCommunication.h"
|
||||
|
||||
#import "OmahaXMLRequest.h"
|
||||
#import "OmahaXMLParser.h"
|
||||
|
||||
// TODO: Turn the below string into a command line flag for testing.
|
||||
static NSString* const omahaURLPath =
|
||||
@"https://tools.google.com/service/update2";
|
||||
|
||||
@interface NSURLSession ()
|
||||
- (NSURLSessionDataTask*)dataTaskWithRequest:(NSURLRequest*)request
|
||||
completionHandler:
|
||||
(void (^)(NSData* data,
|
||||
NSURLResponse* response,
|
||||
NSError* error))completionHandler;
|
||||
@end
|
||||
|
||||
@implementation OmahaCommunication
|
||||
|
||||
@synthesize requestXMLBody = requestXMLBody_;
|
||||
@synthesize delegate = delegate_;
|
||||
|
||||
- (id)init {
|
||||
return [self initWithBody:[OmahaXMLRequest createXMLRequestBody]];
|
||||
}
|
||||
|
||||
- (id)initWithBody:(NSXMLDocument*)xmlBody {
|
||||
if ((self = [super init])) {
|
||||
requestXMLBody_ = xmlBody;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)fetchDownloadURLs {
|
||||
// Forming the request
|
||||
NSURL* requestURL = [NSURL URLWithString:omahaURLPath];
|
||||
NSMutableURLRequest* request =
|
||||
[NSMutableURLRequest requestWithURL:requestURL];
|
||||
[request addValue:@"text/xml" forHTTPHeaderField:@"Content-Type"];
|
||||
NSData* requestBody =
|
||||
[[requestXMLBody_ XMLString] dataUsingEncoding:NSUTF8StringEncoding];
|
||||
request.HTTPBody = requestBody;
|
||||
request.HTTPMethod = @"POST";
|
||||
// Sending the request
|
||||
[[[NSURLSession sharedSession]
|
||||
dataTaskWithRequest:request
|
||||
completionHandler:^(NSData* data, NSURLResponse* response,
|
||||
NSError* error) {
|
||||
NSArray* completeURLs = nil;
|
||||
if (!error) {
|
||||
completeURLs = [OmahaXMLParser parseXML:data error:&error];
|
||||
}
|
||||
// Deals with errors both from the network error and the
|
||||
// parsing error, as the user only needs to know there was a problem
|
||||
// talking with the Google Update server.
|
||||
if (error) {
|
||||
[delegate_ omahaCommunication:self onFailure:error];
|
||||
} else {
|
||||
[delegate_ omahaCommunication:self onSuccess:completeURLs];
|
||||
}
|
||||
}] resume];
|
||||
}
|
||||
|
||||
@end
|
@ -1,19 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_OMAHAXMLPARSER_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_OMAHAXMLPARSER_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface OmahaXMLParser : NSObject
|
||||
|
||||
// Parses the XML body from Omaha's HTTP response and extracts the URLs and name
|
||||
// of the Chrome disk image. Then, returns an array with all the URLs
|
||||
// concatenated with the filename.
|
||||
+ (NSArray*)parseXML:(NSData*)omahaResponseXML error:(NSError**)error;
|
||||
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_OMAHAXMLPARSER_H_
|
@ -1,78 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "OmahaXMLParser.h"
|
||||
|
||||
@interface OmahaXMLParser ()<NSXMLParserDelegate>
|
||||
@end
|
||||
|
||||
@implementation OmahaXMLParser {
|
||||
NSMutableArray* chromeIncompleteDownloadURLs_;
|
||||
NSString* chromeImageFilename_;
|
||||
}
|
||||
|
||||
// Sets up instance of NSXMLParser and calls on delegate methods to do actual
|
||||
// parsing work.
|
||||
+ (NSArray*)parseXML:(NSData*)omahaResponseXML error:(NSError**)error {
|
||||
NSXMLParser* parser = [[NSXMLParser alloc] initWithData:omahaResponseXML];
|
||||
|
||||
OmahaXMLParser* omahaParser = [[OmahaXMLParser alloc] init];
|
||||
[parser setDelegate:omahaParser];
|
||||
if (![parser parse]) {
|
||||
*error = [parser parserError];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray* completeDownloadURLs = [[NSMutableArray alloc] init];
|
||||
for (NSString* URL in omahaParser->chromeIncompleteDownloadURLs_) {
|
||||
[completeDownloadURLs
|
||||
addObject:[NSURL URLWithString:omahaParser->chromeImageFilename_
|
||||
relativeToURL:[NSURL URLWithString:URL]]];
|
||||
}
|
||||
|
||||
if ([completeDownloadURLs count] < 1) {
|
||||
// TODO: The below error exists only so the caller of this method would
|
||||
// catch the error created here. A better way to handle this is to make the
|
||||
// error's contents inform what the installer will try next when it attempts
|
||||
// to recover from an issue.
|
||||
*error = [NSError errorWithDomain:@"ChromeErrorDomain" code:1 userInfo:nil];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return completeDownloadURLs;
|
||||
}
|
||||
|
||||
// Searches the XML data for the tag "URL" and the subsequent "codebase"
|
||||
// attribute that indicates a URL follows. Copies each URL into an array.
|
||||
// NOTE: The URLs in the XML file are incomplete. They need the filename
|
||||
// appended to end. The second if statement checks for the tag "package" which
|
||||
// contains the filename needed to complete the URLs.
|
||||
- (void)parser:(NSXMLParser*)parser
|
||||
didStartElement:(NSString*)elementName
|
||||
namespaceURI:(NSString*)namespaceURI
|
||||
qualifiedName:(NSString*)qName
|
||||
attributes:(NSDictionary*)attributeDict {
|
||||
if ([elementName isEqualToString:@"url"]) {
|
||||
if (!chromeIncompleteDownloadURLs_) {
|
||||
chromeIncompleteDownloadURLs_ = [[NSMutableArray alloc] init];
|
||||
}
|
||||
NSString* extractedURL = [attributeDict objectForKey:@"codebase"];
|
||||
[chromeIncompleteDownloadURLs_ addObject:extractedURL];
|
||||
}
|
||||
if ([elementName isEqualToString:@"package"]) {
|
||||
chromeImageFilename_ =
|
||||
[[NSString alloc] initWithString:[attributeDict objectForKey:@"name"]];
|
||||
}
|
||||
}
|
||||
|
||||
// If either component of the URL is empty then the complete URL cannot
|
||||
// be generated so both variables are set to nil to flag errors.
|
||||
- (void)parserDidEndDocument:(NSXMLParser*)parser {
|
||||
if (!chromeIncompleteDownloadURLs_ || !chromeImageFilename_) {
|
||||
chromeIncompleteDownloadURLs_ = nil;
|
||||
chromeImageFilename_ = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_OMAHAXMLREQUEST_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_OMAHAXMLREQUEST_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface OmahaXMLRequest : NSObject
|
||||
|
||||
// Creates the body of the request being prepared to send to Omaha.
|
||||
+ (NSXMLDocument*)createXMLRequestBody;
|
||||
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_OMAHAXMLREQUEST_H_
|
@ -1,73 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "OmahaXMLRequest.h"
|
||||
|
||||
#include "SystemInfo.h"
|
||||
|
||||
@implementation OmahaXMLRequest : NSObject
|
||||
|
||||
+ (NSXMLElement*)createElementWithName:(NSString*)name {
|
||||
return [[NSXMLElement alloc] initWithName:name];
|
||||
}
|
||||
|
||||
+ (void)forElement:(NSXMLElement*)element
|
||||
AddAttribute:(NSString*)attribute
|
||||
WithValue:(NSString*)value {
|
||||
[element
|
||||
addAttribute:[NSXMLNode attributeWithName:attribute stringValue:value]];
|
||||
}
|
||||
|
||||
// borisv@ indicated that the OS version, platform, appid, and version are the
|
||||
// user attributes that Omaha actually looks at. The other parameters are useful
|
||||
// for logging purposes but otherwise not directly used.
|
||||
+ (NSXMLDocument*)createXMLRequestBody {
|
||||
// TODO: This protocol version number probably shouldn't be hard-coded. Check
|
||||
// with borisv@ regarding changing protocol verions.
|
||||
NSString* protocol = @"3.0";
|
||||
|
||||
NSString* platform = @"mac";
|
||||
NSString* operatingSystem = [SystemInfo getOSVersion];
|
||||
NSString* architecture = [SystemInfo getArch];
|
||||
NSString* plat_arch =
|
||||
[NSString stringWithFormat:@"%@_%@", operatingSystem, architecture];
|
||||
|
||||
NSString* appid = @"com.google.Chrome";
|
||||
NSString* version = @"0.0.0.0";
|
||||
NSString* language = @"en-us";
|
||||
|
||||
NSXMLElement* root = [OmahaXMLRequest createElementWithName:@"request"];
|
||||
[OmahaXMLRequest forElement:root AddAttribute:@"protocol" WithValue:protocol];
|
||||
|
||||
NSXMLElement* osChild = [OmahaXMLRequest createElementWithName:@"os"];
|
||||
[OmahaXMLRequest forElement:osChild
|
||||
AddAttribute:@"platform"
|
||||
WithValue:platform];
|
||||
[OmahaXMLRequest forElement:osChild
|
||||
AddAttribute:@"version"
|
||||
WithValue:operatingSystem];
|
||||
[OmahaXMLRequest forElement:osChild
|
||||
AddAttribute:@"arch"
|
||||
WithValue:architecture];
|
||||
[OmahaXMLRequest forElement:osChild AddAttribute:@"sp" WithValue:plat_arch];
|
||||
[root addChild:osChild];
|
||||
|
||||
NSXMLElement* appChild = [OmahaXMLRequest createElementWithName:@"app"];
|
||||
[OmahaXMLRequest forElement:appChild AddAttribute:@"appid" WithValue:appid];
|
||||
[OmahaXMLRequest forElement:appChild
|
||||
AddAttribute:@"version"
|
||||
WithValue:version];
|
||||
[OmahaXMLRequest forElement:appChild AddAttribute:@"lang" WithValue:language];
|
||||
[root addChild:appChild];
|
||||
|
||||
NSXMLElement* updateChildChild =
|
||||
[OmahaXMLRequest createElementWithName:@"updatecheck"];
|
||||
[appChild addChild:updateChildChild];
|
||||
|
||||
NSXMLDocument* requestXMLDocument =
|
||||
[[NSXMLDocument alloc] initWithRootElement:root];
|
||||
return requestXMLDocument;
|
||||
}
|
||||
|
||||
@end
|
@ -1,177 +0,0 @@
|
||||
# Chrome Installer for Mac -- the repository!
|
||||
|
||||
This Mac app installs Chrome on the machine it's run on. It's meant to be the
|
||||
Mac app the user first downloads when they click 'Download Chrome' on a Mac
|
||||
machine. After the user runs the app, Chrome would launch directly after
|
||||
installation completes successfully.
|
||||
|
||||
## The 10,000 Foot View
|
||||
|
||||
The installer breaks down its task into the following steps:
|
||||
|
||||
1. __OmahaCommunication__: Ask Omaha for a URL of the most recent compatible
|
||||
copy of the Google Chrome disk image in Google's servers.
|
||||
2. __Downloader__: Download the disk image, via URL from OmahaCommunication.
|
||||
3. __Unpacker__: Mount the disk image and extract the Chrome app bundle.
|
||||
4. __AuthorizedInstall__: With privilege escalation if able, move the Chrome
|
||||
app into the Applications folder, set permissions, and hand ownership of
|
||||
the Chrome app to `root`.
|
||||
5. Launch Chrome & close.
|
||||
|
||||
Each of the above modules are designed to carry one action before returning via
|
||||
delegate method. All of these main steps occur on a primary working thread
|
||||
(non-UI), with the exception of `AuthorizedInstall`, which makes use of an
|
||||
authorized-if-able subprocess. If the user does not provide permission to
|
||||
escalate privileges, `AuthorizedInstall` still does its job, but opts for the
|
||||
User's Applications folder instead of the system Applications folder.
|
||||
|
||||
The OmahaXML* classes and SystemInfo class are simply classes to help
|
||||
OmahaCommunication do its work.
|
||||
|
||||
The app's UI is made of a single window that has a determinate progress bar
|
||||
during download, which turns into an indeterminate one during installation. The
|
||||
options to set Chrome as a default browser and opt in for user metrics are made
|
||||
available to the user before they launch Chrome. Once Chrome is ready to launch,
|
||||
a Launch button will now be pressable -- this button will trigger Chrome to open
|
||||
and the installer app to close its remaining window. In the background, the app
|
||||
will take care of any tear-down tasks before exiting naturally.
|
||||
|
||||
We initialize the AuthorizedInstall class early in the life of the installer so
|
||||
the user can immediately choose to authorize the installer for root installation.
|
||||
The script consumes the authorization token (which expires in five minutes by
|
||||
default) immediately, then waits until the installer has progressed to step 4
|
||||
(above).
|
||||
|
||||
## The Class Breakdown
|
||||
|
||||
| Class | Role |
|
||||
|----------------------------|----------------------------------------------------|
|
||||
| AppDelegate | Controls the flow of the program |
|
||||
| AuthorizedInstall | Attempts authorization to add Chrome to the Applications folder and adjust permissions as root |
|
||||
| Downloader | Downloads GoogleChrome.dmg from Omaha servers |
|
||||
| InstallerWindowController | Controls the user interface |
|
||||
| OmahaCommunication | Talks with Omaha Servers to get URL of disk image |
|
||||
| OmahaXMLParser | Extracts URLs from Omaha's XML response |
|
||||
| OmahaXMLRequest | Creates an XML request to send to Omaha |
|
||||
| SystemInfo | Provides system information to help craft the XML request for Omaha |
|
||||
| Unpacker | Mounts the disk image and controls the temporary directory that abstracts the installer's file-manipulating activity from the user |
|
||||
|
||||
## The Future
|
||||
|
||||
Here lies a list of hopes and dreams:
|
||||
|
||||
* Implement resumable downloads.
|
||||
* Add in adequate testing using a local test server.
|
||||
* Include basic error recovery attempts -- say, if during a download a URL
|
||||
does not provide a valid disk image, the installer can try re-downloading
|
||||
the disk image from another URL.
|
||||
* Manage potential conflicts, in the case that Google Chrome already exists in
|
||||
the Applications folder when the installer is run.
|
||||
* Trash the installer application after it has completed running.
|
||||
|
||||
## Diagram Appendix
|
||||
|
||||
### Task Flow
|
||||
|
||||
```
|
||||
|
||||
Exposed Errors Main Logic
|
||||
|
||||
+--------------------------------------+
|
||||
| |
|
||||
| Request authentication from users |
|
||||
| |
|
||||
+------------------+-------------------+
|
||||
|
|
||||
+------------------v-------------------+
|
||||
| |
|
||||
+--------+ Ask Omaha for appropriate Chrome app |
|
||||
v | |
|
||||
+------------------+-------------------+
|
||||
Network Error |
|
||||
+------------------v-------------------+
|
||||
^ | |
|
||||
+--------+ Parse the response from Omaha |
|
||||
| |
|
||||
+------------------+-------------------+
|
||||
|
|
||||
+------------------v-------------------+
|
||||
| |
|
||||
Download Error <-+ Download the Chrome disk image |
|
||||
| |
|
||||
+------------------+-------------------+
|
||||
|
|
||||
+------------------v-------------------+
|
||||
| |
|
||||
+--------+ Mount the disk image |
|
||||
v | |
|
||||
+------------------+-------------------+
|
||||
Install Error |
|
||||
+------------------v-------------------+
|
||||
^ | |
|
||||
+--------+ Install & Configure Chrome app |
|
||||
| |
|
||||
+------------------+-------------------+
|
||||
|
|
||||
+------------------v-------------------+
|
||||
| |
|
||||
| Unmount disk image +-> If unmount fails, system
|
||||
| | restart can resolve this.
|
||||
+------------------+-------------------+
|
||||
|
|
||||
+------------------v-------------------+
|
||||
| |
|
||||
Launch Error <-+ Launch Chrome |
|
||||
| |
|
||||
+--------------------------------------+
|
||||
|
||||
```
|
||||
|
||||
### Class Heirarchy
|
||||
|
||||
```
|
||||
|
||||
Users
|
||||
|
||||
^ +
|
||||
| |
|
||||
| |
|
||||
+-------------------------------+-----v--------------------------------+
|
||||
| |
|
||||
| InstallerWindowController |
|
||||
| |
|
||||
+-------+------^------------+---^--------+----^---------+---------^----+
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
+-------v------+------------v---+--------v----+---------v---------+----+
|
||||
| |
|
||||
| AppDelegate |
|
||||
| |
|
||||
+-------+------^------------+---^--------+----^---------+---------^----+
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
| | | | | | | |
|
||||
+-------v------+-----+ +----v---+---+ +--v----+--+ +----v---------+----+
|
||||
| | | | | | | |
|
||||
| OmahaCommunication | | Downloader | | Unpacker | | AuthorizedInstall |
|
||||
| | | | | | | |
|
||||
+-------^------^-----+ +------------+ +----------+ +---------^---------+
|
||||
| | |
|
||||
| +------------+ |
|
||||
| | |
|
||||
+-------+---------+ +-------+--------+ +--------+--------+
|
||||
| | | | | |
|
||||
| OmahaXMLRequest | | OmahaXMLParser | | copy_to_disk.sh |
|
||||
| | | | | |
|
||||
+-------^---------+ +----------------+ +-----------------+
|
||||
|
|
||||
|
|
||||
|
|
||||
+-----+------+
|
||||
| |
|
||||
| SystemInfo |
|
||||
| |
|
||||
+------------+
|
||||
|
||||
```
|
@ -1,29 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_SYSTEMINFO_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_SYSTEMINFO_H_
|
||||
|
||||
#if !defined(__x86_64__)
|
||||
#error "Your machine's system architecture may not be compatible with Chrome."
|
||||
#endif
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SystemInfo : NSObject
|
||||
// Gets the CPU architecture type of the client's system, which will be used
|
||||
// when crafting the query to Omaha. This should return either "x84_64h" for
|
||||
// systems running on Intel Haswell chips, "i486" for other Intel machines, or
|
||||
// strings representing other CPU types ("amd", "pentium", and "i686", for
|
||||
// example, are all possible; however, due to the above macro, the possible
|
||||
// return strings are limited to either "x84_64h" or "i486").
|
||||
+ (NSString*)getArch;
|
||||
|
||||
// Gets the operating system version of the client. This function may return
|
||||
// values such as "10.11" or "10.10.5".
|
||||
+ (NSString*)getOSVersion;
|
||||
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_SYSTEMINFO_H_
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <mach-o/arch.h>
|
||||
|
||||
#import "SystemInfo.h"
|
||||
|
||||
@implementation SystemInfo
|
||||
|
||||
+ (NSString*)getArch {
|
||||
// NOTE: It seems the below function `NSGetLocalArchInfo` returns an
|
||||
// arch->name that is either "x84_64h" or "i486".
|
||||
const NXArchInfo* arch = NXGetLocalArchInfo();
|
||||
NSString* archName = [NSString stringWithUTF8String:arch->name];
|
||||
return archName;
|
||||
}
|
||||
|
||||
+ (NSString*)getOSVersion {
|
||||
NSDictionary* systemVersion =
|
||||
[NSDictionary dictionaryWithContentsOfFile:
|
||||
@"/System/Library/CoreServices/SystemVersion.plist"];
|
||||
NSString* versionNumber = [systemVersion objectForKey:@"ProductVersion"];
|
||||
|
||||
return versionNumber;
|
||||
}
|
||||
|
||||
@end
|
@ -1,30 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_INSTALLER_MAC_APP_UNPACKER_H_
|
||||
#define CHROME_INSTALLER_MAC_APP_UNPACKER_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Unpacker;
|
||||
@protocol UnpackDelegate<NSObject>
|
||||
- (void)unpacker:(Unpacker*)unpacker onMountSuccess:(NSString*)tempAppPath;
|
||||
- (void)unpacker:(Unpacker*)unpacker onMountFailure:(NSError*)error;
|
||||
- (void)unpacker:(Unpacker*)unpacker onUnmountSuccess:(NSString*)mountpath;
|
||||
- (void)unpacker:(Unpacker*)unpacker onUnmountFailure:(NSError*)error;
|
||||
@end
|
||||
|
||||
@interface Unpacker : NSObject
|
||||
|
||||
@property(nonatomic, assign) id<UnpackDelegate> delegate;
|
||||
@property(nonatomic, copy) NSString* appPath;
|
||||
|
||||
// Mount a disk image at |fileURL|.
|
||||
- (void)mountDMGFromURL:(NSURL*)fileURL;
|
||||
// Unmount that same disk image.
|
||||
- (void)unmountDMG;
|
||||
|
||||
@end
|
||||
|
||||
#endif // CHROME_INSTALLER_MAC_APP_UNPACKER_H_
|
@ -1,167 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "Unpacker.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#include <DiskArbitration/DiskArbitration.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
#import "Downloader.h"
|
||||
|
||||
@interface Unpacker () {
|
||||
NSURL* temporaryDirectoryURL_;
|
||||
NSString* mountPath_;
|
||||
|
||||
NSTask* __weak mountTask_;
|
||||
|
||||
DASessionRef session_;
|
||||
dispatch_queue_t unpack_dq_;
|
||||
}
|
||||
- (void)didFinishEjectingDisk:(DADiskRef)disk
|
||||
withDissenter:(DADissenterRef)dissenter;
|
||||
@end
|
||||
|
||||
static void eject_callback(DADiskRef disk,
|
||||
DADissenterRef dissenter,
|
||||
void* context) {
|
||||
Unpacker* unpacker = (__bridge_transfer Unpacker*)context;
|
||||
[unpacker didFinishEjectingDisk:disk withDissenter:dissenter];
|
||||
}
|
||||
|
||||
static void unmount_callback(DADiskRef disk,
|
||||
DADissenterRef dissenter,
|
||||
void* context) {
|
||||
if (dissenter) {
|
||||
Unpacker* unpacker = (__bridge Unpacker*)context;
|
||||
[unpacker didFinishEjectingDisk:disk withDissenter:dissenter];
|
||||
} else {
|
||||
DADiskEject(disk, kDADiskEjectOptionDefault, eject_callback, context);
|
||||
}
|
||||
}
|
||||
|
||||
@implementation Unpacker
|
||||
|
||||
@synthesize delegate = delegate_;
|
||||
@synthesize appPath = appPath_;
|
||||
|
||||
- (void)cleanUp {
|
||||
[mountTask_ terminate];
|
||||
// It's not the end of the world if this temporary directory is not removed
|
||||
// here. The directory will be deleted when the operating system itself
|
||||
// decides to anyway.
|
||||
[[NSFileManager defaultManager] removeItemAtURL:temporaryDirectoryURL_
|
||||
error:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
// TODO: The failure delegate methods need to be revised to meaningfully deal
|
||||
// with the errors (pipe in stderr / stdout to handle the error according to
|
||||
// what the error was).
|
||||
- (void)mountDMGFromURL:(NSURL*)fileURL {
|
||||
NSError* error = nil;
|
||||
temporaryDirectoryURL_ = [[NSFileManager defaultManager]
|
||||
URLForDirectory:NSItemReplacementDirectory
|
||||
inDomain:NSUserDomainMask
|
||||
appropriateForURL:[NSURL fileURLWithPath:@"/" isDirectory:YES]
|
||||
create:YES
|
||||
error:&error];
|
||||
if (error) {
|
||||
[delegate_ unpacker:self onMountFailure:error];
|
||||
return;
|
||||
}
|
||||
|
||||
NSURL* temporaryDiskImageURL =
|
||||
[temporaryDirectoryURL_ URLByAppendingPathComponent:@"GoogleChrome.dmg"];
|
||||
mountPath_ = [[temporaryDirectoryURL_ URLByAppendingPathComponent:@"mnt"
|
||||
isDirectory:YES] path];
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:mountPath_
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:&error];
|
||||
if (error) {
|
||||
[delegate_ unpacker:self onMountFailure:error];
|
||||
return;
|
||||
}
|
||||
|
||||
// If the user closes the app at any time, we make sure that the cleanUp
|
||||
// function deletes the temporary folder we just created.
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(cleanUp)
|
||||
name:NSApplicationWillTerminateNotification
|
||||
object:nil];
|
||||
|
||||
[[NSFileManager defaultManager] moveItemAtURL:fileURL
|
||||
toURL:temporaryDiskImageURL
|
||||
error:nil];
|
||||
|
||||
NSString* path = @"/usr/bin/hdiutil";
|
||||
NSArray* args = @[
|
||||
@"attach", temporaryDiskImageURL, @"-nobrowse", @"-noverify",
|
||||
@"-mountpoint", mountPath_
|
||||
];
|
||||
|
||||
NSTask* mountTask = [[NSTask alloc] init];
|
||||
mountTask.launchPath = path;
|
||||
mountTask.arguments = args;
|
||||
mountTask.terminationHandler = ^void(NSTask* task) {
|
||||
NSError* error = nil;
|
||||
NSString* diskAppPath =
|
||||
[NSString pathWithComponents:@[ mountPath_, @"Google Chrome.app" ]];
|
||||
NSString* tempAppPath = [[temporaryDirectoryURL_
|
||||
URLByAppendingPathComponent:@"Google Chrome.app"] path];
|
||||
[[NSFileManager defaultManager] copyItemAtPath:diskAppPath
|
||||
toPath:tempAppPath
|
||||
error:&error];
|
||||
if (error) {
|
||||
[delegate_ unpacker:self onMountFailure:error];
|
||||
} else {
|
||||
[delegate_ unpacker:self onMountSuccess:tempAppPath];
|
||||
}
|
||||
};
|
||||
mountTask_ = mountTask;
|
||||
[mountTask launch];
|
||||
}
|
||||
|
||||
- (void)unmountDMG {
|
||||
session_ = DASessionCreate(nil);
|
||||
unpack_dq_ =
|
||||
dispatch_queue_create("com.google.chrome.unpack", DISPATCH_QUEUE_SERIAL);
|
||||
DASessionSetDispatchQueue(session_, unpack_dq_);
|
||||
DADiskRef child_disk = DADiskCreateFromVolumePath(
|
||||
nil, session_,
|
||||
(__bridge CFURLRef)[NSURL fileURLWithPath:mountPath_ isDirectory:YES]);
|
||||
DADiskRef whole_disk = DADiskCopyWholeDisk(child_disk);
|
||||
|
||||
DADiskUnmount(whole_disk,
|
||||
kDADiskUnmountOptionWhole | kDADiskUnmountOptionForce,
|
||||
unmount_callback, (__bridge_retained void*)self);
|
||||
|
||||
CFRelease(whole_disk);
|
||||
CFRelease(child_disk);
|
||||
}
|
||||
|
||||
- (void)didFinishEjectingDisk:(DADiskRef)disk
|
||||
withDissenter:(DADissenterRef)dissenter {
|
||||
DASessionSetDispatchQueue(session_, NULL);
|
||||
CFRelease(session_);
|
||||
NSError* error = nil;
|
||||
if (dissenter) {
|
||||
DAReturn status = DADissenterGetStatus(dissenter);
|
||||
error = [NSError
|
||||
errorWithDomain:@"ChromeErrorDomain"
|
||||
code:err_get_code(status)
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey :
|
||||
(__bridge NSString*)DADissenterGetStatusString(dissenter)
|
||||
}];
|
||||
[delegate_ unpacker:self onUnmountFailure:error];
|
||||
} else {
|
||||
[self cleanUp];
|
||||
[delegate_ unpacker:self onUnmountSuccess:mountPath_];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,43 +0,0 @@
|
||||
#!/bin/sh -p
|
||||
|
||||
# Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# This script will be called by the installer application to copy Google
|
||||
# Chrome.app into the proper /Applications folder. This script may run as root.
|
||||
#
|
||||
# When running as root, this script will be invoked with the real user ID set
|
||||
# to the user's ID, but the effective user ID set to 0 (root). bash -p is
|
||||
# used on the first line to prevent bash from setting the effective user ID to
|
||||
# the real user ID (dropping root privileges).
|
||||
|
||||
# 'e': terminate if error arises
|
||||
# 'u': raise an error if a variable isn't set
|
||||
# 'o pipefail': set the return exit code to the last non-zero error code
|
||||
set -euo pipefail
|
||||
|
||||
# Waits for the main app to pass the path to the app bundle inside the mounted
|
||||
# disk image.
|
||||
read -r SRC
|
||||
|
||||
DEST="${1}"
|
||||
APPBUNDLENAME=$(basename "${SRC}")
|
||||
FULL_DEST="${DEST}"/"${APPBUNDLENAME}"
|
||||
|
||||
# Starts the copy
|
||||
# 'l': copy symlinks as symlinks
|
||||
# 'r': recursive copy
|
||||
# 'p': preserve permissions
|
||||
# 't': preserve times
|
||||
# 'q': quiet mode, so rynsc will only log to console if an error occurs
|
||||
rsync -lrptq "${SRC}" "${DEST}"
|
||||
|
||||
# If this script is run as root, change ownership to root and set elevated
|
||||
# permissions.
|
||||
if [ "${EUID}" -eq 0 ] ; then
|
||||
chown -Rh root:admin "${FULL_DEST}"
|
||||
chmod -R a+rX,ug+w,o-w "${FULL_DEST}"
|
||||
fi
|
||||
|
||||
exit 0
|
@ -1,9 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
return NSApplicationMain(argc, argv);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "chrome/installer/mac/app/OmahaXMLRequest.h"
|
||||
|
||||
#include "base/base_paths.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(OmahaXMLRequestTest, CreateReturnsValidXML) {
|
||||
NSXMLDocument* xml_body_ = [OmahaXMLRequest createXMLRequestBody];
|
||||
ASSERT_TRUE(xml_body_);
|
||||
|
||||
base::FilePath path;
|
||||
base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
|
||||
path = path.AppendASCII("chrome/test/data/mac_installer/requestCheck.dtd");
|
||||
NSString* requestDTDLocation = base::SysUTF8ToNSString(path.value());
|
||||
NSData* requestDTDData = [NSData dataWithContentsOfFile:requestDTDLocation];
|
||||
ASSERT_TRUE(requestDTDData);
|
||||
|
||||
NSError* error;
|
||||
NSXMLDTD* requestXMLChecker =
|
||||
[[NSXMLDTD alloc] initWithData:requestDTDData options:0 error:&error];
|
||||
[requestXMLChecker setName:@"request"];
|
||||
[xml_body_ setDTD:requestXMLChecker];
|
||||
EXPECT_TRUE([xml_body_ validateAndReturnError:&error]);
|
||||
}
|
||||
|
||||
} // namespace
|
@ -1,32 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "chrome/installer/mac/app/SystemInfo.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(SystemInfoTest, GetArchReturnsExpectedString) {
|
||||
NSString* arch = [SystemInfo getArch];
|
||||
|
||||
EXPECT_TRUE([arch isEqualToString:@"i486"] ||
|
||||
[arch isEqualToString:@"x86_64h"]);
|
||||
}
|
||||
|
||||
TEST(SystemInfoTest, GetOSVersionMatchesRegexFormat) {
|
||||
NSString* os_version = [SystemInfo getOSVersion];
|
||||
|
||||
NSRegularExpression* regex = [NSRegularExpression
|
||||
regularExpressionWithPattern:@"^10\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$"
|
||||
options:0
|
||||
error:nil];
|
||||
NSUInteger matches =
|
||||
[regex numberOfMatchesInString:os_version
|
||||
options:0
|
||||
range:NSMakeRange(0, os_version.length)];
|
||||
EXPECT_EQ(1u, matches);
|
||||
}
|
||||
|
||||
} // namespace
|
@ -1,113 +0,0 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "chrome/installer/mac/app/Unpacker.h"
|
||||
|
||||
#include "base/base_paths.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#import "chrome/installer/mac/app/Downloader.h"
|
||||
|
||||
@interface TestDelegate : NSObject<UnpackDelegate>
|
||||
@property(nonatomic) BOOL pass;
|
||||
@property(nonatomic) dispatch_semaphore_t test_semaphore;
|
||||
- (void)fail;
|
||||
- (void)succeed;
|
||||
- (void)wait;
|
||||
@end
|
||||
|
||||
@implementation TestDelegate
|
||||
@synthesize pass = pass_;
|
||||
@synthesize test_semaphore = test_semaphore_;
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
test_semaphore_ = dispatch_semaphore_create(0);
|
||||
pass_ = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)succeed {
|
||||
pass_ = YES;
|
||||
dispatch_semaphore_signal(test_semaphore_);
|
||||
}
|
||||
- (void)fail {
|
||||
pass_ = NO;
|
||||
dispatch_semaphore_signal(test_semaphore_);
|
||||
}
|
||||
- (void)wait {
|
||||
dispatch_semaphore_wait(test_semaphore_, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
- (void)unpacker:(Unpacker*)unpacker onMountSuccess:(NSString*)tempAppPath {
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:tempAppPath]) {
|
||||
[self succeed];
|
||||
} else {
|
||||
[self fail];
|
||||
}
|
||||
}
|
||||
- (void)unpacker:(Unpacker*)unpacker onMountFailure:(NSError*)error {
|
||||
[self fail];
|
||||
}
|
||||
|
||||
- (void)unpacker:(Unpacker*)unpacker onUnmountSuccess:(NSString*)mountpath {
|
||||
if (![[NSFileManager defaultManager]
|
||||
fileExistsAtPath:[NSString pathWithComponents:@[
|
||||
mountpath, @"Google Chrome.app"
|
||||
]]]) {
|
||||
[self succeed];
|
||||
} else {
|
||||
[self fail];
|
||||
}
|
||||
}
|
||||
- (void)unpacker:(Unpacker*)unpacker onUnmountFailure:(NSError*)error {
|
||||
[self fail];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(UnpackerTest, IntegrationTest) {
|
||||
// Create objects and semaphore
|
||||
Unpacker* unpack = [[Unpacker alloc] init];
|
||||
TestDelegate* test_delegate = [[TestDelegate alloc] init];
|
||||
unpack.delegate = test_delegate;
|
||||
|
||||
// Get a disk image to use to test
|
||||
base::FilePath originalPath;
|
||||
base::PathService::Get(base::DIR_SOURCE_ROOT, &originalPath);
|
||||
originalPath = originalPath.AppendASCII("chrome/test/data/mac_installer/");
|
||||
base::FilePath copiedPath = base::FilePath(originalPath);
|
||||
NSString* diskImageOriginalPath = base::SysUTF8ToNSString(
|
||||
(originalPath.AppendASCII("test-dmg.dmg")).value());
|
||||
NSString* diskImageCopiedPath = base::SysUTF8ToNSString(
|
||||
(originalPath.AppendASCII("test-dmg2.dmg")).value());
|
||||
// The unpacker moves (not copies) a downloaded disk image directly into its
|
||||
// own temporary directory, so if the below copy didn't happen, `test-dmg.dmg`
|
||||
// would disappear every time this test was run
|
||||
[[NSFileManager defaultManager] copyItemAtPath:diskImageOriginalPath
|
||||
toPath:diskImageCopiedPath
|
||||
error:nil];
|
||||
NSURL* dmgURL = [NSURL fileURLWithPath:diskImageCopiedPath isDirectory:NO];
|
||||
// Start mount step
|
||||
[unpack mountDMGFromURL:dmgURL];
|
||||
[test_delegate wait];
|
||||
|
||||
// Is the disk image mounted?
|
||||
ASSERT_TRUE([test_delegate pass]);
|
||||
|
||||
// Start unmount step
|
||||
[unpack unmountDMG];
|
||||
[test_delegate wait];
|
||||
|
||||
// Is the disk image gone?
|
||||
EXPECT_TRUE([test_delegate pass]);
|
||||
}
|
||||
|
||||
} // namespace
|
@ -13434,12 +13434,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true
|
||||
@ -14153,15 +14147,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"--test-launcher-print-test-stdio=always"
|
||||
],
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"--test-launcher-print-test-stdio=always"
|
||||
|
@ -658,12 +658,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true
|
||||
@ -8170,19 +8164,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
"dimension_sets": [
|
||||
{
|
||||
"gpu": "8086:0a2e",
|
||||
"os": "Mac-10.14"
|
||||
}
|
||||
],
|
||||
"expiration": 21600
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
@ -9215,15 +9196,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"--enable-features=ViewsBrowserWindows"
|
||||
],
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"--enable-features=ViewsBrowserWindows"
|
||||
|
@ -580,18 +580,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
"dimension_sets": [
|
||||
{
|
||||
"gpu": "none",
|
||||
"os": "Mac-10.10"
|
||||
}
|
||||
]
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
@ -1717,18 +1705,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
"dimension_sets": [
|
||||
{
|
||||
"gpu": "none",
|
||||
"os": "Mac-10.11"
|
||||
}
|
||||
]
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
@ -2939,18 +2915,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
"dimension_sets": [
|
||||
{
|
||||
"gpu": "8086:0a2e",
|
||||
"os": "Mac-10.12.6"
|
||||
}
|
||||
]
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
@ -4076,18 +4040,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
"dimension_sets": [
|
||||
{
|
||||
"gpu": "none",
|
||||
"os": "Mac-10.13"
|
||||
}
|
||||
]
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
@ -5201,18 +5153,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
"dimension_sets": [
|
||||
{
|
||||
"gpu": "none",
|
||||
"os": "Mac-10.13"
|
||||
}
|
||||
]
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true,
|
||||
|
@ -9198,15 +9198,6 @@
|
||||
},
|
||||
"test": "libjingle_xmpp_unittests"
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"--test-launcher-print-test-stdio=always"
|
||||
],
|
||||
"swarming": {
|
||||
"can_use_on_swarming_builders": true
|
||||
},
|
||||
"test": "mac_installer_unittests"
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"--test-launcher-print-test-stdio=always"
|
||||
|
@ -793,10 +793,6 @@
|
||||
"label": "//third_party/libjingle_xmpp:libjingle_xmpp_unittests",
|
||||
"type": "console_test_launcher",
|
||||
},
|
||||
"mac_installer_unittests": {
|
||||
"label": "//chrome/installer/mac/app:mac_installer_unittests",
|
||||
"type": "console_test_launcher",
|
||||
},
|
||||
"mash:all" : {
|
||||
"label": "//mash:all",
|
||||
"type": "additional_compile_target",
|
||||
|
@ -1828,7 +1828,6 @@
|
||||
},
|
||||
|
||||
'mac_specific_chromium_gtests': {
|
||||
'mac_installer_unittests': {},
|
||||
'sandbox_mac_unittests': {},
|
||||
},
|
||||
|
||||
|
Reference in New Issue
Block a user