mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 938704 - Make OS.File support modern iterators. r=florian,Yoric
MozReview-Commit-ID: 8F1DtgakxM3 --HG-- extra : rebase_source : 05c42a3236ad55356a9149d8107e4a569fc06cd0
This commit is contained in:
parent
7c7d5a22d4
commit
b3d2965807
@ -372,7 +372,7 @@ var Agent = {
|
||||
if (!iterator.exists()) {
|
||||
return;
|
||||
}
|
||||
for (let entry in iterator) {
|
||||
for (let entry of iterator) {
|
||||
if (entry.isDir) {
|
||||
continue;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ function gatherFiles(path, fileRegex) {
|
||||
const iterator = new OS.File.DirectoryIterator(path);
|
||||
|
||||
try {
|
||||
for (let child in iterator) {
|
||||
for (let child of iterator) {
|
||||
// Don't descend into test directories. Saves us some time and
|
||||
// there's no reason to.
|
||||
if (child.isDir && !child.path.endsWith("/test")) {
|
||||
|
@ -1245,64 +1245,45 @@ var DirectoryIterator = function DirectoryIterator(path, options) {
|
||||
* @type {Promise}
|
||||
* @resolves {*} A message accepted by the methods of DirectoryIterator
|
||||
* in the worker thread
|
||||
* @rejects {StopIteration} If all entries have already been visited
|
||||
* or the iterator has been closed.
|
||||
*/
|
||||
this.__itmsg = Scheduler.post(
|
||||
this._itmsg = Scheduler.post(
|
||||
"new_DirectoryIterator", [Type.path.toMsg(path), options],
|
||||
path
|
||||
);
|
||||
this._isClosed = false;
|
||||
};
|
||||
DirectoryIterator.prototype = {
|
||||
iterator() {
|
||||
return this;
|
||||
},
|
||||
__iterator__() {
|
||||
[Symbol.asyncIterator]() {
|
||||
return this;
|
||||
},
|
||||
|
||||
// Once close() is called, _itmsg should reject with a
|
||||
// StopIteration. However, we don't want to create the promise until
|
||||
// it's needed because it might never be used. In that case, we
|
||||
// would get a warning on the console.
|
||||
get _itmsg() {
|
||||
if (!this.__itmsg) {
|
||||
this.__itmsg = Promise.reject(StopIteration);
|
||||
}
|
||||
return this.__itmsg;
|
||||
},
|
||||
_itmsg: null,
|
||||
|
||||
/**
|
||||
* Determine whether the directory exists.
|
||||
*
|
||||
* @resolves {boolean}
|
||||
*/
|
||||
exists: function exists() {
|
||||
return this._itmsg.then(
|
||||
function onSuccess(iterator) {
|
||||
return Scheduler.post("DirectoryIterator_prototype_exists", [iterator]);
|
||||
}
|
||||
);
|
||||
async exists() {
|
||||
if (this._isClosed) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
let iterator = await this._itmsg;
|
||||
return Scheduler.post("DirectoryIterator_prototype_exists", [iterator]);
|
||||
},
|
||||
/**
|
||||
* Get the next entry in the directory.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves {OS.File.Entry}
|
||||
* @rejects {StopIteration} If all entries have already been visited.
|
||||
* @resolves By definition of the async iterator protocol, either
|
||||
* `{value: {File.Entry}, done: false}` if there is an unvisited entry
|
||||
* in the directory, or `{value: undefined, done: true}`, otherwise.
|
||||
*/
|
||||
next: function next() {
|
||||
let self = this;
|
||||
let promise = this._itmsg;
|
||||
|
||||
// Get the iterator, call _next
|
||||
promise = promise.then(
|
||||
function withIterator(iterator) {
|
||||
return self._next(iterator);
|
||||
});
|
||||
|
||||
return promise;
|
||||
async next() {
|
||||
if (this._isClosed) {
|
||||
return {value: undefined, done: true};
|
||||
}
|
||||
return this._next(await this._itmsg);
|
||||
},
|
||||
/**
|
||||
* Get several entries at once.
|
||||
@ -1312,20 +1293,13 @@ DirectoryIterator.prototype = {
|
||||
* @return {Promise}
|
||||
* @resolves {Array} An array containing the |length| next entries.
|
||||
*/
|
||||
nextBatch: function nextBatch(size) {
|
||||
async nextBatch(size) {
|
||||
if (this._isClosed) {
|
||||
return Promise.resolve([]);
|
||||
return [];
|
||||
}
|
||||
let promise = this._itmsg;
|
||||
promise = promise.then(
|
||||
function withIterator(iterator) {
|
||||
return Scheduler.post("DirectoryIterator_prototype_nextBatch", [iterator, size]);
|
||||
});
|
||||
promise = promise.then(
|
||||
function withEntries(array) {
|
||||
return array.map(DirectoryIterator.Entry.fromMsg);
|
||||
});
|
||||
return promise;
|
||||
let iterator = await this._itmsg;
|
||||
let array = await Scheduler.post("DirectoryIterator_prototype_nextBatch", [iterator, size]);
|
||||
return array.map(DirectoryIterator.Entry.fromMsg);
|
||||
},
|
||||
/**
|
||||
* Apply a function to all elements of the directory sequentially.
|
||||
@ -1342,82 +1316,51 @@ DirectoryIterator.prototype = {
|
||||
* @return {Promise} A promise resolved once the loop has reached
|
||||
* its end.
|
||||
*/
|
||||
forEach: function forEach(cb, options) {
|
||||
async forEach(cb, options) {
|
||||
if (this._isClosed) {
|
||||
return Promise.resolve();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
let position = 0;
|
||||
let iterator;
|
||||
|
||||
// Grab iterator
|
||||
let promise = this._itmsg.then(
|
||||
function(aIterator) {
|
||||
iterator = aIterator;
|
||||
let iterator = await this._itmsg;
|
||||
while (true) {
|
||||
if (this._isClosed) {
|
||||
return undefined;
|
||||
}
|
||||
);
|
||||
|
||||
// Then iterate
|
||||
let loop = function loop() {
|
||||
if (self._isClosed) {
|
||||
return Promise.resolve();
|
||||
let {value, done} = await this._next(iterator);
|
||||
if (done) {
|
||||
return undefined;
|
||||
}
|
||||
return self._next(iterator).then(
|
||||
function onSuccess(value) {
|
||||
return Promise.resolve(cb(value, position++, self)).then(loop);
|
||||
},
|
||||
function onFailure(reason) {
|
||||
if (reason == StopIteration) {
|
||||
return;
|
||||
}
|
||||
throw reason;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return promise.then(loop);
|
||||
await cb(value, position++, this);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Auxiliary method: fetch the next item
|
||||
*
|
||||
* @rejects {StopIteration} If all entries have already been visited
|
||||
* or the iterator has been closed.
|
||||
* @resolves `{value: undefined, done: true}` If all entries have already
|
||||
* been visited or the iterator has been closed.
|
||||
*/
|
||||
_next: function _next(iterator) {
|
||||
async _next(iterator) {
|
||||
if (this._isClosed) {
|
||||
return this._itmsg;
|
||||
return {value: undefined, done: true};
|
||||
}
|
||||
let self = this;
|
||||
let promise = Scheduler.post("DirectoryIterator_prototype_next", [iterator]);
|
||||
promise = promise.then(
|
||||
DirectoryIterator.Entry.fromMsg,
|
||||
function onReject(reason) {
|
||||
if (reason == StopIteration) {
|
||||
self.close();
|
||||
throw StopIteration;
|
||||
}
|
||||
throw reason;
|
||||
});
|
||||
return promise;
|
||||
let {value, done} = await Scheduler.post("DirectoryIterator_prototype_next", [iterator]);
|
||||
if (done) {
|
||||
this.close();
|
||||
return {value: undefined, done: true};
|
||||
}
|
||||
return {value: DirectoryIterator.Entry.fromMsg(value), done: false};
|
||||
},
|
||||
/**
|
||||
* Close the iterator
|
||||
*/
|
||||
close: function close() {
|
||||
async close() {
|
||||
if (this._isClosed) {
|
||||
return Promise.resolve();
|
||||
return undefined;
|
||||
}
|
||||
this._isClosed = true;
|
||||
let self = this;
|
||||
return this._itmsg.then(
|
||||
function withIterator(iterator) {
|
||||
// Set __itmsg to null so that the _itmsg getter returns a
|
||||
// rejected StopIteration promise if it's ever used.
|
||||
self.__itmsg = null;
|
||||
return Scheduler.post("DirectoryIterator_prototype_close", [iterator]);
|
||||
}
|
||||
);
|
||||
let iterator = this._itmsg;
|
||||
this._itmsg = null;
|
||||
return Scheduler.post("DirectoryIterator_prototype_close", [iterator]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -356,14 +356,12 @@ if (this.Components) {
|
||||
DirectoryIterator_prototype_next: function next(dir) {
|
||||
return withDir(dir,
|
||||
function do_next() {
|
||||
try {
|
||||
return File.DirectoryIterator.Entry.toMsg(this.next());
|
||||
} catch (x) {
|
||||
if (x == StopIteration) {
|
||||
OpenedDirectoryIterators.remove(dir);
|
||||
}
|
||||
throw x;
|
||||
let {value, done} = this.next();
|
||||
if (done) {
|
||||
OpenedDirectoryIterators.remove(dir);
|
||||
return {value: undefined, done: true};
|
||||
}
|
||||
return {value: File.DirectoryIterator.Entry.toMsg(value), done: false};
|
||||
}, false);
|
||||
},
|
||||
DirectoryIterator_prototype_nextBatch: function nextBatch(dir, size) {
|
||||
|
@ -190,9 +190,9 @@ AbstractFile.AbstractIterator = function AbstractIterator() {
|
||||
};
|
||||
AbstractFile.AbstractIterator.prototype = {
|
||||
/**
|
||||
* Allow iterating with |for|
|
||||
* Allow iterating with |for-of|
|
||||
*/
|
||||
__iterator__: function __iterator__() {
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
@ -207,7 +207,7 @@ AbstractFile.AbstractIterator.prototype = {
|
||||
*/
|
||||
forEach: function forEach(cb) {
|
||||
let index = 0;
|
||||
for (let entry in this) {
|
||||
for (let entry of this) {
|
||||
cb(entry, index++, this);
|
||||
}
|
||||
},
|
||||
@ -225,7 +225,7 @@ AbstractFile.AbstractIterator.prototype = {
|
||||
nextBatch: function nextBatch(length) {
|
||||
let array = [];
|
||||
let i = 0;
|
||||
for (let entry in this) {
|
||||
for (let entry of this) {
|
||||
array.push(entry);
|
||||
if (++i >= length) {
|
||||
return array;
|
||||
@ -503,7 +503,7 @@ AbstractFile.removeRecursive = function(path, options = {}) {
|
||||
}
|
||||
|
||||
try {
|
||||
for (let entry in iterator) {
|
||||
for (let entry of iterator) {
|
||||
if (entry.isDir) {
|
||||
if (entry.isLink) {
|
||||
// Unlike Unix symlinks, NTFS junctions or NTFS symlinks to
|
||||
|
@ -732,16 +732,16 @@
|
||||
*
|
||||
* Skip special directories "." and "..".
|
||||
*
|
||||
* @return {File.Entry} The next entry in the directory.
|
||||
* @throws {StopIteration} Once all files in the directory have been
|
||||
* encountered.
|
||||
* @return By definition of the iterator protocol, either
|
||||
* `{value: {File.Entry}, done: false}` if there is an unvisited entry
|
||||
* in the directory, or `{value: undefined, done: true}`, otherwise.
|
||||
*/
|
||||
File.DirectoryIterator.prototype.next = function next() {
|
||||
if (!this._exists) {
|
||||
throw File.Error.noSuchFile("DirectoryIterator.prototype.next", this._path);
|
||||
}
|
||||
if (this._closed) {
|
||||
throw StopIteration;
|
||||
return {value: undefined, done: true};
|
||||
}
|
||||
for (let entry = UnixFile.readdir(this._dir);
|
||||
entry != null && !entry.isNull();
|
||||
@ -764,10 +764,13 @@
|
||||
isSymLink = contents.d_type == Const.DT_LNK;
|
||||
}
|
||||
|
||||
return new File.DirectoryIterator.Entry(isDir, isSymLink, name, this._path);
|
||||
return {
|
||||
value: new File.DirectoryIterator.Entry(isDir, isSymLink, name, this._path),
|
||||
done: false
|
||||
};
|
||||
}
|
||||
this.close();
|
||||
throw StopIteration;
|
||||
return {value: undefined, done: true};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -811,9 +811,9 @@
|
||||
*
|
||||
* Skip special directories "." and "..".
|
||||
*
|
||||
* @return {File.Entry} The next entry in the directory.
|
||||
* @throws {StopIteration} Once all files in the directory have been
|
||||
* encountered.
|
||||
* @return By definition of the iterator protocol, either
|
||||
* `{value: {File.Entry}, done: false}` if there is an unvisited entry
|
||||
* in the directory, or `{value: undefined, done: true}`, otherwise.
|
||||
*/
|
||||
File.DirectoryIterator.prototype.next = function next() {
|
||||
// FIXME: If we start supporting "\\?\"-prefixed paths, do not forget
|
||||
@ -824,9 +824,12 @@
|
||||
if (name == "." || name == "..") {
|
||||
continue;
|
||||
}
|
||||
return new File.DirectoryIterator.Entry(entry, this._path);
|
||||
return {
|
||||
value: new File.DirectoryIterator.Entry(entry, this._path),
|
||||
done: false
|
||||
};
|
||||
}
|
||||
throw StopIteration;
|
||||
return {value: undefined, done: true};
|
||||
};
|
||||
|
||||
File.DirectoryIterator.prototype.close = function close() {
|
||||
|
@ -215,7 +215,7 @@ function test_iter_dir() {
|
||||
let iterator = new OS.File.DirectoryIterator(parent);
|
||||
info("test_iter_dir: iterator created");
|
||||
let encountered_tmp_file = false;
|
||||
for (let entry in iterator) {
|
||||
for (let entry of iterator) {
|
||||
// Checking that |name| can be decoded properly
|
||||
info("test_iter_dir: encountering entry " + entry.name);
|
||||
|
||||
@ -266,7 +266,7 @@ function test_iter_dir() {
|
||||
// Testing nextBatch()
|
||||
iterator = new OS.File.DirectoryIterator(parent);
|
||||
let allentries = [];
|
||||
for (let x in iterator) {
|
||||
for (let x of iterator) {
|
||||
allentries.push(x);
|
||||
}
|
||||
iterator.close();
|
||||
|
@ -2973,12 +2973,9 @@ SearchService.prototype = {
|
||||
{ winPattern: "*.xml" });
|
||||
try {
|
||||
// Add dir to distDirs if it contains any files.
|
||||
await checkForSyncCompletion(iterator.next());
|
||||
distDirs.push(dir);
|
||||
} catch (ex) {
|
||||
// Catch for StopIteration exception.
|
||||
if (ex.result == Cr.NS_ERROR_ALREADY_INITIALIZED) {
|
||||
throw ex;
|
||||
let {done} = await checkForSyncCompletion(iterator.next());
|
||||
if (!done) {
|
||||
distDirs.push(dir);
|
||||
}
|
||||
} finally {
|
||||
iterator.close();
|
||||
@ -2998,12 +2995,9 @@ SearchService.prototype = {
|
||||
{ winPattern: "*.xml" });
|
||||
try {
|
||||
// Add dir to otherDirs if it contains any files.
|
||||
await checkForSyncCompletion(iterator.next());
|
||||
otherDirs.push(dir);
|
||||
} catch (ex) {
|
||||
// Catch for StopIteration exception.
|
||||
if (ex.result == Cr.NS_ERROR_ALREADY_INITIALIZED) {
|
||||
throw ex;
|
||||
let {done} = await checkForSyncCompletion(iterator.next());
|
||||
if (!done) {
|
||||
otherDirs.push(dir);
|
||||
}
|
||||
} finally {
|
||||
iterator.close();
|
||||
|
@ -89,7 +89,7 @@ var Agent = {
|
||||
let skip = new Set(skipFiles);
|
||||
|
||||
let entries = [];
|
||||
for (let entry in iter) {
|
||||
for (let entry of iter) {
|
||||
if (!entry.isDir && !entry.isSymLink && !skip.has(entry.name)) {
|
||||
entries.push(entry);
|
||||
}
|
||||
@ -108,7 +108,7 @@ var Agent = {
|
||||
}
|
||||
let iter = new OS.File.DirectoryIterator(pathFrom);
|
||||
if (iter.exists()) {
|
||||
for (let entry in iter) {
|
||||
for (let entry of iter) {
|
||||
if (entry.isDir || entry.isSymLink) {
|
||||
continue;
|
||||
}
|
||||
@ -153,7 +153,7 @@ var Agent = {
|
||||
wipe: function Agent_wipe(path) {
|
||||
let iterator = new File.DirectoryIterator(path);
|
||||
try {
|
||||
for (let entry in iterator) {
|
||||
for (let entry of iterator) {
|
||||
try {
|
||||
File.remove(entry.path);
|
||||
} catch (ex) {
|
||||
|
@ -6567,8 +6567,11 @@ class SystemAddonInstallLocation extends MutableDirectoryInstallLocation {
|
||||
}
|
||||
|
||||
try {
|
||||
for (let promise in iterator) {
|
||||
let entry = await promise;
|
||||
for (;;) {
|
||||
let {value: entry, done} = await iterator.next();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip the directory currently in use
|
||||
if (this._directory && this._directory.path == entry.path) {
|
||||
@ -6581,16 +6584,16 @@ class SystemAddonInstallLocation extends MutableDirectoryInstallLocation {
|
||||
}
|
||||
|
||||
if (entry.isDir) {
|
||||
await OS.File.removeDir(entry.path, {
|
||||
ignoreAbsent: true,
|
||||
ignorePermissions: true,
|
||||
});
|
||||
} else {
|
||||
await OS.File.remove(entry.path, {
|
||||
ignoreAbsent: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
await OS.File.removeDir(entry.path, {
|
||||
ignoreAbsent: true,
|
||||
ignorePermissions: true,
|
||||
});
|
||||
} else {
|
||||
await OS.File.remove(entry.path, {
|
||||
ignoreAbsent: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
logger.error("Failed to clean updated system add-ons directories.", e);
|
||||
|
Loading…
Reference in New Issue
Block a user