Skip to content

Commit 38136cb

Browse files
committed
Fixed #1938 - an issue with the queue causing an uncaught exception.
1 parent 08cc186 commit 38136cb

File tree

3 files changed

+69
-45
lines changed

3 files changed

+69
-45
lines changed

lib/core/asynctree.js

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,10 @@ class AsyncTree {
3333
}
3434

3535
traverse() {
36-
const childNode = AsyncTree.getNextChild(this.currentNode);
36+
const childNode = AsyncTree.getNextChildNode(this.currentNode);
3737

3838
if (childNode) {
39-
return this.runChildNode(childNode).then(result => {
40-
let abortOnFailure = false;
41-
if (result instanceof Error) {
42-
abortOnFailure = result.abortOnFailure || Utils.isUndefined(result.abortOnFailure);
43-
}
44-
45-
if (abortOnFailure) {
46-
return this.done(result);
47-
}
48-
49-
return this.traverse();
50-
});
39+
return this.runChildNode(childNode);
5140
}
5241

5342
if (this.currentNode.childNodes.length > 0 && this.currentNode.needsPromise) {
@@ -62,20 +51,15 @@ class AsyncTree {
6251
walkUp() {
6352
if (this.currentNode.childNodes.length > 0 && !this.currentNode.done) {
6453
// if the current node has childNodes that have not finished yet
65-
return new Promise((resolve, reject) => {
66-
this.currentNode.result
67-
.then(_=> resolve())
68-
.catch(err => reject(err));
54+
return this.currentNode.result.catch(err => {
55+
console.error(err);
56+
throw err;
6957
});
7058
}
7159

7260
if (!this.currentNode.done) {
7361
// if the current node hasn't finished yet
74-
return new Promise((resolve, reject) => {
75-
this.currentNode.result
76-
.then(_=> resolve())
77-
.catch(err => reject(err));
78-
}).then(_ => this.walkUp());
62+
return this.currentNode.result
7963
}
8064

8165
this.currentNode = this.currentNode.parent;
@@ -86,17 +70,23 @@ class AsyncTree {
8670
runChildNode(node) {
8771
this.currentNode = node;
8872
this.currentNode.started = true;
89-
Logger.log(`\n ${Logger.colors.green('→')} Running command: ${Logger.colors.light_green(node.name)} (${AsyncTree.printArguments(node)})`);
73+
Logger.log(`\n ${Logger.colors.green('→')} Running command: ${Logger.colors.light_green(node.fullName)} (${AsyncTree.printArguments(node)})`);
9074

9175
return node.run()
9276
.then(result => {
93-
Logger.log(`${Logger.colors.green('→')} Completed command ${Logger.colors.light_green(node.name)}` +
77+
Logger.log(`${Logger.colors.green('→')} Completed command ${Logger.colors.light_green(node.fullName)}` +
9478
` (${AsyncTree.printArguments(node)}) (${node.elapsedTime}ms)`);
9579

96-
return result;
97-
})
98-
.catch(err => {
99-
return err;
80+
let abortOnFailure = false;
81+
if (result instanceof Error) {
82+
abortOnFailure = result.abortOnFailure || Utils.isUndefined(result.abortOnFailure);
83+
}
84+
85+
if (abortOnFailure) {
86+
return this.done(result);
87+
}
88+
89+
return this.traverse();
10090
});
10191
}
10292

@@ -124,17 +114,22 @@ class AsyncTree {
124114
///////////////////////////////////////////////////////////////////////////
125115
// STATIC
126116
///////////////////////////////////////////////////////////////////////////
127-
static getNextChild(node) {
117+
static getNextChildNode(node) {
118+
let childNode;
128119
for (let i = 0; i < node.childNodes.length; i++) {
129120
if (!node.childNodes[i].started) {
130121
return node.childNodes[i];
131122
}
132123

133124
if (node.childNodes[i].childNodes.length > 0) {
134-
return AsyncTree.getNextChild(node.childNodes[i]);
125+
childNode = node.childNodes[i];
135126
}
136127
}
137128

129+
if (childNode) {
130+
//return AsyncTree.getNextChildNode(childNode);
131+
}
132+
138133
return false;
139134
}
140135

lib/core/queue.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ class CommandQueue extends EventEmitter {
1919
return this.tree.rootNode.started;
2020
}
2121

22+
shouldStartQueue() {
23+
const childNodes = this.currentNode.childNodes;
24+
const allChildNodesDone = childNodes.every(function(node) {
25+
return node.done;
26+
});
27+
28+
return this.currentNode.started && allChildNodesDone;
29+
}
30+
2231
add(nodeName, commandFn, context, args, stackTrace, namespace) {
2332
const node = new Node({
2433
name : nodeName,
@@ -28,19 +37,27 @@ class CommandQueue extends EventEmitter {
2837
});
2938
node.setCommand(commandFn, context, args);
3039

40+
const initialChildNode = this.shouldStartQueue();
41+
3142
this.tree.addNode(node);
3243

33-
if (this.tree.inProgress) {
34-
this.scheduleTraverse();
44+
if (this.currentNode.done || !this.currentNode.started || initialChildNode) {
45+
this.scheduleTraverse(node);
3546
}
3647
}
3748

38-
scheduleTraverse() {
49+
scheduleTraverse(node) {
3950
if (this.scheduleTimeoutId) {
4051
clearTimeout(this.scheduleTimeoutId);
4152
}
4253

43-
this.scheduleTimeoutId = setTimeout(() => this.traverse(), 0);
54+
this.scheduleTimeoutId = setTimeout(() => {
55+
this.tree
56+
.traverse()
57+
.catch(err => {
58+
return err;
59+
});
60+
}, 0);
4461
}
4562

4663
clearScheduled() {

lib/core/treenode.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ class TreeNode {
1818
return this.__instance;
1919
}
2020

21+
get fullName() {
22+
if (!this.namespace || !Utils.isString(this.namespace)) {
23+
return this.name;
24+
}
25+
26+
return `${this.namespace}.${this.name}`;
27+
}
28+
2129
/**
2230
*
2331
* @param {function} commandFn
@@ -51,6 +59,9 @@ class TreeNode {
5159

5260
run() {
5361
return this.runCommand()
62+
.catch(err => {
63+
return err;
64+
})
5465
.then(result => {
5566
this.done = true;
5667
this.elapsedTime = new Date().getTime() - this.startTime;
@@ -77,21 +88,20 @@ class TreeNode {
7788
runCommand() {
7889
this.started = true;
7990
this.startTime = new Date().getTime();
91+
this.result = null;
8092

8193
try {
82-
this.result = this.execute();
94+
this.result = this.execute().catch(err => {
95+
err.message = `Error while running "${this.name}" command: ${err.message}`;
96+
err.abortOnFailure = err.abortOnFailure || err.abortOnFailure === undefined;
8397

84-
return this.result
85-
.catch(err => {
86-
err.message = `Error while running "${this.name}" command: ${err.message}`;
87-
err.abortOnFailure = err.abortOnFailure || err.abortOnFailure === undefined;
98+
if (err.abortOnFailure) {
99+
throw err;
100+
}
88101

89-
if (err.abortOnFailure) {
90-
throw err;
91-
}
102+
return err;
103+
});
92104

93-
return err;
94-
});
95105
} catch (err) {
96106
let originalError = err.stack;
97107

@@ -101,8 +111,10 @@ class TreeNode {
101111

102112
err.message = `Error while running "${this.name}" command: "${originalError.split('\n')[0]}"`;
103113

104-
return Promise.reject(err);
114+
this.result = Promise.reject(err);
105115
}
116+
117+
return this.result;
106118
}
107119

108120
handleCommandResult() {

0 commit comments

Comments
 (0)