Skip to content

Commit cb0c80c

Browse files
authored
feat(auto-update-manager): show a system prompt about mismatched arch on apple arm on application start COMPASS-9592 (#7133)
* feat(auto-update-manager): show a system prompt about mismatched arch on apple arm on application start * chore(auto-update-manager): error handling and wait for app ready * chore(compass): replace direct download with open external * chore(auto-update-manager): share download logic, normalize url building * chore(auto-update-manager): auto open on download * fix(auto-update-mananger): convert path to file url * chore(compass): adjust unit test for new download behavior
1 parent 37dc196 commit cb0c80c

File tree

3 files changed

+101
-15
lines changed

3 files changed

+101
-15
lines changed

packages/compass/src/main/application.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,13 @@ class CompassApplication {
175175

176176
await this.setupCORSBypass();
177177
void this.setupCompassAuthService();
178-
if (!process.env.CI || process.env.HADRON_AUTO_UPDATE_ENDPOINT_OVERRIDE) {
179-
this.setupAutoUpdate();
180-
}
181178
await setupCSFLELibrary();
182179
setupTheme(this);
183180
this.setupJavaScriptArguments();
184181
this.setupLifecycleListeners();
185182
this.setupApplicationMenu();
186183
this.setupWindowManager();
184+
this.setupAutoUpdate();
187185
this.trackApplicationLaunched(globalPreferences);
188186
}
189187

@@ -213,7 +211,9 @@ class CompassApplication {
213211
}
214212

215213
private static setupAutoUpdate(): void {
216-
CompassAutoUpdateManager.init(this);
214+
if (!process.env.CI || process.env.HADRON_AUTO_UPDATE_ENDPOINT_OVERRIDE) {
215+
void CompassAutoUpdateManager.init(this);
216+
}
217217
}
218218

219219
private static setupApplicationMenu(): void {

packages/compass/src/main/auto-update-manager.spec.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
CompassAutoUpdateManager,
77
} from './auto-update-manager';
88
import type { DownloadItem } from 'electron';
9-
import { dialog, autoUpdater } from 'electron';
9+
import { dialog, autoUpdater, BrowserWindow } from 'electron';
1010
import os from 'os';
1111
import dl from 'electron-dl';
1212
import { createSandboxFromDefaultPreferences } from 'compass-preferences-model';
@@ -344,6 +344,10 @@ describe('CompassAutoUpdateManager', function () {
344344
return Promise.resolve({ response: 0, checkboxChecked: false });
345345
});
346346

347+
sandbox.stub(BrowserWindow, 'getAllWindows').callsFake(() => {
348+
return [{} as BrowserWindow];
349+
});
350+
347351
const stub = sandbox.stub(dl, 'download').callsFake(() => {
348352
return Promise.resolve({} as DownloadItem);
349353
});
@@ -356,6 +360,10 @@ describe('CompassAutoUpdateManager', function () {
356360
)
357361
).to.eq(true);
358362

363+
// Any small timeout will do, we're allowing for the async tasks to
364+
// clear
365+
await wait(300);
366+
359367
expect(stub).to.be.calledOnce;
360368
});
361369

packages/compass/src/main/auto-update-manager.ts

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type { PreferencesAccess } from 'compass-preferences-model';
1616
import { getOsInfo } from '@mongodb-js/get-os-info';
1717
import { createIpcTrack } from '@mongodb-js/compass-telemetry';
1818
import type { Response } from '@mongodb-js/devtools-proxy-support';
19+
import { pathToFileURL } from 'url';
1920

2021
const { log, mongoLogId, debug } = createLogger('COMPASS-AUTO-UPDATES');
2122
const track = createIpcTrack();
@@ -60,6 +61,37 @@ function isMismatchedArchDarwin(): boolean {
6061
return process.platform === 'darwin' && getSystemArch() !== process.arch;
6162
}
6263

64+
async function waitForWindow(timeout = 5_000) {
65+
const start = Date.now();
66+
while (start + timeout > Date.now()) {
67+
await new Promise((resolve) => setTimeout(resolve, 100));
68+
const window = BrowserWindow.getAllWindows()[0];
69+
if (window) {
70+
return window;
71+
}
72+
}
73+
return null;
74+
}
75+
76+
async function download(url: string): Promise<void> {
77+
const maybeWindow = await waitForWindow();
78+
if (maybeWindow) {
79+
await dl.download(maybeWindow, url, {
80+
onCompleted(file) {
81+
const fileURL = pathToFileURL(file.path).toString();
82+
void shell.openExternal(fileURL);
83+
},
84+
});
85+
} else {
86+
await shell.openExternal(url);
87+
}
88+
}
89+
90+
function getMacOSDownloadUrl(channel: string, version: string): string {
91+
version = channel === 'dev' ? 'latest' : version;
92+
return `https://compass.mongodb.com/api/v2/download/${version}/compass/${channel}/darwin-${getSystemArch()}`;
93+
}
94+
6395
type PromptForUpdateResult = 'download' | 'update' | 'cancel';
6496
async function promptForUpdate(
6597
from: string,
@@ -445,7 +477,7 @@ const STATE_UPDATE: Record<
445477
},
446478
[AutoUpdateManagerState.ManualDownload]: {
447479
nextStates: [AutoUpdateManagerState.UserPromptedManualCheck],
448-
enter: function (_updateManager, _fromState, updateInfo: UpdateInfo) {
480+
enter: function (updateManager, _fromState, updateInfo: UpdateInfo) {
449481
log.info(
450482
mongoLogId(1_001_000_167),
451483
'AutoUpdateManager',
@@ -467,10 +499,11 @@ const STATE_UPDATE: Record<
467499
);
468500
}
469501

470-
const url = `https://downloads.mongodb.com/compass/${
471-
process.env.HADRON_PRODUCT
472-
}-${updateInfo.to}-${process.platform}-${getSystemArch()}.dmg`;
473-
void dl.download(BrowserWindow.getAllWindows()[0], url);
502+
const url = getMacOSDownloadUrl(
503+
updateManager.autoUpdateOptions.channel,
504+
updateInfo.to
505+
);
506+
void download(url);
474507
},
475508
},
476509
[AutoUpdateManagerState.UpdateDismissed]: {
@@ -827,11 +860,54 @@ class CompassAutoUpdateManager {
827860
this.setState(AutoUpdateManagerState.RestartDismissed);
828861
}
829862

830-
private static _init(
863+
private static checkForMismatchedMacOSArch() {
864+
const mismatchedOnArm =
865+
isMismatchedArchDarwin() && getSystemArch() === 'arm64';
866+
867+
if (!mismatchedOnArm) {
868+
return;
869+
}
870+
871+
void dialog
872+
.showMessageBox({
873+
icon: COMPASS_ICON,
874+
message: 'Mismatched architecture detected',
875+
detail:
876+
'You are currently using a build of Compass that is not optimized for Apple Silicon processors. This version might have significant performance issues when used. ' +
877+
'Would you like to download the version of Compass optimized for Apple Silicon processors now?',
878+
buttons: [
879+
'Download Compass for Apple Silicon (Recommended)',
880+
'Not now',
881+
],
882+
cancelId: 1,
883+
})
884+
.then(({ response }) => {
885+
if (response === 0) {
886+
const url = getMacOSDownloadUrl(
887+
this.autoUpdateOptions.channel,
888+
this.autoUpdateOptions.version
889+
);
890+
return download(url);
891+
}
892+
})
893+
.catch((err) => {
894+
log.warn(
895+
mongoLogId(1_001_000_362),
896+
'AutoUpdateManager',
897+
'Failed to download Compass for a mismatched macos arch',
898+
{ error: err.message }
899+
);
900+
});
901+
}
902+
903+
private static async _init(
831904
compassApp: typeof CompassApplication,
832905
options: Partial<AutoUpdateManagerOptions> = {}
833-
): void {
906+
): Promise<void> {
907+
await app.whenReady();
908+
834909
this.fetch = (url: string) => compassApp.httpClient.fetch(url);
910+
835911
compassApp.addExitHandler(() => {
836912
this.stop();
837913
return Promise.resolve();
@@ -867,6 +943,8 @@ class CompassAutoUpdateManager {
867943
...options,
868944
};
869945

946+
this.checkForMismatchedMacOSArch();
947+
870948
// TODO(COMPASS-7232): If auto-updates are not supported, then there is
871949
// still a menu item to check for updates and then if it finds an update but
872950
// auto-updates aren't supported it will still display a popup with an
@@ -961,13 +1039,13 @@ class CompassAutoUpdateManager {
9611039
);
9621040
}
9631041

964-
static init(
1042+
static async init(
9651043
compassApp: typeof CompassApplication,
9661044
options: Partial<AutoUpdateManagerOptions> = {}
967-
): void {
1045+
): Promise<void> {
9681046
if (!this.initCalled) {
9691047
this.initCalled = true;
970-
this._init(compassApp, options);
1048+
await this._init(compassApp, options);
9711049
}
9721050
}
9731051

0 commit comments

Comments
 (0)