mirror of
https://github.com/atom/atom.git
synced 2026-01-14 17:38:03 -05:00
🐛 Don't try to recover the same file twice
This commit is contained in:
@@ -65,42 +65,34 @@ describe("FileRecoveryService", () => {
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "some content")
|
||||
})
|
||||
|
||||
describe("when many windows attempt to save the same file", () => {
|
||||
it("recovers the file when the window that initiated the save crashes", () => {
|
||||
const mockWindow = {}
|
||||
const anotherMockWindow = {}
|
||||
const filePath = temp.path()
|
||||
it("restores the created recovery file when many windows attempt to save the same file and one of them crashes", () => {
|
||||
const mockWindow = {}
|
||||
const anotherMockWindow = {}
|
||||
const filePath = temp.path()
|
||||
|
||||
fs.writeFileSync(filePath, "window 1")
|
||||
recoveryService.willSavePath(mockWindow, filePath)
|
||||
fs.writeFileSync(filePath, "window 2")
|
||||
recoveryService.willSavePath(anotherMockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
fs.writeFileSync(filePath, "A")
|
||||
recoveryService.willSavePath(mockWindow, filePath)
|
||||
fs.writeFileSync(filePath, "B")
|
||||
recoveryService.willSavePath(anotherMockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
|
||||
fs.writeFileSync(filePath, "changed")
|
||||
fs.writeFileSync(filePath, "C")
|
||||
|
||||
recoveryService.didCrashWindow(mockWindow)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "window 1")
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
})
|
||||
recoveryService.didCrashWindow(mockWindow)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "A")
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
|
||||
it("recovers the file when a window that did not initiate the save crashes", () => {
|
||||
const mockWindow = {}
|
||||
const anotherMockWindow = {}
|
||||
const filePath = temp.path()
|
||||
fs.writeFileSync(filePath, "D")
|
||||
recoveryService.willSavePath(mockWindow, filePath)
|
||||
fs.writeFileSync(filePath, "E")
|
||||
recoveryService.willSavePath(anotherMockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
|
||||
fs.writeFileSync(filePath, "window 1")
|
||||
recoveryService.willSavePath(mockWindow, filePath)
|
||||
fs.writeFileSync(filePath, "window 2")
|
||||
recoveryService.willSavePath(anotherMockWindow, filePath)
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
||||
fs.writeFileSync(filePath, "F")
|
||||
|
||||
fs.writeFileSync(filePath, "changed")
|
||||
|
||||
recoveryService.didCrashWindow(anotherMockWindow)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "window 1")
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
})
|
||||
recoveryService.didCrashWindow(anotherMockWindow)
|
||||
assert.equal(fs.readFileSync(filePath, 'utf8'), "D")
|
||||
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
||||
})
|
||||
|
||||
it("emits a warning when a file can't be recovered", sinon.test(function () {
|
||||
|
||||
@@ -10,6 +10,7 @@ export default class FileRecoveryService {
|
||||
this.recoveryDirectory = recoveryDirectory
|
||||
this.recoveryFilesByFilePath = new Map()
|
||||
this.recoveryFilesByWindow = new WeakMap()
|
||||
this.windowsByRecoveryFile = new Map()
|
||||
}
|
||||
|
||||
willSavePath (window, path) {
|
||||
@@ -33,7 +34,11 @@ export default class FileRecoveryService {
|
||||
if (!this.recoveryFilesByWindow.has(window)) {
|
||||
this.recoveryFilesByWindow.set(window, new Set())
|
||||
}
|
||||
if (!this.windowsByRecoveryFile.has(recoveryFile)) {
|
||||
this.windowsByRecoveryFile.set(recoveryFile, new Set())
|
||||
}
|
||||
this.recoveryFilesByWindow.get(window).add(recoveryFile)
|
||||
this.windowsByRecoveryFile.get(recoveryFile).add(window)
|
||||
}
|
||||
|
||||
didSavePath (window, path) {
|
||||
@@ -46,6 +51,7 @@ export default class FileRecoveryService {
|
||||
}
|
||||
if (recoveryFile.isReleased()) this.recoveryFilesByFilePath.delete(path)
|
||||
this.recoveryFilesByWindow.get(window).delete(recoveryFile)
|
||||
this.windowsByRecoveryFile.get(recoveryFile).delete(window)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,19 +64,26 @@ export default class FileRecoveryService {
|
||||
} catch (error) {
|
||||
const message = 'A file that Atom was saving could be corrupted'
|
||||
const detail =
|
||||
`There was a crash while saving "${recoveryFile.originalPath}", so this file might be blank or corrupted.\n` +
|
||||
`Error ${error.code}. There was a crash while saving "${recoveryFile.originalPath}", so this file might be blank or corrupted.\n` +
|
||||
`Atom couldn't recover it automatically, but a recovery file has been saved at: "${recoveryFile.recoveryPath}".`
|
||||
console.log(detail)
|
||||
dialog.showMessageBox(window.browserWindow, {type: 'info', buttons: ['OK'], message, detail})
|
||||
} finally {
|
||||
for (let window of this.windowsByRecoveryFile.get(recoveryFile)) {
|
||||
this.recoveryFilesByWindow.get(window).delete(recoveryFile)
|
||||
}
|
||||
this.windowsByRecoveryFile.delete(recoveryFile)
|
||||
this.recoveryFilesByFilePath.delete(recoveryFile.originalPath)
|
||||
}
|
||||
}
|
||||
|
||||
this.recoveryFilesByWindow.delete(window)
|
||||
}
|
||||
|
||||
didCloseWindow (window) {
|
||||
if (!this.recoveryFilesByWindow.has(window)) return
|
||||
|
||||
for (let recoveryFile of this.recoveryFilesByWindow.get(window)) {
|
||||
this.windowsByRecoveryFile.get(recoveryFile).delete(window)
|
||||
}
|
||||
this.recoveryFilesByWindow.delete(window)
|
||||
}
|
||||
}
|
||||
@@ -96,7 +109,6 @@ class RecoveryFile {
|
||||
recoverSync () {
|
||||
fs.writeFileSync(this.originalPath, fs.readFileSync(this.recoveryPath))
|
||||
this.removeSync()
|
||||
this.refCount = 0
|
||||
}
|
||||
|
||||
removeSync () {
|
||||
|
||||
Reference in New Issue
Block a user