Skip to content

Commit 04ed8ec

Browse files
authored
Cleanup and move test-only code into the test utils library (#1878)
1 parent e864efe commit 04ed8ec

File tree

4 files changed

+236
-332
lines changed

4 files changed

+236
-332
lines changed

lib/src/io_utils.dart

Lines changed: 0 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
library dartdoc.io_utils;
77

88
import 'dart:async';
9-
import 'dart:convert';
109
import 'dart:io';
1110

12-
import 'package:dartdoc/src/tuple.dart';
1311
import 'package:path/path.dart' as pathLib;
1412

1513
/// Return a resolved path including the home directory in place of tilde
@@ -82,7 +80,6 @@ final libraryNameRegexp = new RegExp('[.:]');
8280
final partOfRegexp = new RegExp('part of ');
8381
final newLinePartOfRegexp = new RegExp('\npart of ');
8482

85-
final RegExp quotables = new RegExp(r'[ "\r\n\$]');
8683

8784
/// Best used with Future<void>.
8885
class MultiFutureTracker<T> {
@@ -117,204 +114,4 @@ class MultiFutureTracker<T> {
117114
Future<void> wait() async => await _waitUntil(0);
118115
}
119116

120-
/// Keeps track of coverage data automatically for any processes run by this
121-
/// [CoverageSubprocessLauncher]. Requires that these be dart processes.
122-
class CoverageSubprocessLauncher extends SubprocessLauncher {
123-
CoverageSubprocessLauncher(String context, [Map<String, String> environment])
124-
: super(context, environment);
125117

126-
static int nextObservatoryPort = 9292;
127-
128-
/// Set this to true to enable coverage runs.
129-
static bool coverageEnabled = false;
130-
131-
/// A list of all coverage results picked up by all launchers.
132-
static List<Tuple2<String, Future<Iterable<Map>>>> coverageResults = [];
133-
134-
static Directory _tempDir;
135-
static Directory get tempDir =>
136-
_tempDir ??= Directory.systemTemp.createTempSync('dartdoc_coverage_data');
137-
138-
int _observatoryPort;
139-
// TODO(jcollins-g): use ephemeral ports
140-
int get observatoryPort => _observatoryPort ??= nextObservatoryPort++;
141-
142-
String _outCoverageFilename;
143-
String get outCoverageFilename => _outCoverageFilename ??=
144-
pathLib.join(tempDir.path, 'dart-cov-0-${observatoryPort}.json');
145-
146-
/// Call once all coverage runs have been generated by calling runStreamed
147-
/// on all [CoverageSubprocessLaunchers].
148-
static Future<void> generateCoverageToFile(File outputFile) async {
149-
if (!coverageEnabled) return Future.value(null);
150-
var currentCoverageResults = coverageResults;
151-
coverageResults = [];
152-
var launcher = SubprocessLauncher('format_coverage');
153-
154-
/// Wait for all coverage runs to finish.
155-
await Future.wait(currentCoverageResults.map((t) => t.item2));
156-
157-
return launcher.runStreamed(Platform.executable, [
158-
'tool/format_coverage.dart', // TODO(jcollins-g): use pub after dart-lang/coverage#240 is landed
159-
'--lcov',
160-
'-v',
161-
'-b', '.',
162-
'--packages=.packages',
163-
'--sdk-root=${pathLib.canonicalize(pathLib.join(pathLib.dirname(Platform.executable), '..'))}',
164-
'--out=${pathLib.canonicalize(outputFile.path)}',
165-
'--report-on=bin,lib',
166-
'-i', tempDir.path,
167-
]);
168-
}
169-
170-
@override
171-
Future<Iterable<Map>> runStreamed(String executable, List<String> arguments,
172-
{String workingDirectory}) {
173-
assert(executable == Platform.executable,
174-
'Must use dart executable for tracking coverage');
175-
176-
if (coverageEnabled) {
177-
arguments = [
178-
'--enable-vm-service=${observatoryPort}',
179-
'--pause-isolates-on-exit'
180-
]..addAll(arguments);
181-
}
182-
183-
Future<Iterable<Map>> results = super
184-
.runStreamed(executable, arguments, workingDirectory: workingDirectory);
185-
186-
if (coverageEnabled) {
187-
coverageResults.add(new Tuple2(
188-
outCoverageFilename,
189-
super.runStreamed('pub', [
190-
'run',
191-
'coverage:collect_coverage',
192-
'--wait-paused',
193-
'--resume-isolates',
194-
'--port=${observatoryPort}',
195-
'--out=${outCoverageFilename}',
196-
])));
197-
}
198-
return results;
199-
}
200-
}
201-
202-
class SubprocessLauncher {
203-
final String context;
204-
final Map<String, String> environment;
205-
206-
String get prefix => context.isNotEmpty ? '$context: ' : '';
207-
208-
// from flutter:dev/tools/dartdoc.dart, modified
209-
static Future<void> _printStream(Stream<List<int>> stream, Stdout output,
210-
{String prefix: '', Iterable<String> Function(String line) filter}) {
211-
assert(prefix != null);
212-
if (filter == null) filter = (line) => [line];
213-
return stream
214-
.transform(utf8.decoder)
215-
.transform(const LineSplitter())
216-
.expand(filter)
217-
.listen((String line) {
218-
if (line != null) {
219-
output.write('$prefix$line'.trim());
220-
output.write('\n');
221-
}
222-
}).asFuture();
223-
}
224-
225-
SubprocessLauncher(this.context, [Map<String, String> environment])
226-
: this.environment = environment ?? <String, String>{};
227-
228-
/// A wrapper around start/await process.exitCode that will display the
229-
/// output of the executable continuously and fail on non-zero exit codes.
230-
/// It will also parse any valid JSON objects (one per line) it encounters
231-
/// on stdout/stderr, and return them. Returns null if no JSON objects
232-
/// were encountered, or if DRY_RUN is set to 1 in the execution environment.
233-
///
234-
/// Makes running programs in grinder similar to set -ex for bash, even on
235-
/// Windows (though some of the bashisms will no longer make sense).
236-
/// TODO(jcollins-g): move this to grinder?
237-
Future<Iterable<Map>> runStreamed(String executable, List<String> arguments,
238-
{String workingDirectory}) async {
239-
List<Map> jsonObjects;
240-
241-
/// Allow us to pretend we didn't pass the JSON flag in to dartdoc by
242-
/// printing what dartdoc would have printed without it, yet storing
243-
/// json objects into [jsonObjects].
244-
Iterable<String> jsonCallback(String line) {
245-
Map result;
246-
try {
247-
result = json.decoder.convert(line);
248-
} catch (FormatException) {}
249-
if (result != null) {
250-
if (jsonObjects == null) {
251-
jsonObjects = new List();
252-
}
253-
jsonObjects.add(result);
254-
if (result.containsKey('message')) {
255-
line = result['message'];
256-
} else if (result.containsKey('data')) {
257-
line = result['data']['text'];
258-
}
259-
}
260-
return line.split('\n');
261-
}
262-
263-
stderr.write('$prefix+ ');
264-
if (workingDirectory != null) stderr.write('(cd "$workingDirectory" && ');
265-
if (environment != null) {
266-
stderr.write(environment.keys.map((String key) {
267-
if (environment[key].contains(quotables)) {
268-
return "$key='${environment[key]}'";
269-
} else {
270-
return "$key=${environment[key]}";
271-
}
272-
}).join(' '));
273-
stderr.write(' ');
274-
}
275-
stderr.write('$executable');
276-
if (arguments.isNotEmpty) {
277-
for (String arg in arguments) {
278-
if (arg.contains(quotables)) {
279-
stderr.write(" '$arg'");
280-
} else {
281-
stderr.write(" $arg");
282-
}
283-
}
284-
}
285-
if (workingDirectory != null) stderr.write(')');
286-
stderr.write('\n');
287-
288-
if (Platform.environment.containsKey('DRY_RUN')) return null;
289-
290-
String realExecutable = executable;
291-
final List<String> realArguments = [];
292-
if (Platform.isLinux) {
293-
// Use GNU coreutils to force line buffering. This makes sure that
294-
// subprocesses that die due to fatal signals do not chop off the
295-
// last few lines of their output.
296-
//
297-
// Dart does not actually do this (seems to flush manually) unless
298-
// the VM crashes.
299-
realExecutable = 'stdbuf';
300-
realArguments.addAll(['-o', 'L', '-e', 'L']);
301-
realArguments.add(executable);
302-
}
303-
realArguments.addAll(arguments);
304-
305-
Process process = await Process.start(realExecutable, realArguments,
306-
workingDirectory: workingDirectory, environment: environment);
307-
Future<void> stdoutFuture = _printStream(process.stdout, stdout,
308-
prefix: prefix, filter: jsonCallback);
309-
Future<void> stderrFuture = _printStream(process.stderr, stderr,
310-
prefix: prefix, filter: jsonCallback);
311-
await Future.wait([stderrFuture, stdoutFuture, process.exitCode]);
312-
313-
int exitCode = await process.exitCode;
314-
if (exitCode != 0) {
315-
throw new ProcessException(executable, arguments,
316-
"SubprocessLauncher got non-zero exitCode: $exitCode", exitCode);
317-
}
318-
return jsonObjects;
319-
}
320-
}

0 commit comments

Comments
 (0)