Skip to content

Commit af6832b

Browse files
committed
Agents must have a temp dir of their own, or risk interference with other agents in other threads
1 parent 5973ae2 commit af6832b

8 files changed

+310
-273
lines changed

.eslintrc.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
},
88
"extends": "eslint:recommended",
99
"parserOptions": {
10-
"sourceType": "module"
10+
"sourceType": "module",
11+
"ecmaVersion": 2017
1112
},
1213
"globals": {
1314
"assert": true,
@@ -16,6 +17,7 @@
1617
"sinon": true
1718
},
1819
"rules": {
19-
"no-console": [0]
20+
"no-console": [0],
21+
"no-empty-pattern": [0]
2022
}
2123
}

lib/ConsoleAgent.js

+22-9
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,27 @@
22
const fs = require('fs');
33
const path = require('path');
44
const cp = require('child_process');
5-
const temp = require('temp');
65
const recast = require('recast');
6+
const uniqueTempDir = require('unique-temp-dir');
77

8-
const Agent = require('./Agent.js');
9-
const ErrorParser = require('./parseError.js');
8+
const Agent = require('./Agent');
9+
const ErrorParser = require('./parseError');
1010
const inception = require('./inception');
11-
const {getDependencies, hasModuleSpecifier, rawSource} = require('./dependencies.js');
12-
const writeSources = require('./write-sources.js');
11+
const writeSources = require('./write-sources');
12+
const {
13+
getDependencies,
14+
// escapeModuleSpecifier,
15+
hasModuleSpecifier,
16+
rawSource
17+
} = require('./dependencies');
1318

1419
const cpSym = Symbol('cp');
20+
const tpSym = Symbol('tp');
21+
22+
function generateTempFileName() {
23+
const now = Date.now();
24+
return `f-${now}-${process.pid}-${(Math.random() * 0x100000000 + 1).toString(36)}.js`;
25+
}
1526

1627
class ConsoleAgent extends Agent {
1728
constructor(options) {
@@ -21,6 +32,7 @@ class ConsoleAgent extends Agent {
2132
// Promise for the child process created by the most
2233
// recent invocation of `evalScript`
2334
this[cpSym] = null;
35+
this[tpSym] = uniqueTempDir();
2436
}
2537

2638
createChildProcess(args = [], options = {}) {
@@ -32,8 +44,8 @@ class ConsoleAgent extends Agent {
3244
}
3345

3446
evalScript(code, options = {}) {
35-
let tempfile = temp.path({ suffix: '.js' });
36-
let temppath = path.dirname(tempfile);
47+
let tempfile = path.join(this[tpSym], generateTempFileName());
48+
let temppath = this[tpSym];
3749

3850
let hasDependencies = false;
3951
let sourcecode;
@@ -113,12 +125,13 @@ class ConsoleAgent extends Agent {
113125
// 3. Add the prepped source to list of sources that will be written
114126
//
115127
dependencies.forEach(file => {
128+
let absname = path.join(temppath, file);
116129
let rawsource = rawSource.get(path.basename(file));
117130
let jspart = rawsource.split(/\/\*---[\r\n]+[\S\s]*[\r\n]+---\*\//)[1];
118131

119-
if (path.join(temppath, file) !== tempfile) {
132+
if (absname !== tempfile) {
120133
sources.push([
121-
path.join(temppath, file),
134+
absname,
122135
`${preamble}\n${jspart ? jspart : rawsource}`
123136
]);
124137
}

lib/dependencies.js

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ const fs = require('fs');
44
const path = require('path');
55
const rawSourceCache = new Map();
66

7+
function escapeModuleSpecifier(string) {
8+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
9+
}
710

811
function hasModuleSpecifier(source) {
912
const dynamicImport = /import\((\s*)('(.+)'|"(.*)")(\s*)\)/g.exec(source);
@@ -73,6 +76,7 @@ function getDependencies(file, accum = []) {
7376
}
7477

7578
module.exports = {
79+
escapeModuleSpecifier,
7680
getDependencies,
7781
hasModuleSpecifier,
7882
rawSource: {

lib/promisify.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module.exports = function(api) {
2+
return function(...args) {
3+
return new Promise((resolve, reject) => {
4+
args.push((error, result) => {
5+
if (error) {
6+
return reject(error);
7+
}
8+
return resolve(result);
9+
});
10+
api(...args);
11+
});
12+
};
13+
};
14+

lib/write-sources.js

+23-16
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
11
'use strict';
22

33
const fs = require('fs');
4+
const path = require('path');
5+
6+
const promisify = require('./promisify');
7+
const mkdir = promisify(fs.mkdir);
8+
const stat = promisify(fs.stat);
49
const writeFile = promisify(fs.writeFile);
510

6-
module.exports = function(sources) {
11+
module.exports = async function(sources) {
12+
let {0: [file]} = sources;
13+
let dir = path.dirname(file);
14+
15+
await safeMkdir(dir);
716
/*
817
first: path to output file
918
second: contents
1019
*/
11-
return Promise.all(
12-
// TODO: Can we use built-in fs-promise?
20+
return await Promise.all(
1321
sources.map(args => writeFile(...args))
1422
);
1523
};
1624

17-
function promisify(api) {
18-
return function(...args) {
19-
return new Promise(function(resolve, reject) {
20-
args.push(function(error, result) {
21-
if (error) {
22-
return reject(error);
23-
}
24-
return resolve(result);
25-
});
26-
api(...args);
27-
});
28-
};
25+
async function safeMkdir(dir) {
26+
try {
27+
await stat(dir);
28+
} catch (error) {
29+
if (error.code === 'ENOENT') {
30+
try {
31+
await mkdir(dir);
32+
} catch ({}) {
33+
// suppressed?
34+
}
35+
}
36+
}
2937
}
30-

0 commit comments

Comments
 (0)