Don't mkdir restore dir in updater

This commit is contained in:
Fedor Indutny 2022-03-04 11:59:47 -08:00 committed by GitHub
parent effe5aae6f
commit df7cdfacc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 21 deletions

View File

@ -5,14 +5,14 @@ import { ipcRenderer } from 'electron';
import type { DialogType } from '../types/Dialogs';
import type {
UpdateDialogOptionsType,
ShowUpdateDialogAction,
ShowUpdateDialogActionType,
} from '../state/ducks/updates';
type UpdatesActions = {
showUpdateDialog: (
x: DialogType,
options: UpdateDialogOptionsType
) => ShowUpdateDialogAction;
) => ShowUpdateDialogActionType;
};
export function initializeUpdateListener(updatesActions: UpdatesActions): void {

View File

@ -3,6 +3,6 @@
import { ipcRenderer } from 'electron';
export function startUpdate(): void {
ipcRenderer.invoke('start-update');
export function startUpdate(): Promise<void> {
return ipcRenderer.invoke('start-update');
}

View File

@ -32,11 +32,11 @@ export type UpdateDialogOptionsType = {
version?: string;
};
type DismissDialogAction = {
type DismissDialogActionType = {
type: typeof DISMISS_DIALOG;
};
export type ShowUpdateDialogAction = {
export type ShowUpdateDialogActionType = {
type: typeof SHOW_UPDATE_DIALOG;
payload: {
dialogType: DialogType;
@ -48,7 +48,7 @@ type SnoozeUpdateActionType = {
type: typeof SNOOZE_UPDATE;
};
type StartUpdateAction = {
type StartUpdateActionType = {
type: typeof START_UPDATE;
};
@ -58,15 +58,15 @@ type UnsnoozeUpdateActionType = {
};
export type UpdatesActionType =
| DismissDialogAction
| ShowUpdateDialogAction
| DismissDialogActionType
| ShowUpdateDialogActionType
| SnoozeUpdateActionType
| StartUpdateAction
| StartUpdateActionType
| UnsnoozeUpdateActionType;
// Action Creators
function dismissDialog(): DismissDialogAction {
function dismissDialog(): DismissDialogActionType {
return {
type: DISMISS_DIALOG,
};
@ -75,7 +75,7 @@ function dismissDialog(): DismissDialogAction {
function showUpdateDialog(
dialogType: DialogType,
updateDialogOptions: UpdateDialogOptionsType = {}
): ShowUpdateDialogAction {
): ShowUpdateDialogActionType {
return {
type: SHOW_UPDATE_DIALOG,
payload: {
@ -106,11 +106,28 @@ function snoozeUpdate(): ThunkAction<
};
}
function startUpdate(): StartUpdateAction {
updateIpc.startUpdate();
function startUpdate(): ThunkAction<
void,
RootStateType,
unknown,
StartUpdateActionType | ShowUpdateDialogActionType
> {
return async dispatch => {
dispatch({
type: START_UPDATE,
});
return {
type: START_UPDATE,
try {
await updateIpc.startUpdate();
} catch (_) {
dispatch({
type: SHOW_UPDATE_DIALOG,
payload: {
dialogType: DialogType.Cannot_Update,
otherState: {},
},
});
}
};
}

View File

@ -2,6 +2,9 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { pathExists } from 'fs-extra';
import { stat, mkdir } from 'fs/promises';
import { join } from 'path';
import {
createUpdateCacheDirIfNeeded,
@ -10,6 +13,9 @@ import {
isUpdateFileNameValid,
validatePath,
parseYaml,
createTempDir,
getTempDir,
deleteTempDir,
} from '../../updater/common';
describe('updater/signatures', () => {
@ -152,4 +158,32 @@ releaseDate: '2021-12-03T19:00:23.754Z'
});
});
});
describe('createTempDir', () => {
it('creates a temporary directory', async () => {
const dir = await createTempDir();
assert.isTrue((await stat(dir)).isDirectory());
await deleteTempDir(dir);
assert.isFalse(await pathExists(dir), 'Directory should be deleted');
});
});
describe('getTempDir', () => {
it('reserves a temporary directory', async () => {
const dir = await getTempDir();
assert.isTrue(
(await stat(join(dir, '..'))).isDirectory(),
'Parent folder should exist'
);
assert.isFalse(await pathExists(dir), 'Reserved folder should not exist');
await mkdir(dir);
await deleteTempDir(dir);
assert.isFalse(await pathExists(dir), 'Directory should be deleted');
});
});
});

View File

@ -446,7 +446,6 @@ export abstract class Updater {
const targetUpdatePath = join(cacheDir, fileName);
const tempDir = await createTempDir();
const restoreDir = await createTempDir();
const tempUpdatePath = join(tempDir, fileName);
const tempBlockMapPath = join(tempDir, blockMapFileName);
@ -556,7 +555,12 @@ export abstract class Updater {
return undefined;
}
this.logger.info(
'downloadUpdate: Downloaded update, moving into cache dir'
);
// Backup old files
const restoreDir = await getTempDir();
await rename(cacheDir, restoreDir);
// Move the files into the final position
@ -569,9 +573,18 @@ export abstract class Updater {
throw error;
}
try {
await deleteTempDir(restoreDir);
} catch (error) {
this.logger.warn(
'downloadUpdate: Failed to remove backup folder, ignoring',
Errors.toLogFormat(error)
);
}
return { updateFilePath: targetUpdatePath, signature };
} finally {
await Promise.all([deleteTempDir(tempDir), deleteTempDir(restoreDir)]);
await deleteTempDir(tempDir);
}
}
@ -781,14 +794,25 @@ function getBaseTempDir() {
}
export async function createTempDir(): Promise<string> {
const baseTempDir = getBaseTempDir();
const uniqueName = getGuid();
const targetDir = join(baseTempDir, uniqueName);
const targetDir = await getTempDir();
await mkdirpPromise(targetDir);
return targetDir;
}
export async function getTempDir(): Promise<string> {
const baseTempDir = getBaseTempDir();
const uniqueName = getGuid();
// Create parent folder if not already present
if (!(await pathExists(baseTempDir))) {
await mkdirpPromise(baseTempDir);
}
return join(baseTempDir, uniqueName);
}
function getUpdateCacheDir() {
// We only use tmpdir() when this code is run outside of an Electron app (as in: tests)
return app ? getUpdateCachePath(app.getPath('userData')) : tmpdir();