Skip to content

Commit 855efbb

Browse files
authored
Construct PackageGraphs and run tools asynchronously (#1849)
* asynchronous PackageGraph construction and precaching * Run tools more asynchronously * Enhacements and dropping of Future.wait * dartfmt * Rate-limit the number of tools in flight * dartfmt and review comments
1 parent 77d4167 commit 855efbb

File tree

8 files changed

+249
-152
lines changed

8 files changed

+249
-152
lines changed

analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ linter:
1717
- package_api_docs
1818
- slash_for_doc_comments
1919
- prefer_final_fields
20+
- unawaited_futures
2021
# - unnecessary_brace_in_string_interps

lib/src/dartdoc_options.dart

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import 'dart:io';
2020
import 'package:analyzer/dart/element/element.dart';
2121
import 'package:args/args.dart';
2222
import 'package:dartdoc/dartdoc.dart';
23+
import 'package:dartdoc/src/tuple.dart';
2324
import 'package:path/path.dart' as pathLib;
2425
import 'package:yaml/yaml.dart';
2526

@@ -226,22 +227,23 @@ class DartToolDefinition extends ToolDefinition {
226227
/// to run. If no snapshot file existed, then create one and modify the args
227228
/// so that if they are executed with dart, will result in the snapshot being
228229
/// built.
229-
String createSnapshotIfNeeded(List<String> args) {
230-
assert(ToolDefinition.isDartExecutable(args[0]));
231-
// Generate a new snapshot, if needed, and use the first run as the training
230+
Future<Tuple2<String, Function()>> modifyArgsToCreateSnapshotIfNeeded(
231+
List<String> args) async {
232+
assert(args[0] == command.first);
233+
// Set up flags to create a new snapshot, if needed, and use the first run as the training
232234
// run.
233-
File snapshotPath = _snapshotPath;
234-
snapshotPath ??= SnapshotCache.instance.getSnapshot(args[0]);
235-
if (snapshotPath.existsSync()) {
235+
File snapshotFile = await getSnapshotFile();
236+
if (snapshotFile.existsSync()) {
236237
// replace the first argument with the path to the snapshot.
237-
args[0] = snapshotPath.absolute.path;
238+
args[0] = snapshotFile.absolute.path;
238239
} else {
239240
args.insertAll(0, [
240-
'--snapshot=${snapshotPath.absolute.path}',
241+
'--snapshot=${snapshotFile.absolute.path}',
241242
'--snapshot_kind=app-jit'
242243
]);
243244
}
244-
return Platform.resolvedExecutable;
245+
return new Tuple2(Platform.resolvedExecutable,
246+
_snapshotCompleter.isCompleted ? null : _snapshotCompleter.complete);
245247
}
246248

247249
DartToolDefinition(
@@ -250,11 +252,23 @@ class DartToolDefinition extends ToolDefinition {
250252
// If the dart tool is already a snapshot, then we just use that.
251253
if (command[0].endsWith('.snapshot')) {
252254
_snapshotPath = File(command[0]);
255+
_snapshotCompleter.complete();
253256
}
254257
}
255258

259+
final Completer _snapshotCompleter = new Completer();
260+
256261
/// If the tool has a pre-built snapshot, it will be stored here.
257262
File _snapshotPath;
263+
264+
Future<File> getSnapshotFile() async {
265+
if (_snapshotPath == null) {
266+
_snapshotPath = SnapshotCache.instance.getSnapshot(command.first);
267+
} else {
268+
await _snapshotCompleter.future;
269+
}
270+
return _snapshotPath;
271+
}
258272
}
259273

260274
/// A configuration class that can interpret [ToolDefinition]s from a YAML map.

lib/src/io_utils.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,25 +75,25 @@ class MultiFutureTracker<T> {
7575

7676
MultiFutureTracker(this.parallel);
7777

78-
/// Adds a Future to the queue of outstanding Futures, and returns a Future
79-
/// that completes only when the number of Futures outstanding is < [parallel]
80-
/// (and so it is OK to start another).
81-
///
82-
/// That can be extremely brief and there's no longer a guarantee after that
83-
/// point that another async task has not added a Future to the list.
84-
Future<void> addFuture(Future<T> future) async {
85-
_queue.add(future);
86-
future.then((f) => _queue.remove(future));
87-
await _waitUntil(parallel - 1);
88-
}
89-
9078
/// Wait until fewer or equal to this many Futures are outstanding.
9179
Future<void> _waitUntil(int max) async {
9280
while (_queue.length > max) {
9381
await Future.any(_queue);
9482
}
9583
}
9684

85+
/// Generates a [Future] from the given closure and adds it to the queue,
86+
/// once the queue is sufficiently empty.
87+
Future<void> addFutureFromClosure(Future<T> Function() closure) async {
88+
while (_queue.length > parallel - 1) {
89+
await Future.any(_queue);
90+
}
91+
Future future = closure();
92+
_queue.add(future);
93+
// ignore: unawaited_futures
94+
future.then((f) => _queue.remove(future));
95+
}
96+
9797
/// Wait until all futures added so far have completed.
9898
Future<void> wait() async => await _waitUntil(0);
9999
}

0 commit comments

Comments
 (0)