Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(updates): Rework update mechanism #1827

Merged
merged 1 commit into from Mar 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 0 additions & 19 deletions packages/main/src/index.ts
Expand Up @@ -27,25 +27,6 @@ import { StartupInstall } from './system/startup-install';

export const UPDATER_UPDATE_AVAILABLE_ICON = 'fa fa-exclamation-triangle';

// Check for updates when initially ready as well as set a 6 hour interval for any checks
if (import.meta.env.PROD) {
import('electron-updater').then(({ autoUpdater }) => {
app
.whenReady()
.then(() => {
// Check for updates on startup
autoUpdater.checkForUpdatesAndNotify();

// Create an interval to check for updates every 12 hours / notify the user
setInterval(() => {
autoUpdater.checkForUpdatesAndNotify();
// check every 12 hours
}, 1000 * 60 * 60 * 12);
})
.catch(e => console.error('Failed to start auto-updater:', e));
});
}

/**
* Prevent multiple instances
*/
Expand Down
14 changes: 14 additions & 0 deletions packages/main/src/mainWindow.ts
Expand Up @@ -17,6 +17,7 @@
***********************************************************************/

import type { BrowserWindowConstructorOptions, FileFilter } from 'electron';
import { autoUpdater } from 'electron';
import { Menu } from 'electron';
import { BrowserWindow, ipcMain, app, dialog, screen, nativeTheme } from 'electron';
import contextMenu from 'electron-context-menu';
Expand Down Expand Up @@ -119,7 +120,20 @@ async function createWindow() {
configurationRegistry = data;
});

// receive the message because an update is in progress and we need to quit the app
let quitAfterUpdate = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
autoUpdater.on('before-quit-for-update', () => {
quitAfterUpdate = true;
});

browserWindow.on('close', e => {
if (quitAfterUpdate) {
browserWindow.destroy();
app.quit();
return;
}

const closeBehaviorConfiguration = configurationRegistry?.getConfiguration('preferences');
let exitonclose = isLinux(); // default value, which we will use unless the user preference is available.
if (closeBehaviorConfiguration) {
Expand Down
196 changes: 140 additions & 56 deletions packages/main/src/plugin/index.ts
Expand Up @@ -90,6 +90,8 @@ import { InputQuickPickRegistry } from './input-quickpick/input-quickpick-regist
import type { Menu } from '/@/plugin/menu-registry';
import { MenuRegistry } from '/@/plugin/menu-registry';
import { CancellationTokenRegistry } from './cancellation-token-registry';
import type { UpdateCheckResult } from 'electron-updater';
import { autoUpdater } from 'electron-updater';

type LogType = 'log' | 'warn' | 'trace' | 'debug' | 'error';

Expand Down Expand Up @@ -337,17 +339,20 @@ export class PluginSystem {
const currentVersion = `v${app.getVersion()}`;

// Add version entry to the status bar
statusBarRegistry.setEntry(
'version',
false,
0,
currentVersion,
`Using version ${currentVersion}`,
undefined,
true,
'version',
undefined,
);
const defaultVersionEntry = () => {
statusBarRegistry.setEntry(
'version',
false,
0,
currentVersion,
`Using version ${currentVersion}`,
undefined,
true,
'version',
undefined,
);
};
defaultVersionEntry();

// Show a "No update available" only for macOS and Windows users and on production builds
let detailMessage: string;
Expand All @@ -366,55 +371,134 @@ export class PluginSystem {
});
});

if (import.meta.env.PROD) {
// Only import on production builds
import('electron-updater').then(({ autoUpdater }) => {
// autoUpdater.checkForUpdatesAndNotify() is called from main/src/index.ts
autoUpdater.on('update-available', () => {
// Update the 'version' entry in the status bar to show that an update is available
// this uses setEntry to update the existing entry
statusBarRegistry.setEntry(
'version',
false,
0,
currentVersion,
'Update available',
UPDATER_UPDATE_AVAILABLE_ICON,
true,
'update',
undefined,
);
// Only check on production builds for Windows and macOS users
if (import.meta.env.PROD && !isLinux()) {
// disable auto download
autoUpdater.autoDownload = false;

let updateInProgress = false;
let updateAlreadyDownloaded = false;

// setup the event listeners
autoUpdater.on('update-available', () => {
updateInProgress = false;
updateAlreadyDownloaded = false;

// Update the 'version' entry in the status bar to show that an update is available
// this uses setEntry to update the existing entry
statusBarRegistry.setEntry(
'version',
false,
0,
currentVersion,
'Update available',
UPDATER_UPDATE_AVAILABLE_ICON,
true,
'update',
undefined,
);
});

autoUpdater.on('update-not-available', () => {
updateInProgress = false;
updateAlreadyDownloaded = false;

// Update the 'version' entry in the status bar to show that no update is available
defaultVersionEntry();
});

autoUpdater.on('update-downloaded', async () => {
updateAlreadyDownloaded = true;
updateInProgress = false;
const result = await dialog.showMessageBox({
title: 'Update Downloaded',
message: 'Update downloaded, Do you want to restart Podman Desktop ?',
cancelId: 1,
type: 'info',
buttons: ['Restart', 'Cancel'],
});
if (result.response === 0) {
setImmediate(() => autoUpdater.quitAndInstall());
}
});

autoUpdater.on('error', error => {
console.error('unable to check for updates', error);
updateInProgress = false;
dialog.showErrorBox('Error: ', error == null ? 'unknown' : (error.stack || error).toString());
});

// check for updates now
let updateCheckResult: UpdateCheckResult | null;

// Update will create the standard "autoUpdater" dialog / update process that Electron provides
commandRegistry.registerCommand('update', () => {
autoUpdater.checkForUpdates().then(update => {
// Get the version of the update
const updateVersion = update?.updateInfo.version ? `v${update?.updateInfo.version}` : '';

dialog
.showMessageBox({
type: 'info',
title: 'Update Available',
message: `A new version ${updateVersion} of Podman Desktop is available. Do you want to update your current version ${currentVersion}?`,
buttons: ['Update', 'Later'],
})
.then(result => {
if (result.response === 0) {
// Download update and try / catch it and create a dialog if it fails
autoUpdater.downloadUpdate().catch(error => {
console.error('Update error: ', error);
dialog.showMessageBox({
type: 'error',
title: 'Update Failed',
message: `An error occurred while trying to update to version ${updateVersion}. See the developer console for more information.`,
buttons: ['OK'],
});
});
}
});
try {
updateCheckResult = await autoUpdater.checkForUpdates();
} catch (error) {
console.error('unable to check for updates', error);
}

// Create an interval to check for updates every 12 hours
setInterval(async () => {
try {
updateCheckResult = await autoUpdater.checkForUpdates();
} catch (error) {
console.log('unable to check for updates', error);
}
}, 1000 * 60 * 60 * 12);

// Update will create the standard "autoUpdater" dialog / update process that Electron provides
commandRegistry.registerCommand('update', async () => {
if (updateAlreadyDownloaded) {
const result = await dialog.showMessageBox({
type: 'info',
title: 'Update',
message: 'There is already an update downloaded. Please Restart Podman Desktop.',
cancelId: 1,
buttons: ['Restart', 'Cancel'],
});
if (result.response === 0) {
setImmediate(() => autoUpdater.quitAndInstall());
}
return;
}

if (updateInProgress) {
await dialog.showMessageBox({
type: 'info',
title: 'Update',
message: 'There is already an update in progress. Please wait until it is downloaded',
buttons: ['OK'],
});
return;
}

// Get the version of the update
const updateVersion = updateCheckResult?.updateInfo.version ? `v${updateCheckResult?.updateInfo.version}` : '';

const result = await dialog.showMessageBox({
type: 'info',
title: 'Update Available',
message: `A new version ${updateVersion} of Podman Desktop is available. Do you want to update your current version ${currentVersion}?`,
buttons: ['Update', 'Cancel'],
cancelId: 1,
});
if (result.response === 0) {
updateInProgress = true;
updateAlreadyDownloaded = false;

// Download update and try / catch it and create a dialog if it fails
try {
await autoUpdater.downloadUpdate();
} catch (error) {
console.error('Update error: ', error);
dialog.showMessageBox({
type: 'error',
title: 'Update Failed',
message: `An error occurred while trying to update to version ${updateVersion}. See the developer console for more information.`,
buttons: ['OK'],
});
}
}
});
}

Expand Down