@@ -19,60 +19,49 @@ typedef FakeResultCallback = String Function(String tool,
19
19
/// limiting both parallelization and the number of open temporary files.
20
20
final MultiFutureTracker _toolTracker = new MultiFutureTracker (4 );
21
21
22
- /// A helper class for running external tools.
23
- class ToolRunner {
24
- /// Creates a new ToolRunner.
25
- ///
26
- /// Takes a [toolConfiguration] that describes all of the available tools.
27
- /// An optional `errorCallback` will be called for each error message
28
- /// generated by the tool.
29
- ToolRunner (this .toolConfiguration, [this ._errorCallback]);
22
+ /// Can be called when the ToolRunner is no longer needed.
23
+ ///
24
+ /// This will remove any temporary files created by the tool runner.
25
+ class ToolTempFileTracker {
26
+ final Directory temporaryDirectory;
30
27
31
- final ToolConfiguration toolConfiguration;
32
- final ToolErrorCallback _errorCallback;
33
- int _temporaryFileCount = 0 ;
28
+ ToolTempFileTracker ._() : temporaryDirectory = Directory .systemTemp.createTempSync ('dartdoc_tools_' );
34
29
35
- Future <Directory > _temporaryDirectory;
36
- Future <Directory > get temporaryDirectory {
37
- if (_temporaryDirectory == null ) {
38
- _temporaryDirectory = Directory .systemTemp.createTemp ('dartdoc_tools_' );
39
- }
40
- return _temporaryDirectory;
41
- }
30
+ static ToolTempFileTracker _instance;
31
+ static ToolTempFileTracker get instance => _instance ?? = ToolTempFileTracker ._();
42
32
43
- void _error (String message) {
44
- if (_errorCallback != null ) {
45
- _errorCallback (message);
46
- }
47
- }
48
-
49
- Future <File > _createTemporaryFile () async {
33
+ int _temporaryFileCount = 0 ;
34
+ Future <File > createTemporaryFile () async {
50
35
_temporaryFileCount++ ;
51
36
File tempFile = new File (pathLib.join (
52
- ( await temporaryDirectory) .absolute.path,
37
+ temporaryDirectory.absolute.path,
53
38
'input_$_temporaryFileCount ' ));
54
39
await tempFile.create (recursive: true );
55
40
return tempFile;
56
41
}
57
42
58
- /// Must be called when the ToolRunner is no longer needed. Ideally, this is
59
- /// called in the finally section of a try/finally.
60
- ///
61
- /// This will remove any temporary files created by the tool runner.
62
- void dispose () {
63
- if (_temporaryDirectory != null ) disposeAsync (_temporaryDirectory);
64
- }
65
-
66
- /// Avoid blocking on I/O for cleanups.
67
- static Future <void > disposeAsync (Future <Directory > temporaryDirectory) async {
68
- Directory tempDir = await temporaryDirectory;
69
- if (await tempDir.exists ()) {
70
- return tempDir.delete (recursive: true );
43
+ /// Call once no more files are to be created.
44
+ Future <void > dispose () async {
45
+ if (temporaryDirectory.existsSync ()) {
46
+ return temporaryDirectory.delete (recursive: true );
71
47
}
72
48
}
49
+ }
50
+
51
+ /// A helper class for running external tools.
52
+ class ToolRunner {
53
+ /// Creates a new ToolRunner.
54
+ ///
55
+ /// Takes a [toolConfiguration] that describes all of the available tools.
56
+ /// An optional `errorCallback` will be called for each error message
57
+ /// generated by the tool.
58
+ ToolRunner (this .toolConfiguration);
59
+
60
+ final ToolConfiguration toolConfiguration;
73
61
74
62
void _runSetup (
75
- String name, ToolDefinition tool, Map <String , String > environment) async {
63
+ String name, ToolDefinition tool, Map <String , String > environment,
64
+ ToolErrorCallback toolErrorCallback) async {
76
65
bool isDartSetup = ToolDefinition .isDartExecutable (tool.setupCommand[0 ]);
77
66
var args = tool.setupCommand.toList ();
78
67
String commandPath;
@@ -82,18 +71,19 @@ class ToolRunner {
82
71
} else {
83
72
commandPath = args.removeAt (0 );
84
73
}
85
- await _runProcess (name, '' , commandPath, args, environment);
74
+ await _runProcess (name, '' , commandPath, args, environment, toolErrorCallback );
86
75
tool.setupComplete = true ;
87
76
}
88
77
89
78
Future <String > _runProcess (String name, String content, String commandPath,
90
- List <String > args, Map <String , String > environment) async {
79
+ List <String > args, Map <String , String > environment,
80
+ ToolErrorCallback toolErrorCallback) async {
91
81
String commandString () => ([commandPath] + args).join (' ' );
92
82
try {
93
83
ProcessResult result =
94
84
await Process .run (commandPath, args, environment: environment);
95
85
if (result.exitCode != 0 ) {
96
- _error ('Tool "$name " returned non-zero exit code '
86
+ toolErrorCallback ('Tool "$name " returned non-zero exit code '
97
87
'(${result .exitCode }) when run as '
98
88
'"${commandString ()}" from ${Directory .current }\n '
99
89
'Input to $name was:\n '
@@ -104,7 +94,7 @@ class ToolRunner {
104
94
return result.stdout;
105
95
}
106
96
} on ProcessException catch (exception) {
107
- _error ('Failed to run tool "$name " as '
97
+ toolErrorCallback ('Failed to run tool "$name " as '
108
98
'"${commandString ()}": $exception \n '
109
99
'Input to $name was:\n '
110
100
'$content ' );
@@ -118,26 +108,26 @@ class ToolRunner {
118
108
///
119
109
/// The [args] must not be null, and it must have at least one member (the name
120
110
/// of the tool).
121
- Future <String > run (List <String > args,
111
+ Future <String > run (List <String > args, ToolErrorCallback toolErrorCallback,
122
112
{String content, Map <String , String > environment}) async {
123
113
Future runner;
124
114
// Prevent too many tools from running simultaneously.
125
115
await _toolTracker.addFutureFromClosure (() {
126
- runner = _run (args, content: content, environment: environment);
116
+ runner = _run (args, toolErrorCallback, content: content, environment: environment);
127
117
return runner;
128
118
});
129
119
return runner;
130
120
}
131
121
132
- Future <String > _run (List <String > args,
122
+ Future <String > _run (List <String > args, ToolErrorCallback toolErrorCallback,
133
123
{String content, Map <String , String > environment}) async {
134
124
assert (args != null );
135
125
assert (args.isNotEmpty);
136
126
content ?? = '' ;
137
127
environment ?? = < String , String > {};
138
128
var tool = args.removeAt (0 );
139
129
if (! toolConfiguration.tools.containsKey (tool)) {
140
- _error ('Unable to find definition for tool "$tool " in tool map. '
130
+ toolErrorCallback ('Unable to find definition for tool "$tool " in tool map. '
141
131
'Did you add it to dartdoc_options.yaml?' );
142
132
return '' ;
143
133
}
@@ -152,7 +142,7 @@ class ToolRunner {
152
142
// file before running the tool synchronously.
153
143
154
144
// Write the content to a temp file.
155
- var tmpFile = await _createTemporaryFile ();
145
+ var tmpFile = await ToolTempFileTracker .instance. createTemporaryFile ();
156
146
await tmpFile.writeAsString (content);
157
147
158
148
// Substitute the temp filename for the "$INPUT" token, and all of the other
@@ -188,7 +178,7 @@ class ToolRunner {
188
178
}
189
179
190
180
if (toolDefinition.setupCommand != null && ! toolDefinition.setupComplete)
191
- await _runSetup (tool, toolDefinition, envWithInput);
181
+ await _runSetup (tool, toolDefinition, envWithInput, toolErrorCallback );
192
182
193
183
argsWithInput = toolArgs + argsWithInput;
194
184
var commandPath;
@@ -201,13 +191,14 @@ class ToolRunner {
201
191
} else {
202
192
commandPath = argsWithInput.removeAt (0 );
203
193
}
194
+
204
195
if (callCompleter != null ) {
205
196
return _runProcess (
206
- tool, content, commandPath, argsWithInput, envWithInput)
197
+ tool, content, commandPath, argsWithInput, envWithInput, toolErrorCallback )
207
198
.whenComplete (callCompleter);
208
199
} else {
209
200
return _runProcess (
210
- tool, content, commandPath, argsWithInput, envWithInput);
201
+ tool, content, commandPath, argsWithInput, envWithInput, toolErrorCallback );
211
202
}
212
203
}
213
204
}
0 commit comments