Skip to content

Commit 487d20f

Browse files
authored
fix: fix the shortcuts on windows to be the app name, not executable name COMPASS-8367 (#6846)
* Add shortcutName to MSI Creator so it will have the expected space * Also fix the shortcut that's made by squirrel * spaces * quotes * better link * do not strip spaces from the windows executable name * comment * replace spaces * rather rename the shortcut * turns out that, at this point, HADRON_PRODUCT_NAME already contains Dev or Beta * incorrect comment
1 parent 2b2a627 commit 487d20f

File tree

7 files changed

+146
-62
lines changed

7 files changed

+146
-62
lines changed

package-lock.json

Lines changed: 0 additions & 52 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/compass/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@
251251
"electron-devtools-installer": "^3.2.0",
252252
"electron-dl": "^3.5.0",
253253
"electron-mocha": "^12.2.0",
254-
"electron-squirrel-startup": "^1.0.1",
255254
"ensure-error": "^3.0.1",
256255
"glob": "^10.2.5",
257256
"local-links": "^1.4.0",

packages/compass/src/main/application.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
extractProxySecrets,
4040
translateToElectronProxyConfig,
4141
} from '@mongodb-js/devtools-proxy-support';
42+
import { handleSquirrelWindowsStartup } from './squirrel-startup';
4243

4344
const { debug, log, mongoLogId } = createLogger('COMPASS-MAIN');
4445
const track = createIpcTrack();
@@ -121,8 +122,8 @@ class CompassApplication {
121122
);
122123

123124
// needs to happen after setupProtocolHandlers
124-
if ((await import('electron-squirrel-startup')).default) {
125-
debug('electron-squirrel-startup event handled sucessfully\n');
125+
if (await handleSquirrelWindowsStartup()) {
126+
app.quit();
126127
return;
127128
}
128129

packages/compass/src/main/electron-squirrel-startup.d.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { promises as fs } from 'fs';
2+
import os from 'os';
3+
import path from 'path';
4+
import { spawn } from 'child_process';
5+
import { createLogger } from '@mongodb-js/compass-logging';
6+
const { debug } = createLogger('SQUIRREL-STARTUP');
7+
8+
function runUpdateExe(args: string[]): Promise<void> {
9+
return new Promise<void>(function (resolve) {
10+
const updateExe = path.resolve(
11+
path.dirname(process.execPath),
12+
'..',
13+
'Update.exe'
14+
);
15+
debug('Spawning `%s` with args `%s`', updateExe, args.join(' '));
16+
spawn(updateExe, args, {
17+
detached: true,
18+
}).on('close', () => resolve());
19+
});
20+
}
21+
22+
function getShortcutName() {
23+
return process.env.HADRON_PRODUCT_NAME ?? 'MongoDB Compass';
24+
}
25+
26+
async function renameShortcuts(from: string, to: string) {
27+
const folders: string[] = [];
28+
29+
if (process.env.APPDATA) {
30+
// start menu shortcut
31+
// NOTE: This includes the non-ideal "MongoDB Inc" folder name as opposed to
32+
// "MongoDB".
33+
folders.push(
34+
path.join(
35+
process.env.APPDATA,
36+
'Microsoft',
37+
'Windows',
38+
'Start Menu',
39+
'Programs',
40+
'MongoDB Inc'
41+
)
42+
);
43+
}
44+
45+
// desktop shortcut
46+
folders.push(path.join(os.homedir(), 'Desktop'));
47+
48+
for (const folder of folders) {
49+
const source = path.join(folder, from);
50+
const destination = path.join(folder, to);
51+
try {
52+
// only rename the shortcut if it exists at the standard, expected location
53+
if (await fs.stat(source)) {
54+
debug('renaming shortcut from %s to %s', source, destination);
55+
await fs.rename(source, destination);
56+
} else {
57+
debug('shortcut %s does not exist, skipping rename', source);
58+
}
59+
} catch (err: unknown) {
60+
debug(
61+
'error renaming shortcut from %s to %s: %s',
62+
source,
63+
destination,
64+
err
65+
);
66+
}
67+
}
68+
}
69+
70+
/*
71+
Squirrel will spawn Compass with command line flags on first run, updates, and
72+
uninstalls. It is very important that we handle these events as early as
73+
possible, and quit immediately after handling them. Squirrel gives apps a short
74+
amount of time (~15sec) to apply these operations and quit.
75+
*/
76+
export async function handleSquirrelWindowsStartup(): Promise<boolean> {
77+
if (process.platform !== 'win32') {
78+
return false;
79+
}
80+
81+
// This has to be an executable that was packaged up with the app. There's no
82+
// way to control what the shortcut name will be - it is always the same as
83+
// the executable.
84+
const exeName = path.basename(process.execPath);
85+
86+
// We want the desktop and start menu shortcuts to be named with spaces in
87+
// them so that when the user searches for "compass" in the start menu it will
88+
// find it.
89+
const correctShortcutName = getShortcutName() + '.lnk';
90+
const wrongShortcutName = getShortcutName().replace(/ /g, '') + '.lnk';
91+
92+
const cmd = process.argv[1];
93+
debug('processing squirrel command `%s`', cmd);
94+
95+
/*
96+
For more detailed info on these commands, so Electron, electron-winstaller and Squirrel Windows'
97+
documentation:
98+
99+
https://github.com/electron/windows-installer?tab=readme-ov-file#handling-squirrel-events
100+
https://github.com/electron-archive/grunt-electron-installer?tab=readme-ov-file#handling-squirrel-events
101+
https://github.com/Squirrel/Squirrel.Windows/blob/master/docs/using/custom-squirrel-events-non-cs.md
102+
https://github.com/Squirrel/Squirrel.Windows/blob/master/docs/using/install-process.md
103+
https://github.com/Squirrel/Squirrel.Windows/blob/master/docs/using/update-process.md#update-process
104+
*/
105+
switch (cmd) {
106+
case '--squirrel-install':
107+
case '--squirrel-updated':
108+
await runUpdateExe([`--createShortcut=${exeName}`]);
109+
// Rename the shortcut that was just created to be what we want it to be.
110+
await renameShortcuts(wrongShortcutName, correctShortcutName);
111+
debug(`${cmd} handled sucessfully`);
112+
return true;
113+
114+
case '--squirrel-uninstall':
115+
// Rename the shortcut back to the original name so it can be removed as
116+
// usual.
117+
await renameShortcuts(correctShortcutName, wrongShortcutName);
118+
await runUpdateExe([`--removeShortcut=${exeName}`]);
119+
debug(`${cmd} handled sucessfully`);
120+
return true;
121+
122+
case '--squirrel-obsolete':
123+
debug(`${cmd} handled sucessfully`);
124+
return true;
125+
126+
default:
127+
debug(`Unknown squirrel command: ${cmd}. Continuing on.`);
128+
}
129+
130+
return false;
131+
}

packages/hadron-build/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ And then finally
213213

214214
- User's launch application via a desktop shortcut `${productName}`
215215
- Installing into `C:\\Program Files\` would require Administrator
216-
- Desktop shortcut managed for you automatically if you use https://github.com/mongodb-js/electron-squirrel-startup
217216
- Shortcut Target: `C:\Users\${username}\AppData\Local\${_.titlecase(productName)}\Update.exe --processStart ${_.titlecase(productName)}.exe`
218217
- Shortcut Start In: `C:\Users\${username}\AppData\Local\${_.titlecase(productName)}\app-${version}`
219218

@@ -267,7 +266,6 @@ Which assets are generated depends on the target platform.
267266

268267
### Windows
269268

270-
- `electron-squirrel-startup`: https://github.com/mongodb-js/electron-squirrel-startup
271269
- [Update process explained step by step](https://github.com/Squirrel/Squirrel.Windows/blob/master/docs/using/update-process.md#update-process)
272270

273271
### Linux

packages/hadron-build/lib/target.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ class Target {
313313
* remoteToken: this.githubToken,
314314
*/
315315
Object.assign(this.packagerOptions, {
316+
// This name becomes the .exe name, but it is also used to determine
317+
// various other parts including the nupkg file and its metadata and the
318+
// code that makes that validates that the filename does not contain
319+
// spaces. So basically the .exe we build is not allowed to contain
320+
// spaces and it is out of our control.
316321
name: this.productName.replace(/ /g, ''),
317322
icon: this.src(platformSettings.icon),
318323
'version-string': {
@@ -393,6 +398,10 @@ class Target {
393398
iconUrl: platformSettings.favicon_url,
394399
appDirectory: this.appPath,
395400
outputDirectory: this.packagerOptions.out,
401+
// NOTE: This also becomes the name of the shortcut folder. Will be
402+
// "MongoDB Inc" if it uses this.author. Tempting to use
403+
// this.shortcutFolderName so it becomes MongoDB like for the .msi, but
404+
// who knows what else will be affected.
396405
authors: this.author,
397406
version: this.version,
398407
exe: `${this.packagerOptions.name}.exe`,
@@ -450,10 +459,12 @@ class Target {
450459
outputDirectory: this.packagerOptions.out,
451460
exe: this.packagerOptions.name,
452461
name: this.productName,
462+
// NOTE: falling back to author would result in MongoDB Inc
463+
shortcutFolderName: this.shortcutFolderName || this.author,
464+
shortcutName: this.productName,
453465
description: this.description,
454466
manufacturer: this.author,
455467
version: windowsInstallerVersion(this.installerVersion || this.version),
456-
shortcutFolderName: this.shortcutFolderName || this.author,
457468
programFilesFolderName: this.programFilesFolderName || this.productName,
458469
appUserModelId: this.bundleId,
459470
upgradeCode: this.upgradeCode,

0 commit comments

Comments
 (0)