 Chromium Code Reviews
 Chromium Code Reviews Issue 2542073002:
  DevTools: [Persistence] validate persistence binding.  (Closed)
    
  
    Issue 2542073002:
  DevTools: [Persistence] validate persistence binding.  (Closed) 
  | Index: third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js | 
| diff --git a/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js b/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js | 
| index a67fd69013a738f2c74b04e11dd477ea68d948c7..09adad84d5e5254c64db5994052b3be98e20650d 100644 | 
| --- a/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js | 
| +++ b/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js | 
| @@ -32,19 +32,71 @@ Persistence.Persistence = class extends Common.Object { | 
| * @param {!Persistence.PersistenceBinding} binding | 
| */ | 
| _onBindingCreated(binding) { | 
| - if (binding.network.isDirty()) { | 
| - Common.console.log( | 
| - Common.UIString('%s can not be persisted to file system due to unsaved changes.', binding.network.name())); | 
| + if (!binding.network.contentLoaded() && !binding.fileSystem.contentLoaded() && !binding.network.isDirty() && | 
| + !binding.fileSystem.isDirty()) { | 
| + this._establishBinding(binding); | 
| return; | 
| } | 
| - if (binding.fileSystem.isDirty()) | 
| - binding.network.setWorkingCopy(binding.fileSystem.workingCopy()); | 
| + if (binding[Persistence.Persistence._prevalidatePromise]) | 
| + return; | 
| + var promise = this._validateBinding(binding).then(onBindingValidated.bind(this)); | 
| + binding[Persistence.Persistence._prevalidatePromise] = promise; | 
| + | 
| + /** | 
| + * @this {Persistence.Persistence} | 
| + */ | 
| + function onBindingValidated(isValid) { | 
| 
dgozman
2016/12/07 01:45:41
@param
 | 
| + if (binding[Persistence.Persistence._prevalidatePromise] !== promise) | 
| + return; | 
| + binding[Persistence.Persistence._prevalidatePromise] = null; | 
| + | 
| + if (isValid) | 
| + this._establishBinding(binding); | 
| + else | 
| + this._prevalidationFailedForTest(binding); | 
| + } | 
| + } | 
| + | 
| + /** | 
| + * @param {!Persistence.PersistenceBinding} binding | 
| + */ | 
| + _prevalidationFailedForTest(binding) { | 
| + } | 
| + | 
| + /** | 
| + * @param {!Persistence.PersistenceBinding} binding | 
| 
dgozman
2016/12/07 01:45:41
@return promise.....
 | 
| + */ | 
| + _validateBinding(binding) { | 
| + return Promise.all([binding.network.requestContent(), binding.fileSystem.requestContent()]).then(onContentsLoaded); | 
| + | 
| + function onContentsLoaded() { | 
| 
dgozman
2016/12/07 01:45:41
@return boolean
 | 
| + var target = Bindings.NetworkProject.targetForUISourceCode(binding.network); | 
| + if (target.isNodeJS()) { | 
| + var fileSystemContent = binding.fileSystem.workingCopy(); | 
| + var networkContent = binding.network.workingCopy(); | 
| + var rewrappedNetworkContent = Persistence.Persistence._rewrapNodeJSContent( | 
| + binding, binding.fileSystem, fileSystemContent, networkContent); | 
| + return fileSystemContent === rewrappedNetworkContent; | 
| + } | 
| + // Trim trailing whitespaces because V8 adds trailing newline. | 
| + var fileSystemContent = binding.fileSystem.workingCopy().replace(/\s*$/, ''); | 
| 
dgozman
2016/12/07 01:45:41
.trimRight()
 | 
| + var networkContent = binding.network.workingCopy().replace(/\s*$/, ''); | 
| + return fileSystemContent === networkContent; | 
| + } | 
| + } | 
| + | 
| + /** | 
| + * @param {!Persistence.PersistenceBinding} binding | 
| + */ | 
| + _establishBinding(binding) { | 
| binding.network[Persistence.Persistence._binding] = binding; | 
| binding.fileSystem[Persistence.Persistence._binding] = binding; | 
| binding.fileSystem.forceLoadOnCheckContent(); | 
| + binding.network.addEventListener(Workspace.UISourceCode.Events.ContentLoaded, this._onContentLoaded, this); | 
| + binding.fileSystem.addEventListener(Workspace.UISourceCode.Events.ContentLoaded, this._onContentLoaded, this); | 
| binding.network.addEventListener( | 
| Workspace.UISourceCode.Events.WorkingCopyCommitted, this._onWorkingCopyCommitted, this); | 
| binding.fileSystem.addEventListener( | 
| @@ -64,9 +116,19 @@ Persistence.Persistence = class extends Common.Object { | 
| * @param {!Persistence.PersistenceBinding} binding | 
| */ | 
| _onBindingRemoved(binding) { | 
| + binding[Persistence.Persistence._postvalidatePromise] = null; | 
| + if (binding[Persistence.Persistence._prevalidatePromise]) { | 
| + binding[Persistence.Persistence._prevalidatePromise] = null; | 
| + return; | 
| 
dgozman
2016/12/07 01:45:41
Drop this return, and the if.
 | 
| + } | 
| + if (!binding.network[Persistence.Persistence._binding] || !binding.fileSystem[Persistence.Persistence._binding]) | 
| + return; | 
| + | 
| binding.network[Persistence.Persistence._binding] = null; | 
| binding.fileSystem[Persistence.Persistence._binding] = null; | 
| + binding.network.removeEventListener(Workspace.UISourceCode.Events.ContentLoaded, this._onContentLoaded, this); | 
| + binding.fileSystem.removeEventListener(Workspace.UISourceCode.Events.ContentLoaded, this._onContentLoaded, this); | 
| binding.network.removeEventListener( | 
| Workspace.UISourceCode.Events.WorkingCopyCommitted, this._onWorkingCopyCommitted, this); | 
| binding.fileSystem.removeEventListener( | 
| @@ -85,6 +147,29 @@ Persistence.Persistence = class extends Common.Object { | 
| /** | 
| * @param {!Common.Event} event | 
| */ | 
| + _onContentLoaded(event) { | 
| + var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.target); | 
| + var binding = uiSourceCode[Persistence.Persistence._binding]; | 
| + if (!binding || binding[Persistence.Persistence._postvalidatePromise]) | 
| + return; | 
| + var promise = this._validateBinding(binding).then(onBindingValidated.bind(this)); | 
| + binding[Persistence.Persistence._postvalidatePromise] = promise; | 
| + | 
| + /** | 
| + * @this {Persistence.Persistence} | 
| + */ | 
| + function onBindingValidated(isValid) { | 
| + if (binding[Persistence.Persistence._postvalidatePromise] !== promise) | 
| + return; | 
| + binding[Persistence.Persistence._postvalidatePromise] = null; | 
| + if (!isValid) | 
| + this._onBindingRemoved(binding); | 
| + } | 
| + } | 
| + | 
| + /** | 
| + * @param {!Common.Event} event | 
| + */ | 
| _onWorkingCopyChanged(event) { | 
| var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.target); | 
| var binding = uiSourceCode[Persistence.Persistence._binding]; | 
| @@ -95,7 +180,8 @@ Persistence.Persistence = class extends Common.Object { | 
| if (target.isNodeJS()) { | 
| var newContent = uiSourceCode.workingCopy(); | 
| other.requestContent().then(() => { | 
| - var nodeJSContent = this._rewrapNodeJSContent(binding, other, other.workingCopy(), newContent); | 
| + var nodeJSContent = | 
| + Persistence.Persistence._rewrapNodeJSContent(binding, other, other.workingCopy(), newContent); | 
| setWorkingCopy.call(this, () => nodeJSContent); | 
| }); | 
| return; | 
| @@ -128,7 +214,7 @@ Persistence.Persistence = class extends Common.Object { | 
| var target = Bindings.NetworkProject.targetForUISourceCode(binding.network); | 
| if (target.isNodeJS()) { | 
| other.requestContent().then(currentContent => { | 
| - var nodeJSContent = this._rewrapNodeJSContent(binding, other, currentContent, newContent); | 
| + var nodeJSContent = Persistence.Persistence._rewrapNodeJSContent(binding, other, currentContent, newContent); | 
| setContent.call(this, nodeJSContent); | 
| }); | 
| return; | 
| @@ -154,7 +240,7 @@ Persistence.Persistence = class extends Common.Object { | 
| * @param {string} newContent | 
| * @return {string} | 
| */ | 
| - _rewrapNodeJSContent(binding, uiSourceCode, currentContent, newContent) { | 
| + static _rewrapNodeJSContent(binding, uiSourceCode, currentContent, newContent) { | 
| if (uiSourceCode === binding.fileSystem) { | 
| if (newContent.startsWith(Persistence.Persistence._NodePrefix) && | 
| newContent.endsWith(Persistence.Persistence._NodeSuffix)) { | 
| @@ -293,5 +379,8 @@ Persistence.PersistenceBinding = class { | 
| } | 
| }; | 
| +Persistence.Persistence._prevalidatePromise = Symbol('Persistence.prevalidatePromise'); | 
| 
dgozman
2016/12/07 01:45:41
Let's have private fields instead.
 | 
| +Persistence.Persistence._postvalidatePromise = Symbol('Persistence.postvalidatePromise'); | 
| + | 
| /** @type {!Persistence.Persistence} */ | 
| Persistence.persistence; |