@@ -19,60 +19,49 @@ typedef FakeResultCallback = String Function(String tool,
1919/// limiting both parallelization and the number of open temporary files.
2020final MultiFutureTracker _toolTracker = new MultiFutureTracker (4 );
2121
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;
3027
31- final ToolConfiguration toolConfiguration;
32- final ToolErrorCallback _errorCallback;
33- int _temporaryFileCount = 0 ;
28+ ToolTempFileTracker ._() : temporaryDirectory = Directory .systemTemp.createTempSync ('dartdoc_tools_' );
3429
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 ._();
4232
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 {
5035 _temporaryFileCount++ ;
5136 File tempFile = new File (pathLib.join (
52- ( await temporaryDirectory) .absolute.path,
37+ temporaryDirectory.absolute.path,
5338 'input_$_temporaryFileCount ' ));
5439 await tempFile.create (recursive: true );
5540 return tempFile;
5641 }
5742
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 );
7147 }
7248 }
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;
7361
7462 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 {
7665 bool isDartSetup = ToolDefinition .isDartExecutable (tool.setupCommand[0 ]);
7766 var args = tool.setupCommand.toList ();
7867 String commandPath;
@@ -82,18 +71,19 @@ class ToolRunner {
8271 } else {
8372 commandPath = args.removeAt (0 );
8473 }
85- await _runProcess (name, '' , commandPath, args, environment);
74+ await _runProcess (name, '' , commandPath, args, environment, toolErrorCallback );
8675 tool.setupComplete = true ;
8776 }
8877
8978 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 {
9181 String commandString () => ([commandPath] + args).join (' ' );
9282 try {
9383 ProcessResult result =
9484 await Process .run (commandPath, args, environment: environment);
9585 if (result.exitCode != 0 ) {
96- _error ('Tool "$name " returned non-zero exit code '
86+ toolErrorCallback ('Tool "$name " returned non-zero exit code '
9787 '(${result .exitCode }) when run as '
9888 '"${commandString ()}" from ${Directory .current }\n '
9989 'Input to $name was:\n '
@@ -104,7 +94,7 @@ class ToolRunner {
10494 return result.stdout;
10595 }
10696 } on ProcessException catch (exception) {
107- _error ('Failed to run tool "$name " as '
97+ toolErrorCallback ('Failed to run tool "$name " as '
10898 '"${commandString ()}": $exception \n '
10999 'Input to $name was:\n '
110100 '$content ' );
@@ -118,26 +108,26 @@ class ToolRunner {
118108 ///
119109 /// The [args] must not be null, and it must have at least one member (the name
120110 /// of the tool).
121- Future <String > run (List <String > args,
111+ Future <String > run (List <String > args, ToolErrorCallback toolErrorCallback,
122112 {String content, Map <String , String > environment}) async {
123113 Future runner;
124114 // Prevent too many tools from running simultaneously.
125115 await _toolTracker.addFutureFromClosure (() {
126- runner = _run (args, content: content, environment: environment);
116+ runner = _run (args, toolErrorCallback, content: content, environment: environment);
127117 return runner;
128118 });
129119 return runner;
130120 }
131121
132- Future <String > _run (List <String > args,
122+ Future <String > _run (List <String > args, ToolErrorCallback toolErrorCallback,
133123 {String content, Map <String , String > environment}) async {
134124 assert (args != null );
135125 assert (args.isNotEmpty);
136126 content ?? = '' ;
137127 environment ?? = < String , String > {};
138128 var tool = args.removeAt (0 );
139129 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. '
141131 'Did you add it to dartdoc_options.yaml?' );
142132 return '' ;
143133 }
@@ -152,7 +142,7 @@ class ToolRunner {
152142 // file before running the tool synchronously.
153143
154144 // Write the content to a temp file.
155- var tmpFile = await _createTemporaryFile ();
145+ var tmpFile = await ToolTempFileTracker .instance. createTemporaryFile ();
156146 await tmpFile.writeAsString (content);
157147
158148 // Substitute the temp filename for the "$INPUT" token, and all of the other
@@ -188,7 +178,7 @@ class ToolRunner {
188178 }
189179
190180 if (toolDefinition.setupCommand != null && ! toolDefinition.setupComplete)
191- await _runSetup (tool, toolDefinition, envWithInput);
181+ await _runSetup (tool, toolDefinition, envWithInput, toolErrorCallback );
192182
193183 argsWithInput = toolArgs + argsWithInput;
194184 var commandPath;
@@ -201,13 +191,14 @@ class ToolRunner {
201191 } else {
202192 commandPath = argsWithInput.removeAt (0 );
203193 }
194+
204195 if (callCompleter != null ) {
205196 return _runProcess (
206- tool, content, commandPath, argsWithInput, envWithInput)
197+ tool, content, commandPath, argsWithInput, envWithInput, toolErrorCallback )
207198 .whenComplete (callCompleter);
208199 } else {
209200 return _runProcess (
210- tool, content, commandPath, argsWithInput, envWithInput);
201+ tool, content, commandPath, argsWithInput, envWithInput, toolErrorCallback );
211202 }
212203 }
213204}
0 commit comments