Don't mkdir restore dir in updater
This commit is contained in:
parent
effe5aae6f
commit
df7cdfacc7
5 changed files with 96 additions and 21 deletions
|
@ -5,14 +5,14 @@ import { ipcRenderer } from 'electron';
|
||||||
import type { DialogType } from '../types/Dialogs';
|
import type { DialogType } from '../types/Dialogs';
|
||||||
import type {
|
import type {
|
||||||
UpdateDialogOptionsType,
|
UpdateDialogOptionsType,
|
||||||
ShowUpdateDialogAction,
|
ShowUpdateDialogActionType,
|
||||||
} from '../state/ducks/updates';
|
} from '../state/ducks/updates';
|
||||||
|
|
||||||
type UpdatesActions = {
|
type UpdatesActions = {
|
||||||
showUpdateDialog: (
|
showUpdateDialog: (
|
||||||
x: DialogType,
|
x: DialogType,
|
||||||
options: UpdateDialogOptionsType
|
options: UpdateDialogOptionsType
|
||||||
) => ShowUpdateDialogAction;
|
) => ShowUpdateDialogActionType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function initializeUpdateListener(updatesActions: UpdatesActions): void {
|
export function initializeUpdateListener(updatesActions: UpdatesActions): void {
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
|
|
||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
|
|
||||||
export function startUpdate(): void {
|
export function startUpdate(): Promise<void> {
|
||||||
ipcRenderer.invoke('start-update');
|
return ipcRenderer.invoke('start-update');
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,11 +32,11 @@ export type UpdateDialogOptionsType = {
|
||||||
version?: string;
|
version?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DismissDialogAction = {
|
type DismissDialogActionType = {
|
||||||
type: typeof DISMISS_DIALOG;
|
type: typeof DISMISS_DIALOG;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ShowUpdateDialogAction = {
|
export type ShowUpdateDialogActionType = {
|
||||||
type: typeof SHOW_UPDATE_DIALOG;
|
type: typeof SHOW_UPDATE_DIALOG;
|
||||||
payload: {
|
payload: {
|
||||||
dialogType: DialogType;
|
dialogType: DialogType;
|
||||||
|
@ -48,7 +48,7 @@ type SnoozeUpdateActionType = {
|
||||||
type: typeof SNOOZE_UPDATE;
|
type: typeof SNOOZE_UPDATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StartUpdateAction = {
|
type StartUpdateActionType = {
|
||||||
type: typeof START_UPDATE;
|
type: typeof START_UPDATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,15 +58,15 @@ type UnsnoozeUpdateActionType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdatesActionType =
|
export type UpdatesActionType =
|
||||||
| DismissDialogAction
|
| DismissDialogActionType
|
||||||
| ShowUpdateDialogAction
|
| ShowUpdateDialogActionType
|
||||||
| SnoozeUpdateActionType
|
| SnoozeUpdateActionType
|
||||||
| StartUpdateAction
|
| StartUpdateActionType
|
||||||
| UnsnoozeUpdateActionType;
|
| UnsnoozeUpdateActionType;
|
||||||
|
|
||||||
// Action Creators
|
// Action Creators
|
||||||
|
|
||||||
function dismissDialog(): DismissDialogAction {
|
function dismissDialog(): DismissDialogActionType {
|
||||||
return {
|
return {
|
||||||
type: DISMISS_DIALOG,
|
type: DISMISS_DIALOG,
|
||||||
};
|
};
|
||||||
|
@ -75,7 +75,7 @@ function dismissDialog(): DismissDialogAction {
|
||||||
function showUpdateDialog(
|
function showUpdateDialog(
|
||||||
dialogType: DialogType,
|
dialogType: DialogType,
|
||||||
updateDialogOptions: UpdateDialogOptionsType = {}
|
updateDialogOptions: UpdateDialogOptionsType = {}
|
||||||
): ShowUpdateDialogAction {
|
): ShowUpdateDialogActionType {
|
||||||
return {
|
return {
|
||||||
type: SHOW_UPDATE_DIALOG,
|
type: SHOW_UPDATE_DIALOG,
|
||||||
payload: {
|
payload: {
|
||||||
|
@ -106,11 +106,28 @@ function snoozeUpdate(): ThunkAction<
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function startUpdate(): StartUpdateAction {
|
function startUpdate(): ThunkAction<
|
||||||
updateIpc.startUpdate();
|
void,
|
||||||
|
RootStateType,
|
||||||
return {
|
unknown,
|
||||||
|
StartUpdateActionType | ShowUpdateDialogActionType
|
||||||
|
> {
|
||||||
|
return async dispatch => {
|
||||||
|
dispatch({
|
||||||
type: START_UPDATE,
|
type: START_UPDATE,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateIpc.startUpdate();
|
||||||
|
} catch (_) {
|
||||||
|
dispatch({
|
||||||
|
type: SHOW_UPDATE_DIALOG,
|
||||||
|
payload: {
|
||||||
|
dialogType: DialogType.Cannot_Update,
|
||||||
|
otherState: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
|
import { pathExists } from 'fs-extra';
|
||||||
|
import { stat, mkdir } from 'fs/promises';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createUpdateCacheDirIfNeeded,
|
createUpdateCacheDirIfNeeded,
|
||||||
|
@ -10,6 +13,9 @@ import {
|
||||||
isUpdateFileNameValid,
|
isUpdateFileNameValid,
|
||||||
validatePath,
|
validatePath,
|
||||||
parseYaml,
|
parseYaml,
|
||||||
|
createTempDir,
|
||||||
|
getTempDir,
|
||||||
|
deleteTempDir,
|
||||||
} from '../../updater/common';
|
} from '../../updater/common';
|
||||||
|
|
||||||
describe('updater/signatures', () => {
|
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');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -446,7 +446,6 @@ export abstract class Updater {
|
||||||
const targetUpdatePath = join(cacheDir, fileName);
|
const targetUpdatePath = join(cacheDir, fileName);
|
||||||
|
|
||||||
const tempDir = await createTempDir();
|
const tempDir = await createTempDir();
|
||||||
const restoreDir = await createTempDir();
|
|
||||||
|
|
||||||
const tempUpdatePath = join(tempDir, fileName);
|
const tempUpdatePath = join(tempDir, fileName);
|
||||||
const tempBlockMapPath = join(tempDir, blockMapFileName);
|
const tempBlockMapPath = join(tempDir, blockMapFileName);
|
||||||
|
@ -556,7 +555,12 @@ export abstract class Updater {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logger.info(
|
||||||
|
'downloadUpdate: Downloaded update, moving into cache dir'
|
||||||
|
);
|
||||||
|
|
||||||
// Backup old files
|
// Backup old files
|
||||||
|
const restoreDir = await getTempDir();
|
||||||
await rename(cacheDir, restoreDir);
|
await rename(cacheDir, restoreDir);
|
||||||
|
|
||||||
// Move the files into the final position
|
// Move the files into the final position
|
||||||
|
@ -569,9 +573,18 @@ export abstract class Updater {
|
||||||
throw error;
|
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 };
|
return { updateFilePath: targetUpdatePath, signature };
|
||||||
} finally {
|
} finally {
|
||||||
await Promise.all([deleteTempDir(tempDir), deleteTempDir(restoreDir)]);
|
await deleteTempDir(tempDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,14 +794,25 @@ function getBaseTempDir() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createTempDir(): Promise<string> {
|
export async function createTempDir(): Promise<string> {
|
||||||
const baseTempDir = getBaseTempDir();
|
const targetDir = await getTempDir();
|
||||||
const uniqueName = getGuid();
|
|
||||||
const targetDir = join(baseTempDir, uniqueName);
|
|
||||||
await mkdirpPromise(targetDir);
|
await mkdirpPromise(targetDir);
|
||||||
|
|
||||||
return 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() {
|
function getUpdateCacheDir() {
|
||||||
// We only use tmpdir() when this code is run outside of an Electron app (as in: tests)
|
// We only use tmpdir() when this code is run outside of an Electron app (as in: tests)
|
||||||
return app ? getUpdateCachePath(app.getPath('userData')) : tmpdir();
|
return app ? getUpdateCachePath(app.getPath('userData')) : tmpdir();
|
||||||
|
|
Loading…
Reference in a new issue