Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit 118d816

Browse files
committed
Merge pull request #7930 from adobe/randy/issue-7683
Determine when all prefs have been written to disk
2 parents 5f327ef + 404810e commit 118d816

3 files changed

Lines changed: 78 additions & 15 deletions

File tree

src/document/DocumentCommandHandlers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1280,7 +1280,7 @@ define(function (require, exports, module) {
12801280

12811281
PreferencesManager.savePreferences();
12821282

1283-
postCloseHandler();
1283+
PreferencesManager.finalize().always(postCloseHandler);
12841284
})
12851285
.fail(function () {
12861286
_windowGoingAway = false;

src/preferences/PreferencesBase.js

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ define(function (require, exports, module) {
7575
*/
7676

7777
/**
78+
* @constructor
7879
* MemoryStorage, as the name implies, stores the preferences in memory.
7980
* This is suitable for single session data or testing.
8081
*
@@ -93,7 +94,7 @@ define(function (require, exports, module) {
9394
* @return {Promise} promise that is already resolved
9495
*/
9596
load: function () {
96-
var result = $.Deferred();
97+
var result = new $.Deferred();
9798
result.resolve(this.data);
9899
return result.promise();
99100
},
@@ -106,7 +107,7 @@ define(function (require, exports, module) {
106107
* @return {Promise} promise that is already resolved
107108
*/
108109
save: function (newData) {
109-
var result = $.Deferred();
110+
var result = new $.Deferred();
110111
this.data = newData;
111112
result.resolve();
112113
return result.promise();
@@ -122,6 +123,7 @@ define(function (require, exports, module) {
122123
};
123124

124125
/**
126+
* @constructor
125127
* Error type for problems parsing preference files.
126128
*
127129
* @param {string} message Error message
@@ -134,6 +136,7 @@ define(function (require, exports, module) {
134136
ParsingError.prototype = new Error();
135137

136138
/**
139+
* @constructor
137140
* Loads/saves preferences from a JSON file on disk.
138141
*
139142
* @param {string} path Path to the preferences file
@@ -156,7 +159,7 @@ define(function (require, exports, module) {
156159
* @return {Promise} Resolved with the data once it has been parsed.
157160
*/
158161
load: function () {
159-
var result = $.Deferred();
162+
var result = new $.Deferred();
160163
var path = this.path;
161164
var createIfNew = this.createIfNew;
162165
var self = this;
@@ -200,7 +203,7 @@ define(function (require, exports, module) {
200203
* @return {Promise} Promise resolved (with no arguments) once the data has been saved
201204
*/
202205
save: function (newData) {
203-
var result = $.Deferred();
206+
var result = new $.Deferred();
204207
var path = this.path;
205208
var prefFile = FileSystem.getFileForPath(path);
206209

@@ -251,6 +254,7 @@ define(function (require, exports, module) {
251254
};
252255

253256
/**
257+
* @constructor
254258
* A `Scope` is a data container that is tied to a `Storage`.
255259
*
256260
* Additionally, `Scope`s support "layers" which are additional levels of preferences
@@ -275,7 +279,7 @@ define(function (require, exports, module) {
275279
* @return {Promise} Promise that is resolved once loading is complete
276280
*/
277281
load: function () {
278-
var result = $.Deferred();
282+
var result = new $.Deferred();
279283
this.storage.load()
280284
.then(function (data) {
281285
var oldKeys = this.getKeys();
@@ -302,7 +306,7 @@ define(function (require, exports, module) {
302306
self._dirty = false;
303307
return this.storage.save(this.data);
304308
} else {
305-
return $.Deferred().resolve().promise();
309+
return (new $.Deferred()).resolve().promise();
306310
}
307311
},
308312

@@ -672,6 +676,7 @@ define(function (require, exports, module) {
672676
// }
673677

674678
/**
679+
* @constructor
675680
* There can be multiple paths and they are each checked in turn. The first that matches the
676681
* currently edited file wins.
677682
*
@@ -833,6 +838,7 @@ define(function (require, exports, module) {
833838
};
834839

835840
/**
841+
* @constructor
836842
* Represents a single, known Preference.
837843
*
838844
* @param {Object} properties Information about the Preference that is stored on this object
@@ -864,10 +870,11 @@ define(function (require, exports, module) {
864870
});
865871

866872
/**
873+
* @constructor
867874
* Provides a subset of the PreferencesSystem functionality with preference
868875
* access always occurring with the given prefix.
869876
*
870-
* @param {PreferencesSystem} baseSystem The real PreferencesSystem that is backing this one
877+
* @param {PreferencesSystem} base The real PreferencesSystem that is backing this one
871878
* @param {string} prefix Prefix that is used for preferences lookup. Any separator characters should already be added.
872879
*/
873880
function PrefixedPreferencesSystem(base, prefix) {
@@ -1030,6 +1037,7 @@ define(function (require, exports, module) {
10301037
};
10311038

10321039
/**
1040+
* @constructor
10331041
* PreferencesSystem ties everything together to provide a simple interface for
10341042
* managing the whole prefs system.
10351043
*
@@ -1064,8 +1072,9 @@ define(function (require, exports, module) {
10641072

10651073
this._pendingScopes = {};
10661074

1067-
this._saveInProgress = false;
1075+
this._saveInProgress = null;
10681076
this._nextSaveDeferred = null;
1077+
this.finalized = false;
10691078

10701079
// The objects that define the different kinds of path-based Scope handlers.
10711080
// Examples could include the handler for .brackets.json files or an .editorconfig
@@ -1552,31 +1561,37 @@ define(function (require, exports, module) {
15521561

15531562
/**
15541563
* Saves the preferences. If a save is already in progress, a Promise is returned for
1555-
* that save operation.
1564+
* that save operation. If preferences have already been finalized then return a
1565+
* rejected promise.
15561566
*
15571567
* @return {Promise} Resolved when the preferences are done saving.
15581568
*/
15591569
save: function () {
1570+
if (this.finalized) {
1571+
console.log("PreferencesSystem.save() called after finalized!");
1572+
return (new $.Deferred()).reject().promise();
1573+
}
1574+
15601575
if (this._saveInProgress) {
15611576
if (!this._nextSaveDeferred) {
1562-
this._nextSaveDeferred = $.Deferred();
1577+
this._nextSaveDeferred = new $.Deferred();
15631578
}
15641579
return this._nextSaveDeferred.promise();
15651580
}
15661581

1567-
this._saveInProgress = true;
1568-
var deferred = this._nextSaveDeferred || $.Deferred();
1582+
var deferred = this._nextSaveDeferred || (new $.Deferred());
1583+
this._saveInProgress = deferred;
15691584
this._nextSaveDeferred = null;
15701585

15711586
Async.doInParallel(_.values(this._scopes), function (scope) {
15721587
if (scope) {
15731588
return scope.save();
15741589
} else {
1575-
return $.Deferred().resolve().promise();
1590+
return (new $.Deferred()).resolve().promise();
15761591
}
15771592
}.bind(this))
15781593
.then(function () {
1579-
this._saveInProgress = false;
1594+
this._saveInProgress = null;
15801595
if (this._nextSaveDeferred) {
15811596
this.save();
15821597
}
@@ -1742,6 +1757,34 @@ define(function (require, exports, module) {
17421757
*/
17431758
getPrefixedSystem: function (prefix) {
17441759
return new PrefixedPreferencesSystem(this, prefix + ".");
1760+
},
1761+
1762+
/**
1763+
* Return a promise that is resolved when all preferences have been saved.
1764+
* Disallow any other preferences from getting saved after promise is resolved.
1765+
*
1766+
* @return {Promise} Resolved when the preferences are done saving.
1767+
*/
1768+
_finalize: function () {
1769+
var deferred = new $.Deferred(),
1770+
self = this;
1771+
1772+
// Don't resolve promise until last `_saveInProgress` promise completes.
1773+
// There will only ever be a `_nextSaveDeferred`, if there is already a
1774+
// `_saveInProgress` and it will become the new `_saveInProgress` as soon as
1775+
// previous `_saveInProgress` resolves, so only need to wait for `_saveInProgress`.
1776+
function checkForSaveAndFinalize() {
1777+
if (self._saveInProgress) {
1778+
self._saveInProgress.done(checkForSaveAndFinalize);
1779+
} else {
1780+
self.finalized = true;
1781+
deferred.resolve();
1782+
}
1783+
}
1784+
1785+
checkForSaveAndFinalize();
1786+
1787+
return deferred.promise();
17451788
}
17461789
});
17471790

src/preferences/PreferencesManager.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ define(function (require, exports, module) {
3434

3535
var OldPreferenceStorage = require("preferences/PreferenceStorage").PreferenceStorage,
3636
AppInit = require("utils/AppInit"),
37+
Async = require("utils/Async"),
3738
Commands = require("command/Commands"),
3839
CommandManager = require("command/CommandManager"),
3940
DeprecationWarning = require("utils/DeprecationWarning"),
@@ -532,6 +533,24 @@ define(function (require, exports, module) {
532533
}
533534
}
534535

536+
/**
537+
* Return a promise that is resolved when all preferences have been resolved,
538+
* or rejected if any have been rejected.
539+
*
540+
* @return {Promise} Resolved when the preferences are done saving.
541+
*/
542+
function finalize() {
543+
var promiseList = [
544+
PreferencesImpl.managerReady,
545+
PreferencesImpl.smUserScopeLoading,
546+
PreferencesImpl.manager._finalize(),
547+
PreferencesImpl.stateManager._finalize()
548+
],
549+
identityFunc = function (promise) { return promise; };
550+
551+
return Async.doSequentially(promiseList, identityFunc, false);
552+
}
553+
535554
AppInit.appReady(function () {
536555
PreferencesImpl.manager.resumeChangeEvents();
537556
});
@@ -562,6 +581,7 @@ define(function (require, exports, module) {
562581
exports.setValueAndSave = setValueAndSave;
563582
exports.getViewState = getViewState;
564583
exports.setViewState = setViewState;
584+
exports.finalize = finalize;
565585
exports.addScope = PreferencesImpl.manager.addScope.bind(PreferencesImpl.manager);
566586
exports.stateManager = PreferencesImpl.stateManager;
567587
exports.FileStorage = PreferencesBase.FileStorage;

0 commit comments

Comments
 (0)