mirror of
https://github.com/Microsoft/vscode
synced 2024-10-30 03:25:38 +00:00
backups - ensure to discard all on shutdown without dirty (#92962)
This commit is contained in:
parent
92b9e7f53e
commit
52fe5f21f5
5 changed files with 70 additions and 2 deletions
|
@ -47,7 +47,8 @@ export class NativeBackupTracker extends BackupTracker implements IWorkbenchCont
|
|||
return this.onBeforeShutdownWithDirty(reason, dirtyWorkingCopies);
|
||||
}
|
||||
|
||||
return false; // no veto (no dirty working copies)
|
||||
// No dirty working copies
|
||||
return this.onBeforeShutdownWithoutDirty();
|
||||
}
|
||||
|
||||
protected async onBeforeShutdownWithDirty(reason: ShutdownReason, workingCopies: IWorkingCopy[]): Promise<boolean> {
|
||||
|
@ -253,4 +254,21 @@ export class NativeBackupTracker extends BackupTracker implements IWorkbenchCont
|
|||
|
||||
return Promise.all(backupsToDiscard.map(workingCopy => this.backupFileService.discardBackup(workingCopy.resource))).then(() => false, () => false);
|
||||
}
|
||||
|
||||
private async onBeforeShutdownWithoutDirty(): Promise<boolean> {
|
||||
// If we have proceeded enough that editors and dirty state
|
||||
// has restored, we make sure that no backups lure around
|
||||
// given we have no known dirty working copy. This helps
|
||||
// to clean up stale backups as for example reported in
|
||||
// https://github.com/microsoft/vscode/issues/92962
|
||||
if (this.lifecycleService.phase >= LifecyclePhase.Restored) {
|
||||
try {
|
||||
await this.backupFileService.discardBackups();
|
||||
} catch (error) {
|
||||
this.logService.error(`[backup tracker] error discarding backups: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,9 +63,14 @@ export interface IBackupFileService {
|
|||
backup<T extends object>(resource: URI, content?: ITextSnapshot, versionId?: number, meta?: T): Promise<void>;
|
||||
|
||||
/**
|
||||
* Discards the backup associated with a resource if it exists..
|
||||
* Discards the backup associated with a resource if it exists.
|
||||
*
|
||||
* @param resource The resource whose backup is being discarded discard to back up.
|
||||
*/
|
||||
discardBackup(resource: URI): Promise<void>;
|
||||
|
||||
/**
|
||||
* Discards all backups.
|
||||
*/
|
||||
discardBackups(): Promise<void>;
|
||||
}
|
||||
|
|
|
@ -165,6 +165,10 @@ export class BackupFileService implements IBackupFileService {
|
|||
return this.impl.discardBackup(resource);
|
||||
}
|
||||
|
||||
discardBackups(): Promise<void> {
|
||||
return this.impl.discardBackups();
|
||||
}
|
||||
|
||||
getBackups(): Promise<URI[]> {
|
||||
return this.impl.getBackups();
|
||||
}
|
||||
|
@ -260,6 +264,14 @@ class BackupFileServiceImpl extends Disposable implements IBackupFileService {
|
|||
});
|
||||
}
|
||||
|
||||
async discardBackups(): Promise<void> {
|
||||
const model = await this.ready;
|
||||
|
||||
await this.deleteIgnoreFileNotFound(this.backupWorkspacePath);
|
||||
|
||||
model.clear();
|
||||
}
|
||||
|
||||
discardBackup(resource: URI): Promise<void> {
|
||||
const backupResource = this.toBackupResource(resource);
|
||||
|
||||
|
@ -429,6 +441,10 @@ export class InMemoryBackupFileService implements IBackupFileService {
|
|||
this.backups.delete(this.toBackupResource(resource).toString());
|
||||
}
|
||||
|
||||
async discardBackups(): Promise<void> {
|
||||
this.backups.clear();
|
||||
}
|
||||
|
||||
toBackupResource(resource: URI): URI {
|
||||
return URI.file(join(resource.scheme, this.hashPath(resource)));
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ const barFile = URI.file(platform.isWindows ? 'c:\\Bar' : '/Bar');
|
|||
const fooBarFile = URI.file(platform.isWindows ? 'c:\\Foo Bar' : '/Foo Bar');
|
||||
const untitledFile = URI.from({ scheme: Schemas.untitled, path: 'Untitled-1' });
|
||||
const fooBackupPath = path.join(workspaceBackupPath, 'file', hashPath(fooFile));
|
||||
const barBackupPath = path.join(workspaceBackupPath, 'file', hashPath(barFile));
|
||||
const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(untitledFile));
|
||||
|
||||
class TestBackupEnvironmentService extends NativeWorkbenchEnvironmentService {
|
||||
|
@ -285,6 +286,33 @@ suite('BackupFileService', () => {
|
|||
});
|
||||
});
|
||||
|
||||
suite('discardBackups', () => {
|
||||
test('text file', async () => {
|
||||
await service.backup(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false));
|
||||
assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
|
||||
await service.backup(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false));
|
||||
assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2);
|
||||
await service.discardBackups();
|
||||
assert.equal(fs.existsSync(fooBackupPath), false);
|
||||
assert.equal(fs.existsSync(barBackupPath), false);
|
||||
assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'file')), false);
|
||||
});
|
||||
|
||||
test('untitled file', async () => {
|
||||
await service.backup(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false));
|
||||
assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
|
||||
await service.discardBackups();
|
||||
assert.equal(fs.existsSync(untitledBackupPath), false);
|
||||
assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'untitled')), false);
|
||||
});
|
||||
|
||||
test('can backup after discarding all', async () => {
|
||||
await service.discardBackups();
|
||||
await service.backup(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false));
|
||||
assert.equal(fs.existsSync(workspaceBackupPath), true);
|
||||
});
|
||||
});
|
||||
|
||||
suite('getBackups', () => {
|
||||
test('("file") - text file', async () => {
|
||||
await service.backup(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false));
|
||||
|
|
|
@ -811,6 +811,7 @@ export class TestBackupFileService implements IBackupFileService {
|
|||
getBackups(): Promise<URI[]> { return Promise.resolve([]); }
|
||||
resolve<T extends object>(_backup: URI): Promise<IResolvedBackup<T> | undefined> { return Promise.resolve(undefined); }
|
||||
discardBackup(_resource: URI): Promise<void> { return Promise.resolve(); }
|
||||
discardBackups(): Promise<void> { return Promise.resolve(); }
|
||||
parseBackupContent(textBufferFactory: ITextBufferFactory): string {
|
||||
const textBuffer = textBufferFactory.create(DefaultEndOfLine.LF);
|
||||
const lineCount = textBuffer.getLineCount();
|
||||
|
|
Loading…
Reference in a new issue